From 42fec1f84422fb698e29eecdbe3a8e46ac254be5 Mon Sep 17 00:00:00 2001
From: OZGCloud <ozgcloud@mgm-tp.com>
Date: Mon, 26 Apr 2021 11:42:27 +0200
Subject: [PATCH] OZG-532 refactor: use event to finish command

---
 .../java/de/itvsh/ozg/mail/EMailService.java  |  2 +-
 ...{MailSendEvent.java => MailSentEvent.java} |  4 +-
 .../de/itvsh/ozg/mail/EMailServiceTest.java   |  2 +-
 pluto-server/pom.xml                          |  5 ++
 .../de/itvsh/ozg/pluto/command/Command.java   |  4 +-
 .../pluto/command/CommandEventListener.java   | 17 +++++
 .../pluto/command/CommandExecutedEvent.java   | 21 ++++++
 .../ozg/pluto/command/CommandRepository.java  |  4 +-
 .../ozg/pluto/command/CommandService.java     |  4 +-
 .../pluto/command/CreateCommandRequest.java   |  3 +
 .../GrpcCreateCommandRequestMapper.java       |  4 +-
 .../status/GrpcVorgangCommandService.java     | 36 +++------
 .../ozg/pluto/command/status/StatusOrder.java |  3 +-
 .../ozg/pluto/vorgang/StatusChangedEvent.java | 14 ++++
 .../ozg/pluto/vorgang/VorgangService.java     | 50 ++++++++-----
 .../vorgang/redirect/RedirectRequest.java     |  5 ++
 .../redirect/RedirectRequestMapper.java       | 11 +++
 .../command/CommandEventListenerTest.java     | 29 +++++++
 .../CommandExecutedEventTestFactory.java      |  9 +++
 .../ozg/pluto/command/CommandTestFactory.java |  2 +
 .../kommentar/GrpcKommentarServiceTest.java   |  6 +-
 .../status/GrpcCommandServiceITCase.java      | 29 +++++--
 .../status/GrpcVorgangCommandServiceTest.java | 75 +++++++++++--------
 .../pluto/vorgang/VorgangServiceITCase.java   | 15 ++--
 .../ozg/pluto/vorgang/VorgangServiceTest.java | 68 ++++++++++++-----
 25 files changed, 303 insertions(+), 119 deletions(-)
 rename mail-service/src/main/java/de/itvsh/ozg/mail/{MailSendEvent.java => MailSentEvent.java} (71%)
 create mode 100644 pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandEventListener.java
 create mode 100644 pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandExecutedEvent.java
 create mode 100644 pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/StatusChangedEvent.java
 create mode 100644 pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequestMapper.java
 create mode 100644 pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandEventListenerTest.java
 create mode 100644 pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandExecutedEventTestFactory.java

diff --git a/mail-service/src/main/java/de/itvsh/ozg/mail/EMailService.java b/mail-service/src/main/java/de/itvsh/ozg/mail/EMailService.java
index 998248f11..0fd24bdff 100644
--- a/mail-service/src/main/java/de/itvsh/ozg/mail/EMailService.java
+++ b/mail-service/src/main/java/de/itvsh/ozg/mail/EMailService.java
@@ -65,6 +65,6 @@ class EMailService {
 	void send(MimeMessage message, MailSendRequest request) {
 		sender.send(message);
 
-		publisher.publishEvent(new MailSendEvent(request));
+		publisher.publishEvent(new MailSentEvent(request));
 	}
 }
diff --git a/mail-service/src/main/java/de/itvsh/ozg/mail/MailSendEvent.java b/mail-service/src/main/java/de/itvsh/ozg/mail/MailSentEvent.java
similarity index 71%
rename from mail-service/src/main/java/de/itvsh/ozg/mail/MailSendEvent.java
rename to mail-service/src/main/java/de/itvsh/ozg/mail/MailSentEvent.java
index 26ce18e33..eddaf1d76 100644
--- a/mail-service/src/main/java/de/itvsh/ozg/mail/MailSendEvent.java
+++ b/mail-service/src/main/java/de/itvsh/ozg/mail/MailSentEvent.java
@@ -2,11 +2,11 @@ package de.itvsh.ozg.mail;
 
 import org.springframework.context.ApplicationEvent;
 
-public class MailSendEvent extends ApplicationEvent {
+public class MailSentEvent extends ApplicationEvent {
 
 	private static final long serialVersionUID = 1L;
 
-	public MailSendEvent(MailSendRequest source) {
+	public MailSentEvent(MailSendRequest source) {
 		super(source);
 	}
 
diff --git a/mail-service/src/test/java/de/itvsh/ozg/mail/EMailServiceTest.java b/mail-service/src/test/java/de/itvsh/ozg/mail/EMailServiceTest.java
index 1c2d33bb0..ed7df678a 100644
--- a/mail-service/src/test/java/de/itvsh/ozg/mail/EMailServiceTest.java
+++ b/mail-service/src/test/java/de/itvsh/ozg/mail/EMailServiceTest.java
@@ -136,7 +136,7 @@ class EMailServiceTest {
 			void shouldTriggerEvent() {
 				service.send(message, request);
 
-				verify(publisher).publishEvent(any(MailSendEvent.class));
+				verify(publisher).publishEvent(any(MailSentEvent.class));
 			}
 		}
 	}
diff --git a/pluto-server/pom.xml b/pluto-server/pom.xml
index b5dcc4f66..14df102b3 100644
--- a/pluto-server/pom.xml
+++ b/pluto-server/pom.xml
@@ -180,6 +180,11 @@
 				</executions>
 			</plugin>
 
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+			</plugin>
+
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-failsafe-plugin</artifactId>
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/Command.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/Command.java
index 9608ebfba..10255c834 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/Command.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/Command.java
@@ -6,6 +6,7 @@ import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
+import de.itvsh.ozg.pluto.vorgang.redirect.RedirectRequest;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.Setter;
@@ -29,7 +30,6 @@ public class Command {
 	private CommandStatus status;
 
 	private String relationId;
-
 	private long relationVersion;
 
 	private Order order;
@@ -38,5 +38,7 @@ public class Command {
 
 	private Wiedervorlage wiedervorlage;
 
+	private RedirectRequest redirectRequest;
+
 	private Kommentar kommentar;
 }
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandEventListener.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandEventListener.java
new file mode 100644
index 000000000..eeee633b5
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandEventListener.java
@@ -0,0 +1,17 @@
+package de.itvsh.ozg.pluto.command;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CommandEventListener {
+
+	@Autowired
+	private CommandService commandService;
+
+	@EventListener
+	public void setStatusFinished(CommandExecutedEvent event) {
+		commandService.setCommandFinished(event.getSource().getId());
+	}
+}
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandExecutedEvent.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandExecutedEvent.java
new file mode 100644
index 000000000..2ae6340a8
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandExecutedEvent.java
@@ -0,0 +1,21 @@
+package de.itvsh.ozg.pluto.command;
+
+import org.springframework.context.ApplicationEvent;
+
+public class CommandExecutedEvent extends ApplicationEvent {
+
+	private static final long serialVersionUID = 1L;
+
+	protected CommandExecutedEvent(Command source) {
+		super(source);
+	}
+
+	@Override
+	public Command getSource() {
+		return (Command) super.getSource();
+	}
+
+	public Order getOrder() {
+		return getSource().getOrder();
+	}
+}
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandRepository.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandRepository.java
index fc6049cf5..58c09037e 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandRepository.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandRepository.java
@@ -36,12 +36,12 @@ class CommandRepository {
 				Command.class);
 	}
 
-	void updateCommandStatusAndVersion(String commandId, CommandStatus status, long commandVersion) {
+	void updateCommandStatusAndVersion(String commandId, CommandStatus status, long relationVersion) {
 		mongoOperations.updateFirst(
 				query(where(MONGODB_ID).is(commandId)),
 				new Update()
 						.set(MONDODB_STATUS, status)
-						.set(MONDODB_RELATION_VERSION, commandVersion),
+						.set(MONDODB_RELATION_VERSION, relationVersion),
 				Command.class);
 	}
 
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandService.java
index 8f9807e66..d1b9c2b3a 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandService.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CommandService.java
@@ -48,8 +48,8 @@ public class CommandService {
 		return command;
 	}
 
-	public void setCommandFinished(String commandId, long version) {
-		repository.updateCommandStatusAndVersion(commandId, CommandStatus.FINISHED, version);
+	public void setCommandFinished(String commandId, long relationVersion) {
+		repository.updateCommandStatusAndVersion(commandId, CommandStatus.FINISHED, relationVersion);
 	}
 
 	public Optional<Command> findCommand(String commandId) {
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CreateCommandRequest.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CreateCommandRequest.java
index face497fe..f63515933 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CreateCommandRequest.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/CreateCommandRequest.java
@@ -3,6 +3,7 @@ package de.itvsh.ozg.pluto.command;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 
+import de.itvsh.ozg.pluto.vorgang.redirect.RedirectRequest;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.ToString;
@@ -25,5 +26,7 @@ public class CreateCommandRequest {
 
 	private Wiedervorlage wiedervorlage;
 
+	private RedirectRequest redirectRequest;
+
 	private Kommentar kommentar;
 }
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/GrpcCreateCommandRequestMapper.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/GrpcCreateCommandRequestMapper.java
index f257378cf..9db7b31b3 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/GrpcCreateCommandRequestMapper.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/GrpcCreateCommandRequestMapper.java
@@ -16,9 +16,11 @@ import de.itvsh.ozg.pluto.grpc.command.GrpcCreateCommandRequest;
 import de.itvsh.ozg.pluto.grpc.command.GrpcOrder;
 import de.itvsh.ozg.pluto.grpc.command.GrpcUser;
 import de.itvsh.ozg.pluto.kommentar.GrpcKommentar;
+import de.itvsh.ozg.pluto.vorgang.redirect.RedirectRequestMapper;
 import de.itvsh.ozg.pluto.wiedervorlage.GrpcWiedervorlage;
 
-@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, //
+@Mapper(uses = RedirectRequestMapper.class, //
+		nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, //
 		nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, //
 		collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
 public interface GrpcCreateCommandRequestMapper {
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandService.java
index 2758470b3..f72db8a13 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandService.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandService.java
@@ -12,7 +12,6 @@ import de.itvsh.ozg.pluto.command.CommandService;
 import de.itvsh.ozg.pluto.command.CreateCommandRequest;
 import de.itvsh.ozg.pluto.command.GrpcCommandResponseMapper;
 import de.itvsh.ozg.pluto.command.GrpcCreateCommandRequestMapper;
-import de.itvsh.ozg.pluto.command.Order;
 import de.itvsh.ozg.pluto.common.errorhandling.NotFoundException;
 import de.itvsh.ozg.pluto.grpc.command.CommandServiceGrpc.CommandServiceImplBase;
 import de.itvsh.ozg.pluto.grpc.command.GrpcCommand;
@@ -37,16 +36,14 @@ class GrpcVorgangCommandService extends CommandServiceImplBase {
 
 	@Autowired
 	private CommandService commandService;
+	@Autowired
+	private VorgangService vorgangService;
 
 	@Autowired
 	private GrpcCommandResponseMapper commandResponseMapper;
-
 	@Autowired
 	private GrpcCommandMapper grpcCommandMapper;
 
-	@Autowired
-	private VorgangService vorgangService;
-
 	@Override
 	public void createCommand(GrpcCreateCommandRequest grpcRequest, StreamObserver<GrpcCommandResponse> responseObserver) {
 		CreateCommandRequest request = createCommandRequestMapper.fromGrpc(grpcRequest);
@@ -54,28 +51,19 @@ class GrpcVorgangCommandService extends CommandServiceImplBase {
 		Vorgang vorgang = vorgangService.getById(request.getRelationId());
 		Command command = commandService.persistCommand(request, vorgang.getStatus());
 
-		Vorgang updatedVorgang = executeOrder(request);
-
-		setCommandFinished(request.getOrder(), command, updatedVorgang);
+		executeOrder(command);
 
-		responseObserver.onNext(mapToGrpcResponse(findCommand(command.getId())));
+		responseObserver.onNext(mapToGrpcResponse(getCommand(command.getId())));
 		responseObserver.onCompleted();
 	}
 
-	Vorgang executeOrder(CreateCommandRequest request) {
-		return StatusOrder.getOrderMethod(request.getOrder()).executeOrder(vorgangService, request.getRelationId(),
-				request.getRelationVersion());
-	}
-
-	void setCommandFinished(Order requestOrder, Command command, Vorgang vorgang) {
-		if (requestOrder != Order.REDIRECT_VORGANG) {
-			commandService.setCommandFinished(command.getId(), vorgang.getVersion());
-		}
+	Vorgang executeOrder(Command command) {
+		return StatusOrder.getOrderMethod(command.getOrder()).executeOrder(vorgangService, command);
 	}
 
 	@Override
 	public void getCommand(GrpcGetCommandRequest request, StreamObserver<GrpcCommand> responseObserver) {
-		Command command = findCommand(request.getId());
+		Command command = getCommand(request.getId());
 
 		responseObserver.onNext(grpcCommandMapper.toGrpc(command));
 		responseObserver.onCompleted();
@@ -88,21 +76,21 @@ class GrpcVorgangCommandService extends CommandServiceImplBase {
 
 		proceedRevokeCommand(commandId);
 
-		Command updatedCommand = findCommand(commandId);
+		Command updatedCommand = getCommand(commandId);
 
 		responseObserver.onNext(mapToGrpcResponse(updatedCommand));
 		responseObserver.onCompleted();
 	}
 
-	private void proceedRevokeCommand(String commandId) {
-		Command command = findCommand(commandId);
+	void proceedRevokeCommand(String commandId) {
+		Command command = getCommand(commandId);
 
-		vorgangService.updateStatus(command.getRelationId(), command.getRelationVersion(), command.getPreviousStatus());
+		vorgangService.revokeStatusChange(command);
 
 		commandService.setCommandRevoked(commandId);
 	}
 
-	private Command findCommand(String commandId) {
+	Command getCommand(String commandId) {
 		return commandService.findCommand(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
 	}
 
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/StatusOrder.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/StatusOrder.java
index b32458718..86765ee4b 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/StatusOrder.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/command/status/StatusOrder.java
@@ -1,5 +1,6 @@
 package de.itvsh.ozg.pluto.command.status;
 
+import de.itvsh.ozg.pluto.command.Command;
 import de.itvsh.ozg.pluto.command.Order;
 import de.itvsh.ozg.pluto.vorgang.Vorgang;
 import de.itvsh.ozg.pluto.vorgang.VorgangService;
@@ -23,7 +24,7 @@ enum StatusOrder {
 	REDIRECT_VORGANG(VorgangService::redirect);
 
 	interface OrderMethod {
-		Vorgang executeOrder(VorgangService service, String vorgangId, long version);
+		Vorgang executeOrder(VorgangService service, Command command);
 	}
 
 	private OrderMethod method;
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/StatusChangedEvent.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/StatusChangedEvent.java
new file mode 100644
index 000000000..47c6ac385
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/StatusChangedEvent.java
@@ -0,0 +1,14 @@
+package de.itvsh.ozg.pluto.vorgang;
+
+import de.itvsh.ozg.pluto.command.Command;
+import de.itvsh.ozg.pluto.command.CommandExecutedEvent;
+
+public class StatusChangedEvent extends CommandExecutedEvent {
+
+	private static final long serialVersionUID = 1L;
+
+	StatusChangedEvent(Command source) {
+		super(source);
+	}
+
+}
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/VorgangService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/VorgangService.java
index bd84095fc..2e6692785 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/VorgangService.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/VorgangService.java
@@ -1,8 +1,10 @@
 package de.itvsh.ozg.pluto.vorgang;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 
+import de.itvsh.ozg.pluto.command.Command;
 import de.itvsh.ozg.pluto.common.errorhandling.NotFoundException;
 import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
 
@@ -11,6 +13,8 @@ public class VorgangService {
 
 	@Autowired
 	private VorgangRepository repository;
+	@Autowired
+	private ApplicationEventPublisher publisher;
 
 	public void createVorgang(Eingang eingang) {
 		repository.save(Vorgang.builder()
@@ -19,39 +23,51 @@ public class VorgangService {
 				.build());
 	}
 
-	public Vorgang setStatusNeu(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.NEU);
+	public Vorgang setStatusNeu(Command command) {
+		return executeStatusChangeCommand(command, Status.NEU);
+	}
+
+	public Vorgang annehmen(Command command) {
+		return executeStatusChangeCommand(command, Status.ANGENOMMEN);
 	}
 
-	public Vorgang annehmen(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.ANGENOMMEN);
+	public Vorgang verwerfen(Command command) {
+		return executeStatusChangeCommand(command, Status.VERWORFEN);
 	}
 
-	public Vorgang verwerfen(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.VERWORFEN);
+	public Vorgang bescheiden(Command command) {
+		return executeStatusChangeCommand(command, Status.BESCHIEDEN);
 	}
 
-	public Vorgang bescheiden(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.BESCHIEDEN);
+	public Vorgang abschliessen(Command command) {
+		return executeStatusChangeCommand(command, Status.ABGESCHLOSSEN);
 	}
 
-	public Vorgang abschliessen(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.ABGESCHLOSSEN);
+	public Vorgang wiedereroeffnen(Command command) {
+		return bearbeiten(command);
 	}
 
-	public Vorgang wiedereroeffnen(String vorgangId, long version) {
-		return bearbeiten(vorgangId, version);
+	public Vorgang bearbeiten(Command command) {
+		return executeStatusChangeCommand(command, Status.IN_BEARBEITUNG);
 	}
 
-	public Vorgang bearbeiten(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.IN_BEARBEITUNG);
+	public Vorgang redirect(Command command) {
+		return doUpdateStatus(command.getRelationId(), command.getRelationVersion(), Status.REDIRECT);
 	}
 
-	public Vorgang redirect(String vorgangId, long version) {
-		return updateStatus(vorgangId, version, Status.REDIRECT);
+	public Vorgang revokeStatusChange(Command command) {
+		return doUpdateStatus(command.getRelationId(), command.getRelationVersion() + 1, command.getPreviousStatus());
+	}
+
+	Vorgang executeStatusChangeCommand(Command command, Status status) {
+		var vorgang = doUpdateStatus(command.getRelationId(), command.getRelationVersion(), status);
+
+		publisher.publishEvent(new StatusChangedEvent(command));
+
+		return vorgang;
 	}
 
-	public Vorgang updateStatus(String vorgangId, long version, Status status) {
+	Vorgang doUpdateStatus(String vorgangId, long version, Status status) {
 		repository.updateStatus(vorgangId, version, status);
 
 		return getById(vorgangId);
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequest.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequest.java
index e5fcaf071..145f62796 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequest.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequest.java
@@ -1,10 +1,15 @@
 package de.itvsh.ozg.pluto.vorgang.redirect;
 
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 
 @Getter
 @Builder
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
 public class RedirectRequest {
 
 	private String email;
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequestMapper.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequestMapper.java
new file mode 100644
index 000000000..436c49b70
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/vorgang/redirect/RedirectRequestMapper.java
@@ -0,0 +1,11 @@
+package de.itvsh.ozg.pluto.vorgang.redirect;
+
+import org.mapstruct.Mapper;
+
+import de.itvsh.ozg.pluto.grpc.command.GrpcRedirectRequest;
+
+@Mapper
+public interface RedirectRequestMapper {
+
+	RedirectRequest fromGrpc(GrpcRedirectRequest request);
+}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandEventListenerTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandEventListenerTest.java
new file mode 100644
index 000000000..868206ac9
--- /dev/null
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandEventListenerTest.java
@@ -0,0 +1,29 @@
+package de.itvsh.ozg.pluto.command;
+
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+class CommandEventListenerTest {
+
+	@InjectMocks // NOSONAR
+	private CommandEventListener listener;
+
+	@Mock
+	private CommandService commandService;
+
+	@Nested
+	class TestCommandExecutedEventListener {
+
+		@Test
+		void shouldSetStatusFinished() {
+			listener.setStatusFinished(
+					CommandExecutedEventTestFactory.createFor(CommandTestFactory.create()));
+
+			verify(commandService).setCommandFinished(CommandTestFactory.ID);
+		}
+	}
+}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandExecutedEventTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandExecutedEventTestFactory.java
new file mode 100644
index 000000000..58c005062
--- /dev/null
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandExecutedEventTestFactory.java
@@ -0,0 +1,9 @@
+package de.itvsh.ozg.pluto.command;
+
+public class CommandExecutedEventTestFactory {
+
+	public static CommandExecutedEvent createFor(Command command) {
+		return new CommandExecutedEvent(command);
+	}
+
+}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandTestFactory.java
index 75bd00d77..84c7d832d 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandTestFactory.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/CommandTestFactory.java
@@ -14,8 +14,10 @@ public class CommandTestFactory {
 	public static final String CREATED_BY = UserTestFactory.ID;
 	public static final String CREATED_BY_NAME = UserTestFactory.NAME;
 	public static final CommandStatus STATUS = CommandStatus.PENDING;
+
 	public static final String RELATION_ID = VorgangTestFactory.ID;
 	public static final long RELATION_VERSION = VorgangTestFactory.VERSION;
+
 	public static final Order ORDER = Order.VORGANG_ANNEHMEN;
 	public static final Status PREV_STATUS = Status.NEU;
 	public static final Wiedervorlage WIEDERVORLAGE = WiedervorlageTestFactory.create();
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/kommentar/GrpcKommentarServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/kommentar/GrpcKommentarServiceTest.java
index 962627464..dc885ab09 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/kommentar/GrpcKommentarServiceTest.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/kommentar/GrpcKommentarServiceTest.java
@@ -1,8 +1,7 @@
 package de.itvsh.ozg.pluto.command.kommentar;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
 
 import java.util.Optional;
 
@@ -43,7 +42,6 @@ class GrpcKommentarServiceTest {
 	private VorgangService vorgangService;
 	@Mock
 	private KommentarService kommentarService;
-	private final StreamRecorder<GrpcCommandResponse> responseObserver = StreamRecorder.create();
 
 	@Nested
 	class TestCreateAndGetCommand {
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcCommandServiceITCase.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcCommandServiceITCase.java
index ce13a01e9..f25374880 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcCommandServiceITCase.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcCommandServiceITCase.java
@@ -105,7 +105,7 @@ class GrpcCommandServiceITCase {
 			assertThat(command.getCreatedBy()).isNotNull();
 			assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
 			assertThat(command.getRelationId()).isEqualTo(persistedDocument.getId());
-			assertThat(command.getRelationVersion()).isEqualTo(VorgangTestFactory.VERSION + 1);
+			assertThat(command.getRelationVersion()).isEqualTo(VorgangTestFactory.VERSION);
 			assertThat(command.getPreviousStatus()).isEqualTo(VorgangTestFactory.STATUS);
 		}
 	}
@@ -168,8 +168,8 @@ class GrpcCommandServiceITCase {
 				mongoOperations.dropCollection(Vorgang.class);
 				mongoOperations.save(VorgangTestFactory.createBuilder().status(Status.ANGENOMMEN).build());
 
-				mongoOperations.save(
-						CommandTestFactory.createBuilder().relationId(VorgangTestFactory.ID).build());
+				mongoOperations.save(CommandTestFactory.createBuilder()
+						.relationId(VorgangTestFactory.ID).relationVersion(VorgangTestFactory.VERSION - 1).build());
 			}
 
 			@Test
@@ -183,14 +183,24 @@ class GrpcCommandServiceITCase {
 			void shouldUpdateVorgang() {
 				service.revokeCommand(request, responseObserver);
 
-				verifyVorgang();
+				Vorgang vorgang = mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class);
+				assertThat(vorgang).isNotNull().extracting(Vorgang::getStatus).isEqualTo(Status.NEU);
 			}
 
 			@Test
 			void shouldUpdateCommand() {
 				service.revokeCommand(request, responseObserver);
 
-				verifyCommand();
+				Command command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
+				assertThat(command).isNotNull().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKED);
+			}
+
+			@Test
+			void shouldNOTUpdateRelationVersion() {
+				service.revokeCommand(request, responseObserver);
+
+				Command command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
+				assertThat(command).isNotNull().extracting(Command::getRelationVersion).isEqualTo(VorgangTestFactory.VERSION - 1);
 			}
 		}
 
@@ -201,7 +211,8 @@ class GrpcCommandServiceITCase {
 			void persistVorgangWithVorgangVerwerfenCommand() {
 				mongoOperations.save(VorgangTestFactory.createBuilder().status(Status.VERWORFEN).build());
 
-				mongoOperations.save(CommandTestFactory.createBuilder().relationId(VorgangTestFactory.ID).order(Order.VORGANG_VERWERFEN).build());
+				mongoOperations.save(CommandTestFactory.createBuilder().relationId(VorgangTestFactory.ID)
+						.relationVersion(VorgangTestFactory.VERSION - 1).order(Order.VORGANG_VERWERFEN).build());
 			}
 
 			@Test
@@ -215,14 +226,16 @@ class GrpcCommandServiceITCase {
 			void shouldUpdateVorgang() {
 				service.revokeCommand(request, responseObserver);
 
-				verifyVorgang();
+				Vorgang vorgang = mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class);
+				assertThat(vorgang).isNotNull().extracting(Vorgang::getStatus).isEqualTo(Status.NEU);
 			}
 
 			@Test
 			void shouldUpdateCommand() {
 				service.revokeCommand(request, responseObserver);
 
-				verifyCommand();
+				Command command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
+				assertThat(command).isNotNull().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKED);
 			}
 		}
 
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandServiceTest.java
index 1b45169be..33774451f 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandServiceTest.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/command/status/GrpcVorgangCommandServiceTest.java
@@ -5,7 +5,6 @@ import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Optional;
-import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -25,7 +24,6 @@ import de.itvsh.ozg.pluto.command.CreateCommandRequest;
 import de.itvsh.ozg.pluto.command.CreateCommandRequestTestFactory;
 import de.itvsh.ozg.pluto.command.GrpcCommandResponseMapper;
 import de.itvsh.ozg.pluto.command.GrpcCreateCommandRequestMapper;
-import de.itvsh.ozg.pluto.command.Order;
 import de.itvsh.ozg.pluto.common.grpc.StreamRecorder;
 import de.itvsh.ozg.pluto.grpc.command.GrpcCommand;
 import de.itvsh.ozg.pluto.grpc.command.GrpcCommandResponse;
@@ -98,13 +96,6 @@ class GrpcVorgangCommandServiceTest {
 			verify(commandService).persistCommand(createComandRequest, VorgangTestFactory.STATUS);
 		}
 
-		@Test
-		void shouldCallSetCommandFinish() throws Exception {
-			callCreateCommand();
-
-			verify(service).setCommandFinished(CreateCommandRequestTestFactory.ORDER, persistedCommand, updatedVorgang);
-		}
-
 		@Test
 		void shouldReturnValue() throws Exception {
 			callCreateCommand();
@@ -124,24 +115,6 @@ class GrpcVorgangCommandServiceTest {
 		}
 	}
 
-	@Nested
-	class TestSetCommandFinish {
-
-		@Test
-		void shouldSetCommandFinish() {
-			service.setCommandFinished(Order.VORGANG_ANNEHMEN, CommandTestFactory.create(), VorgangTestFactory.create());
-
-			verify(commandService).setCommandFinished(CommandTestFactory.ID, VorgangTestFactory.VERSION);
-		}
-
-		@Test
-		void shouldNotSetCommandFinish() {
-			service.setCommandFinished(Order.REDIRECT_VORGANG, CommandTestFactory.create(), VorgangTestFactory.create());
-
-			verify(commandService, times(0)).setCommandFinished(any());
-		}
-	}
-
 	@Nested
 	class TestGetVorgangCommand {
 
@@ -195,13 +168,12 @@ class GrpcVorgangCommandServiceTest {
 	@Nested
 	class TestRevokeCommand {
 
-		final String commandId = UUID.randomUUID().toString();
-		final GrpcRevokeCommandRequest request = GrpcRevokeCommandRequest.newBuilder().setId(commandId).build();
+		private final GrpcRevokeCommandRequest request = GrpcRevokeCommandRequest.newBuilder().setId(CommandTestFactory.ID).build();
 		private final StreamRecorder<GrpcCommandResponse> responseObserver = StreamRecorder.create();
 
 		@BeforeEach
 		void mockCommandService() {
-			Command vorgangCommand = CommandTestFactory.createBuilder().id(commandId).build();
+			Command vorgangCommand = CommandTestFactory.createBuilder().id(CommandTestFactory.ID).build();
 
 			when(commandService.findCommand(any())).thenReturn(Optional.of(vorgangCommand));
 		}
@@ -214,19 +186,58 @@ class GrpcVorgangCommandServiceTest {
 		}
 
 		@Test
-		void shouldCallServiceSetCommandRevoked() throws Exception {
+		void shouldCallMapper() throws Exception {
 			callRevokeCommand();
 
 			verify(commandResponseMapper).toGrpc(any());
 		}
 
 		@Test
-		void shouldCallMapper() throws Exception {
+		void shouldCallServiceSetCommandRevoked() throws Exception {
 			callRevokeCommand();
 
 			verify(commandService).setCommandRevoked(any());
 		}
 
+		@Test
+		void shouldCallProceed() throws Exception {
+			callRevokeCommand();
+
+			verify(service).proceedRevokeCommand(CommandTestFactory.ID);
+		}
+
+		@Nested
+		class TestProceedRevokeCommand {
+
+			private Command command = CommandTestFactory.create();;
+
+			@BeforeEach
+			void init() {
+				when(commandService.findCommand(anyString())).thenReturn(Optional.of(command));
+			}
+
+			@Test
+			void shouldLoadCommand() {
+				service.proceedRevokeCommand(CommandTestFactory.ID);
+
+				verify(service).getCommand(CommandTestFactory.ID);
+			}
+
+			@Test
+			void shouldRevokeCommand() {
+				service.proceedRevokeCommand(CommandTestFactory.ID);
+
+				verify(vorgangService).revokeStatusChange(command);
+			}
+
+			@Test
+			void shouldSetCommandRevoked() {
+				service.proceedRevokeCommand(CommandTestFactory.ID);
+
+				verify(commandService).setCommandRevoked(CommandTestFactory.ID);
+			}
+		}
+
 		private void callRevokeCommand() throws Exception {
 			service.revokeCommand(request, responseObserver);
 
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceITCase.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceITCase.java
index 2cf9236ef..14a34e624 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceITCase.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceITCase.java
@@ -1,6 +1,6 @@
 package de.itvsh.ozg.pluto.vorgang;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
 
 import java.util.Optional;
 
@@ -12,6 +12,8 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.test.context.ActiveProfiles;
 
+import de.itvsh.ozg.pluto.command.Command;
+import de.itvsh.ozg.pluto.command.CommandTestFactory;
 import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
 
 @SpringBootTest
@@ -31,17 +33,20 @@ class VorgangServiceITCase {
 	class TestVorgangUpdateStatus {
 
 		private Vorgang persistedVorgang;
+		private Command command;
 
 		@BeforeEach
 		void persistVorgang() {
 			mongoOperations.dropCollection(Vorgang.class);
 			persistedVorgang = repository.save(VorgangTestFactory.create());
+
+			command = CommandTestFactory.createBuilder().relationId(persistedVorgang.getId()).relationVersion(persistedVorgang.getVersion()).build();
 		}
 
 		@Test
 		void annehmenShouldUpdateStatusAndVersion() {
 
-			vorgangService.annehmen(persistedVorgang.getId(), persistedVorgang.getVersion());
+			vorgangService.annehmen(command);
 
 			Optional<Vorgang> vorgang = repository.findById(persistedVorgang.getId());
 
@@ -52,7 +57,7 @@ class VorgangServiceITCase {
 		@Test
 		void verwerfenShouldUpdateStatusAndVersion() {
 
-			vorgangService.verwerfen(persistedVorgang.getId(), persistedVorgang.getVersion());
+			vorgangService.verwerfen(command);
 
 			Optional<Vorgang> vorgang = repository.findById(persistedVorgang.getId());
 
@@ -63,7 +68,7 @@ class VorgangServiceITCase {
 		@Test
 		void bescheidenShouldUpdateStatusAndVersion() {
 
-			vorgangService.bescheiden(persistedVorgang.getId(), persistedVorgang.getVersion());
+			vorgangService.bescheiden(command);
 
 			Optional<Vorgang> vorgang = repository.findById(persistedVorgang.getId());
 
@@ -74,7 +79,7 @@ class VorgangServiceITCase {
 		@Test
 		void wiedereroeffnenShouldUpdateStatusAndVersion() {
 
-			vorgangService.wiedereroeffnen(persistedVorgang.getId(), persistedVorgang.getVersion());
+			vorgangService.wiedereroeffnen(command);
 
 			Optional<Vorgang> vorgang = repository.findById(persistedVorgang.getId());
 
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceTest.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceTest.java
index d30043a5b..677bf17f7 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceTest.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/vorgang/VorgangServiceTest.java
@@ -6,7 +6,6 @@ import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Optional;
-import java.util.function.BiFunction;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -17,8 +16,11 @@ import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.data.mongodb.core.MongoOperations;
 
+import de.itvsh.ozg.pluto.command.Command;
+import de.itvsh.ozg.pluto.command.CommandTestFactory;
 import de.itvsh.ozg.pluto.common.errorhandling.NotFoundException;
 import de.itvsh.ozg.pluto.vorgang.Vorgang.Status;
 
@@ -30,9 +32,10 @@ class VorgangServiceTest {
 
 	@Mock
 	private VorgangRepository repository;
-
 	@Mock
 	private MongoOperations mongoOperations;
+	@Mock
+	private ApplicationEventPublisher publisher;
 
 	@Captor
 	private ArgumentCaptor<Vorgang> vorgangCaptor;
@@ -93,34 +96,51 @@ class VorgangServiceTest {
 	@Nested
 	class TestVorgangStatusChange {
 
+		private Command command = CommandTestFactory.create();
+
 		@BeforeEach
 		void mockRepository() {
 			when(repository.findById(any())).thenReturn(Optional.of(VorgangTestFactory.create()));
 		}
 
 		@Nested
-		class TestUpdateStatus {
+		class TestExecuteStatusChangeCommand {
 
-			@BeforeEach
-			void doServiceCall() {
-				service.updateStatus(VorgangTestFactory.ID, VorgangTestFactory.VERSION, Status.ANGENOMMEN);
-			}
+			@Captor // NOSONAR
+			private ArgumentCaptor<StatusChangedEvent> eventCaptor;
 
 			@Test
 			void shouldUpdateStatus() {
+				doServiceCall();
+
 				verifyServiceCall(Status.ANGENOMMEN);
 			}
 
 			@Test
 			void shouldCallRepository() {
+				doServiceCall();
+
 				verify(repository).findById(VorgangTestFactory.ID);
 			}
+
+			@Test
+			void shouldPublishExecutedEvent() {
+				doServiceCall();
+
+				verify(publisher).publishEvent(eventCaptor.capture());
+				assertThat(eventCaptor.getValue()).isInstanceOf(StatusChangedEvent.class)
+						.extracting(StatusChangedEvent::getSource).isSameAs(command);
+			}
+
+			private void doServiceCall() {
+				service.executeStatusChangeCommand(command, Status.ANGENOMMEN);
+			}
 		}
 
 		@DisplayName("should update vorgang by the given status 'ANGENOMMEN")
 		@Test
 		void shouldUpdateByStatusAngenommen() {
-			applyServiceCallParam((id, version) -> service.annehmen(id, version));
+			service.annehmen(command);
 
 			verifyServiceCall(Status.ANGENOMMEN);
 		}
@@ -128,7 +148,7 @@ class VorgangServiceTest {
 		@DisplayName("should update vorgang by the given status 'VERWORFEN")
 		@Test
 		void shouldUpdateByStatusVerworfen() {
-			applyServiceCallParam((id, version) -> service.verwerfen(id, version));
+			service.verwerfen(command);
 
 			verifyServiceCall(Status.VERWORFEN);
 		}
@@ -136,7 +156,7 @@ class VorgangServiceTest {
 		@DisplayName("should update vorgang by the given status 'IN_BEARBEITUNG")
 		@Test
 		void shouldUpdateByStatusBearbeiten() {
-			applyServiceCallParam((id, version) -> service.bearbeiten(id, version));
+			service.bearbeiten(command);
 
 			verifyServiceCall(Status.IN_BEARBEITUNG);
 		}
@@ -144,7 +164,7 @@ class VorgangServiceTest {
 		@DisplayName("should update vorgang by the given status 'BESCHIEDEN")
 		@Test
 		void shouldUpdateByStatusBeschieden() {
-			applyServiceCallParam((id, version) -> service.bescheiden(id, version));
+			service.bescheiden(command);
 
 			verifyServiceCall(Status.BESCHIEDEN);
 		}
@@ -152,7 +172,7 @@ class VorgangServiceTest {
 		@DisplayName("should update vorgang by the given status 'ABGESCHLOSSEN")
 		@Test
 		void shouldUpdateByStatusAbgeschlossen() {
-			applyServiceCallParam((id, version) -> service.abschliessen(id, version));
+			service.abschliessen(command);
 
 			verifyServiceCall(Status.ABGESCHLOSSEN);
 		}
@@ -160,17 +180,29 @@ class VorgangServiceTest {
 		@DisplayName("should update vorgang by the given status 'REDIRECT")
 		@Test
 		void shouldUpdateByStatusRedirect() {
-			applyServiceCallParam((id, version) -> service.redirect(id, version));
+			service.redirect(command);
 
-			verifyServiceCall(Status.REDIRECT);
+			verify(service).doUpdateStatus(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION, Status.REDIRECT);
 		}
 
-		private void applyServiceCallParam(BiFunction<String, Long, Vorgang> serviceStatusFunction) {
-			serviceStatusFunction.apply(VorgangTestFactory.ID, VorgangTestFactory.VERSION);
+		private void verifyServiceCall(Status status) {
+			verify(service).executeStatusChangeCommand(command, status);
 		}
+	}
 
-		private void verifyServiceCall(Status status) {
-			verify(service).updateStatus(VorgangTestFactory.ID, VorgangTestFactory.VERSION, status);
+	@Nested
+	class TestRevokeStatusChange {
+
+		@BeforeEach
+		void mockRepository() {
+			when(repository.findById(any())).thenReturn(Optional.of(VorgangTestFactory.create()));
+		}
+
+		@Test
+		void shouldRevindToOldStatus() {
+			service.revokeStatusChange(CommandTestFactory.create());
+
+			verify(service).doUpdateStatus(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION + 1, CommandTestFactory.PREV_STATUS);
 		}
 	}
 }
\ No newline at end of file
-- 
GitLab