From b137574d507e02ed0560717e003464c292e79c77 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Tue, 11 Mar 2025 15:28:20 +0100
Subject: [PATCH 01/14] OZG-7501 OZG-7899 Extend ForwardingEventListener

---
 .../de/ozgcloud/vorgang/command/Order.java    |   1 +
 .../vorgang/vorgang/redirect/Address.java     |  37 ++++++
 .../redirect/ForwardingEventListener.java     |  18 ++-
 .../vorgang/redirect/ForwardingRequest.java   |  38 ++++++
 .../redirect/ForwardingRequestMapper.java     |  50 ++++++++
 .../vorgang/redirect/ForwardingService.java   |   4 +
 .../vorgang/redirect/OrganisationEinheit.java |  36 ++++++
 .../vorgang/redirect/AddressTestFactory.java  |  48 +++++++
 .../redirect/ForwardingEventListenerTest.java |  50 +++++++-
 .../redirect/ForwardingRequestMapperTest.java | 120 ++++++++++++++++++
 .../ForwardingRequestTestFactory.java         |  44 +++++++
 .../OrganisationEinheitTestFactory.java       |  47 +++++++
 12 files changed, 485 insertions(+), 8 deletions(-)
 create mode 100644 vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/Address.java
 create mode 100644 vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
 create mode 100644 vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
 create mode 100644 vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheit.java
 create mode 100644 vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/AddressTestFactory.java
 create mode 100644 vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
 create mode 100644 vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestTestFactory.java
 create mode 100644 vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheitTestFactory.java

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
index 5a4c25ad1..cdc8f9ed1 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
@@ -50,6 +50,7 @@ public enum Order {
 	REDIRECT_VORGANG,
 	FORWARD_SUCCESSFULL,
 	FORWARD_FAILED,
+	FORWARD_VORGANG,
 
 	SEND_POSTFACH_MAIL,
 	RESEND_POSTFACH_MAIL,
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/Address.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/Address.java
new file mode 100644
index 000000000..b15442afa
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/Address.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+class Address {
+
+	private String street;
+	private String houseNumber;
+	private String zipCode;
+	private String city;
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index d84484bc8..7f25cf25b 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -26,7 +26,6 @@ package de.ozgcloud.vorgang.vorgang.redirect;
 import java.util.ConcurrentModificationException;
 import java.util.function.Predicate;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
@@ -38,9 +37,11 @@ import de.ozgcloud.nachrichten.email.MailSendErrorEvent;
 import de.ozgcloud.nachrichten.email.MailSendRequest;
 import de.ozgcloud.nachrichten.email.MailSentEvent;
 import de.ozgcloud.vorgang.command.Order;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
 @Component
+@RequiredArgsConstructor
 @Log4j2
 public class ForwardingEventListener {
 
@@ -48,17 +49,17 @@ public class ForwardingEventListener {
 	private static final String IS_SUCCESSFULL_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_SUCCESSFULL_ORDER.test(event.getSource())}";
 	private static final String IS_FAILED_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FAILED_ORDER.test(event.getSource())}";
 	private static final String IS_FORWARD_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FORWARD_ORDER.test(event.getSource())}";
+	private static final String IS_FORWARD_VORGANG_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FORWARD_VORGANG_ORDER.test(event.getSource())}";
 
 	public static final Predicate<MailSendRequest> IS_REDIRECT_MAIL_REQ = req -> req.getRequestReference() instanceof Forwarding;
 	public static final Predicate<Command> IS_SUCCESSFULL_ORDER = command -> Order.FORWARD_SUCCESSFULL.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_FAILED_ORDER = command -> Order.FORWARD_FAILED.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_FORWARD_ORDER = command -> Order.REDIRECT_VORGANG.isMeant(command.getOrder());
+	public static final Predicate<Command> IS_FORWARD_VORGANG_ORDER = command -> Order.FORWARD_VORGANG.isMeant(command.getOrder());
 
-	@Autowired
-	private ForwardingService service;
-
-	@Autowired
-	private ApplicationEventPublisher publisher;
+	private final ForwardingService service;
+	private final ApplicationEventPublisher publisher;
+	private final ForwardingRequestMapper forwardingRequestMapper;
 
 	@EventListener(condition = IS_FORWARD_ORDER_CONDITION)
 	public void onForwardOrder(CommandCreatedEvent event) {
@@ -89,6 +90,11 @@ public class ForwardingEventListener {
 		service.markAsFailed(event.getSource());
 	}
 
+	@EventListener(condition = IS_FORWARD_VORGANG_ORDER_CONDITION)
+	public void onForwardVorgangOrder(CommandCreatedEvent event) {
+		service.forward(forwardingRequestMapper.fromCommand(event.getSource()));
+	}
+
 	private void handleException(Runnable runnable, String commandId) {
 		try {
 			runnable.run();
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
new file mode 100644
index 000000000..b8dbf0587
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class ForwardingRequest {
+
+	private String vorgangId;
+	private long version;
+	private String createdBy;
+	private String createdByName;
+	private OrganisationEinheit organisationEinheit;
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
new file mode 100644
index 000000000..0da7cd2ac
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import java.util.Map;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+import de.ozgcloud.command.Command;
+
+@Mapper
+interface ForwardingRequestMapper {
+
+	@Mapping(target = "version", source = "relationVersion")
+	@Mapping(target = "organisationEinheit", source = "bodyObject")
+	ForwardingRequest fromCommand(Command command);
+
+	@Mapping(target = "id", expression = "java((String) body.get(\"organisationsEinheitId\"))")
+	@Mapping(target = "name", expression = "java((String) body.get(\"name\"))")
+	@Mapping(target = "address", source = ".")
+	OrganisationEinheit toOrganisationEinheit(Map<String, Object> body);
+
+	@Mapping(target = "street", expression = "java((String) body.get(\"strasse\"))")
+	@Mapping(target = "houseNumber", expression = "java((String) body.get(\"hausnummer\"))")
+	@Mapping(target = "zipCode", expression = "java((String) body.get(\"plz\"))")
+	@Mapping(target = "city", expression = "java((String) body.get(\"ort\"))")
+	Address toAddress(Map<String, Object> body);
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
index 7af3879a0..a38f6fcf7 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
@@ -329,4 +329,8 @@ public class ForwardingService {
 	public Stream<Forwarding> findForwardings(String vorgangId) {
 		return repository.findByVorgangId(vorgangId).stream();
 	}
+
+	public void forward(ForwardingRequest request) {
+
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheit.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheit.java
new file mode 100644
index 000000000..8465f4180
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheit.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class OrganisationEinheit {
+
+	private String id;
+	private String name;
+	private Address address;
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/AddressTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/AddressTestFactory.java
new file mode 100644
index 000000000..69d3d4e21
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/AddressTestFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.vorgang.vorgang.redirect.Address.AddressBuilder;
+
+class AddressTestFactory {
+
+	public static final String STREET = LoremIpsum.getInstance().getName();
+	public static final String HOUSE_NUMBER = "42a";
+	public static final String ZIP_CODE = LoremIpsum.getInstance().getZipCode();
+	public static final String CITY = LoremIpsum.getInstance().getCity();
+
+	public static Address create() {
+		return createBuilder().build();
+	}
+
+	public static AddressBuilder createBuilder() {
+		return new AddressBuilder()
+				.street(STREET)
+				.houseNumber(HOUSE_NUMBER)
+				.zipCode(ZIP_CODE)
+				.city(CITY);
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 1c4363149..364aa21a9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -23,18 +23,26 @@
  */
 package de.ozgcloud.vorgang.vorgang.redirect;
 
+import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.ConcurrentModificationException;
+import java.util.Map;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.springframework.context.ApplicationEventPublisher;
 
+import com.thedeanda.lorem.LoremIpsum;
+
 import de.ozgcloud.command.Command;
+import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.nachrichten.email.MailSentEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
@@ -50,9 +58,11 @@ class ForwardingEventListenerTest {
 	private ForwardingService forwardingService;
 	@Mock
 	private ApplicationEventPublisher publisher;
+	@Mock
+	private ForwardingRequestMapper forwardingRequestMapper;
 
 	@Nested
-	class onForwardOrderCommand {
+	class OnForwardOrderCommand {
 
 		@Test
 		void shouldCallService() {
@@ -72,7 +82,7 @@ class ForwardingEventListenerTest {
 	}
 
 	@Nested
-	class onMailSentEvent {
+	class OnMailSentEvent {
 
 		private Forwarding forwarding = ForwardingTestFactory.create();
 
@@ -85,6 +95,42 @@ class ForwardingEventListenerTest {
 
 	}
 
+	@Nested
+	class TestOnForwardVorgangOrder {
+
+		private final CommandCreatedEvent event = event();
+		@Captor
+		private ArgumentCaptor<ForwardingRequest> forwardingRequestCaptor;
+
+		@BeforeEach
+		void init() {
+			when(forwardingRequestMapper.fromCommand(event.getSource())).thenReturn(ForwardingRequestTestFactory.create());
+		}
+
+		@Test
+		void shouldMapCommandForwardingRequest() {
+			listener.onForwardVorgangOrder(event);
+
+			verify(forwardingRequestMapper).fromCommand(event.getSource());
+		}
+
+		@Test
+		void shouldCallForwardingService() {
+			listener.onForwardVorgangOrder(event);
+
+			verify(forwardingService).forward(forwardingRequestCaptor.capture());
+			assertThat(forwardingRequestCaptor.getValue()).usingRecursiveComparison().isEqualTo(ForwardingRequestTestFactory.create());
+		}
+
+		private static CommandCreatedEvent event() {
+			return CommandCreatedEventTestFactory.create(CommandTestFactory.createBuilder().bodyObject(commandBody()).build());
+		}
+
+		private static Map<String, Object> commandBody() {
+			return Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1));
+		}
+ 	}
+
 	@Nested
 	class TestMarkAsSuccessfull {
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
new file mode 100644
index 000000000..08f42edb7
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+import org.mockito.Spy;
+
+import de.ozgcloud.vorgang.command.CommandTestFactory;
+
+class ForwardingRequestMapperTest {
+
+	@Spy
+	private ForwardingRequestMapper mapper = Mappers.getMapper(ForwardingRequestMapper.class);
+	private final Map<String, Object> bodyObject = Map.of(
+			"organisationsEinheitId", OrganisationEinheitTestFactory.ID,
+			"name", OrganisationEinheitTestFactory.NAME,
+			"strasse", AddressTestFactory.STREET,
+			"hausnummer", AddressTestFactory.HOUSE_NUMBER,
+			"plz", AddressTestFactory.ZIP_CODE,
+			"ort", AddressTestFactory.CITY
+	);
+
+	@Nested
+	class TestFromCommand {
+
+		@BeforeEach
+		void init() {
+			doReturn(OrganisationEinheitTestFactory.create()).when(mapper).toOrganisationEinheit(any());
+		}
+
+		@Test
+		void shouldMapToOrganisationEinheit() {
+			map();
+
+			verify(mapper).toOrganisationEinheit(bodyObject);
+		}
+
+		@Test
+		void shouldMapForwardingRequestFields() {
+			var mapped = map();
+
+			assertThat(mapped).usingRecursiveComparison().isEqualTo(ForwardingRequestTestFactory.create());
+		}
+
+		private ForwardingRequest map() {
+			return mapper.fromCommand(CommandTestFactory.createBuilder().bodyObject(bodyObject).build());
+		}
+	}
+
+	@Nested
+	class TestToOrganisationEinheit {
+
+		@BeforeEach
+		void init() {
+			doReturn(AddressTestFactory.create()).when(mapper).toAddress(any());
+		}
+
+		@Test
+		void shouldMapToAddress() {
+			map();
+
+			verify(mapper).toAddress(bodyObject);
+		}
+
+		@Test
+		void shouldMapOrganisationEinheitFields() {
+			var mapped = map();
+
+			assertThat(mapped).usingRecursiveComparison().isEqualTo(OrganisationEinheitTestFactory.create());
+		}
+
+		private OrganisationEinheit map() {
+			return mapper.toOrganisationEinheit(bodyObject);
+		}
+	}
+
+	@Nested
+	class TestToAddress {
+
+		@Test
+		void shouldMapAddressFields() {
+			var mapped = map();
+
+			assertThat(mapped).usingRecursiveComparison().isEqualTo(AddressTestFactory.create());
+		}
+
+		private Address map() {
+			return mapper.toAddress(bodyObject);
+		}
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestTestFactory.java
new file mode 100644
index 000000000..dbe06e0b8
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestTestFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import de.ozgcloud.vorgang.callcontext.UserTestFactory;
+import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
+import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRequest.ForwardingRequestBuilder;
+
+class ForwardingRequestTestFactory {
+
+	public static ForwardingRequest create() {
+		return createBuilder().build();
+	}
+
+	public static ForwardingRequestBuilder createBuilder() {
+		return new ForwardingRequestBuilder()
+				.vorgangId(VorgangTestFactory.ID)
+				.version(VorgangTestFactory.VERSION)
+				.createdBy(UserTestFactory.ID)
+				.createdByName(UserTestFactory.NAME)
+				.organisationEinheit(OrganisationEinheitTestFactory.create());
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheitTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheitTestFactory.java
new file mode 100644
index 000000000..27e64b0db
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/OrganisationEinheitTestFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang.redirect;
+
+import java.util.UUID;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.vorgang.vorgang.redirect.OrganisationEinheit.OrganisationEinheitBuilder;
+
+class OrganisationEinheitTestFactory {
+
+	public static final String ID = UUID.randomUUID().toString();
+	public static final String NAME = LoremIpsum.getInstance().getName();
+
+	public static OrganisationEinheit create() {
+		return createBuilder().build();
+	}
+
+	public static OrganisationEinheitBuilder createBuilder() {
+		return new OrganisationEinheitBuilder()
+				.id(ID)
+				.name(NAME)
+				.address(AddressTestFactory.create());
+	}
+}
-- 
GitLab


From 8d3e9d7083dd64cdb6fd96dfe24ffab33689f39c Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Wed, 12 Mar 2025 11:24:14 +0100
Subject: [PATCH 02/14] OZG-7501 OZG-7899 Change signature of
 VorgangService.lockVorgang()

---
 .../de/ozgcloud/vorgang/vorgang/Lock.java     |   6 +-
 .../ozgcloud/vorgang/vorgang/LockMapper.java  |  52 +++++++
 .../vorgang/vorgang/VorgangEventListener.java |   5 +-
 .../vorgang/vorgang/VorgangService.java       |  32 +---
 .../vorgang/vorgang/LockMapperTest.java       | 144 ++++++++++++++++++
 .../vorgang/VorgangEventListenerTest.java     |  55 +++++--
 .../vorgang/vorgang/VorgangServiceITCase.java |  55 +++++--
 .../vorgang/vorgang/VorgangServiceTest.java   |  73 ++-------
 8 files changed, 318 insertions(+), 104 deletions(-)
 create mode 100644 vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
 create mode 100644 vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
index a888e0ea8..336a0335d 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
@@ -25,19 +25,23 @@ package de.ozgcloud.vorgang.vorgang;
 
 import java.time.ZonedDateTime;
 
+import jakarta.validation.constraints.NotNull;
 import lombok.Builder;
 import lombok.Getter;
 
 @Builder
 @Getter
-class Lock {
+public class Lock {
 
 	static final String FIELD_CLIENT_NAME = "clientName";
 	static final String FIELD_LOCKED_SINCE = "lockedSince";
 	static final String FIELD_REASON = "reason";
 
+	@NotNull
 	private final String clientName;
+	@NotNull
 	private final ZonedDateTime lockedSince;
+	@NotNull
 	private final String reason;
 
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
new file mode 100644
index 000000000..c94e7b765
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Map;
+
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+import de.ozgcloud.command.Command;
+
+@Mapper
+interface LockMapper {
+
+	@Mapping(target = "clientName", source = "createdByClientName")
+	@Mapping(target = "lockedSince", expression = "java(getLockedSince())")
+	@Mapping(target = "reason", source = "bodyObject")
+	Lock fromCommand(Command command);
+
+	default String getReason(Map<String, Object> bodyObject) {
+		return StringUtils.trimToNull(MapUtils.getString(bodyObject, Lock.FIELD_REASON));
+	}
+
+	default ZonedDateTime getLockedSince() {
+		return ZonedDateTime.now(ZoneId.of("UTC"));
+	}
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
index be036bb81..d44544422 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
@@ -37,6 +37,7 @@ import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandRevokeFailedEvent;
 import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
 import de.ozgcloud.command.VorgangUnlockedEvent;
 import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.Order;
@@ -72,6 +73,7 @@ public class VorgangEventListener {
 	private final VorgangHeaderService vorgangHeaderService;
 	private final FileService fileService;
 	private final CommandService commandService;
+	private final LockMapper lockMapper;
 
 	private final ApplicationEventPublisher publisher;
 
@@ -122,7 +124,8 @@ public class VorgangEventListener {
 	public void onLockVorgang(CommandCreatedEvent event) {
 		var command = event.getSource();
 		try {
-			vorgangService.lockVorgang(command);
+			vorgangService.lockVorgang(lockMapper.fromCommand(command), command.getVorgangId(), command.getRelationVersion());
+			publisher.publishEvent(new VorgangLockedEvent(command));
 		} catch (RuntimeException e) {
 			LOG.error("Error locking vorgang.", e);
 			publisher.publishEvent(new CommandFailedEvent(command.getId(), e.getMessage()));
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
index 3cbc342a0..a4690f4c7 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
@@ -23,13 +23,10 @@
  */
 package de.ozgcloud.vorgang.vorgang;
 
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -44,8 +41,6 @@ import org.springframework.validation.annotation.Validated;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.VorgangAssignedEvent;
 import de.ozgcloud.command.VorgangCreatedEvent;
-import de.ozgcloud.command.VorgangLockedEvent;
-import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeMap;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap;
@@ -223,30 +218,15 @@ public class VorgangService {
 		return repository.findById(vorgangId).orElseThrow(() -> new NotFoundException(Vorgang.class, vorgangId));
 	}
 
-	public void lockVorgang(Command command) {
-		validateLockCommand(command);
-		repository.patch(command.getVorgangId(), command.getRelationVersion(), buildLockPatch(command));
-		publisher.publishEvent(new VorgangLockedEvent(command));
+	public void lockVorgang(@Valid Lock lock, String vorgangId, Long version) {
+		repository.patch(vorgangId, version, buildLockPatch(lock));
 	}
 
-	void validateLockCommand(Command command) {
-		if (Objects.isNull(command.getCreatedByClientName())) {
-			throw new TechnicalException("Missing client name in lock command");
-		}
-		if (Objects.isNull(getReason(command.getBodyObject()))) {
-			throw new TechnicalException("Missing reason in lock command");
-		}
-	}
-
-	Map<String, Object> buildLockPatch(Command command) {
+	Map<String, Object> buildLockPatch(Lock lock) {
 		return Map.of(KEY_HEADER_LOCK, Map.of(
-				Lock.FIELD_CLIENT_NAME, command.getCreatedByClientName(),
-				Lock.FIELD_LOCKED_SINCE, ZonedDateTime.now(ZoneId.of("UTC")),
-				Lock.FIELD_REASON, getReason(command.getBodyObject())));
-	}
-
-	String getReason(Map<String, Object> commandBody) {
-		return StringUtils.trimToNull(MapUtils.getString(commandBody, Lock.FIELD_REASON));
+				Lock.FIELD_CLIENT_NAME, lock.getClientName(),
+				Lock.FIELD_LOCKED_SINCE, lock.getLockedSince(),
+				Lock.FIELD_REASON, lock.getReason()));
 	}
 
 	public boolean isVorgangLocked(String vorgangId) {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java
new file mode 100644
index 000000000..990b94324
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mapstruct.factory.Mappers;
+import org.mockito.Spy;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.command.Command;
+import de.ozgcloud.vorgang.command.CommandTestFactory;
+
+class LockMapperTest {
+
+	@Spy
+	private LockMapper mapper = Mappers.getMapper(LockMapper.class);
+
+	@Nested
+	class TestFromCommand {
+
+		private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
+
+		@BeforeEach
+		void init() {
+			doReturn(LockTestFactory.REASON).when(mapper).getReason(any());
+			doReturn(LockTestFactory.LOCKED_SINCE).when(mapper).getLockedSince();
+		}
+
+		@Test
+		void shouldGetLockedSince() {
+			map();
+
+			verify(mapper).getLockedSince();
+		}
+
+		@Test
+		void shouldGetReason() {
+			map();
+
+			verify(mapper).getReason(command.getBodyObject());
+		}
+
+		@Test
+		void shouldMap() {
+			var mapped = map();
+
+			assertThat(mapped).usingRecursiveComparison().isEqualTo(LockTestFactory.create());
+		}
+
+		private Lock map() {
+			return mapper.fromCommand(command);
+		}
+	}
+
+	@Nested
+	class TestGetReason {
+
+		@Test
+		void shouldReturnNullIfKeyNotFound() {
+			var mapped = mapper.getReason(Map.of("dummyKey", "dummyValue"));
+
+			assertThat(mapped).isNull();
+		}
+
+		@Test
+		void shouldReturnNullIfValueIsNull() {
+			Map<String, Object> bodyObject = new HashMap<>();
+			bodyObject.put(Lock.FIELD_REASON, null); // need to put, because Map.of() does not accept null values
+
+			var mapped = mapper.getReason(bodyObject);
+
+			assertThat(mapped).isNull();
+		}
+
+		@Test
+		void shouldReturnReason() {
+			var reason = LoremIpsum.getInstance().getWords(2);
+			Map<String, Object> bodyObject = Map.of(Lock.FIELD_REASON, reason);
+
+			var mapped = mapper.getReason(bodyObject);
+
+			assertThat(mapped).isEqualTo(reason);
+		}
+
+		@ParameterizedTest
+		@ValueSource(strings = { " " })
+		@NullAndEmptySource
+		void shouldTrimToNull(String reason) {
+			Map<String, Object> bodyObject = new HashMap<>();
+			bodyObject.put(Lock.FIELD_REASON, reason); // need to put, because Map.of() does not accept null values
+
+			var mapped = mapper.getReason(bodyObject);
+
+			assertThat(mapped).isNull();
+		}
+	}
+
+	@Nested
+	class TestLockedSince {
+
+		@Test
+		void shouldReturnCurrentTime() {
+			var lockedSince = mapper.getLockedSince();
+
+			assertThat(lockedSince).isCloseTo(ZonedDateTime.now(ZoneId.of("UTC")), within(2, ChronoUnit.SECONDS));
+		}
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
index d8bb400c4..dc3152d78 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
@@ -50,6 +50,7 @@ import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandRevokeFailedEvent;
 import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
 import de.ozgcloud.command.VorgangUnlockedEvent;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
@@ -77,6 +78,8 @@ class VorgangEventListenerTest {
 	private FileService fileService;
 	@Mock
 	private CommandService commandService;
+	@Mock
+	private LockMapper lockMapper;
 
 	@Mock
 	private ApplicationEventPublisher publisher;
@@ -239,32 +242,66 @@ class VorgangEventListenerTest {
 	@Nested
 	class TestOnLockVorgang {
 
+		private final Command command = CommandTestFactory.create();
+		private final Lock lock = LockTestFactory.create();
 		@Captor
-		private ArgumentCaptor<CommandFailedEvent> eventCaptor;
+		private ArgumentCaptor<VorgangLockedEvent> lockedEventCaptor;
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> failedEventCaptor;
+
+		@BeforeEach
+		void init() {
+			when(lockMapper.fromCommand(any())).thenReturn(lock);
+		}
+
+		@Test
+		void shouldMapToLock() {
+			onLockVorgang();
+
+			verify(lockMapper).fromCommand(command);
+		}
 
 		@Test
 		void shouldCallLockVorgang() {
-			var command = CommandTestFactory.create();
+			onLockVorgang();
 
-			listener.onLockVorgang(CommandCreatedEventTestFactory.create(command));
+			verify(service).lockVorgang(lock, VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION);
+		}
+
+		@Test
+		void shouldCallPublishEvent() {
+			onLockVorgang();
 
-			verify(service).lockVorgang(command);
+			verify(publisher).publishEvent(lockedEventCaptor.capture());
+			assertThat(lockedEventCaptor.getValue().getCommand()).isSameAs(command);
 		}
 
 		@Test
 		void shouldPublishCommandFailedEvent() {
-			var command = CommandTestFactory.create();
 			var errorMessage = "error message";
-			doThrow(new RuntimeException(errorMessage)).when(service).lockVorgang(command);
+			doThrow(new RuntimeException(errorMessage)).when(service).lockVorgang(any(), any(), anyLong());
 
-			listener.onLockVorgang(CommandCreatedEventTestFactory.create(command));
+			onLockVorgang();
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue()).satisfies(event -> {
+			verify(publisher).publishEvent(failedEventCaptor.capture());
+			assertThat(failedEventCaptor.getValue()).satisfies(event -> {
 				assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID);
 				assertThat(event.getErrorMessage()).isEqualTo(errorMessage);
 			});
 		}
+
+		@Test
+		void shouldNotPublishVorgangLockedEventOnFailure() {
+			doThrow(new RuntimeException("error message")).when(service).lockVorgang(any(), any(), anyLong());
+
+			onLockVorgang();
+
+			verify(publisher, never()).publishEvent(any(VorgangLockedEvent.class));
+		}
+
+		private void onLockVorgang() {
+			listener.onLockVorgang(CommandCreatedEventTestFactory.create(command));
+		}
 	}
 
 	@Nested
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
index 1ddb4dee4..f4a609551 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
@@ -29,20 +29,19 @@ import static org.mockito.Mockito.*;
 
 import java.util.List;
 
-import jakarta.validation.ConstraintViolationException;
-
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
 
 import de.ozgcloud.common.test.DataITCase;
 import de.ozgcloud.notification.antragsteller.AntragstellerNotificationEventListener;
 import de.ozgcloud.notification.user.UserNotificationEventListener;
 import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.servicekonto.ServiceKontoTestFactory;
+import jakarta.validation.ConstraintViolationException;
 
 @DataITCase
 @WithMockUser
@@ -51,14 +50,14 @@ class VorgangServiceITCase {
 	@Autowired
 	private VorgangService vorgangService;
 
-	@MockBean
+	@MockitoBean
 	private CommandService commandService;
-
-	@MockBean
+	@MockitoBean
 	private AntragstellerNotificationEventListener antragstellerNotificationEventListener;
-
-	@MockBean
+	@MockitoBean
 	private UserNotificationEventListener userNotificationEventListener;
+	@MockitoBean
+	private VorgangRepository vorgangRepository;
 
 	@DisplayName("Test creating a new Vorgang")
 	@Nested
@@ -92,11 +91,49 @@ class VorgangServiceITCase {
 			@Test
 			void shouldBeInvalidOnMissingPostfachAddress() {
 				var eingang = EingangTestFactory.createBuilder().header(EingangHeaderTestFactory.createBuilder()
-						.serviceKonto(ServiceKontoTestFactory.createBuilder().clearPostfachAddresses().build()).build())
+								.serviceKonto(ServiceKontoTestFactory.createBuilder().clearPostfachAddresses().build()).build())
 						.build();
 
 				assertThatThrownBy(() -> vorgangService.startCreation(eingang)).isInstanceOf(ConstraintViolationException.class);
 			}
 		}
 	}
+
+	@Nested
+	class TestLockVorgang {
+
+		@Nested
+		class TestValidation {
+
+			@Test
+			void shouldBeInvalidOnMissingClientName() {
+				var lock = LockTestFactory.createBuilder().clientName(null).build();
+
+				assertThatThrownBy(() -> vorgangService.lockVorgang(lock, VorgangTestFactory.ID, VorgangTestFactory.VERSION)).isInstanceOf(
+						ConstraintViolationException.class);
+			}
+
+			@Test
+			void shouldBeInvalidOnMissingLockedSince() {
+				var lock = LockTestFactory.createBuilder().lockedSince(null).build();
+
+				assertThatThrownBy(() -> vorgangService.lockVorgang(lock, VorgangTestFactory.ID, VorgangTestFactory.VERSION)).isInstanceOf(
+						ConstraintViolationException.class);
+			}
+
+			@Test
+			void shouldBeInvalidOnMissingReason() {
+				var lock = LockTestFactory.createBuilder().reason(null).build();
+
+				assertThatThrownBy(() -> vorgangService.lockVorgang(lock, VorgangTestFactory.ID, VorgangTestFactory.VERSION)).isInstanceOf(
+						ConstraintViolationException.class);
+			}
+
+			@Test
+			void shouldBeValidWhenRequiredFieldsAreNotNull() {
+				assertThatNoException().isThrownBy(
+						() -> vorgangService.lockVorgang(LockTestFactory.create(), VorgangTestFactory.ID, VorgangTestFactory.VERSION));
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
index 3449659b1..dd60f6033 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
@@ -28,13 +28,10 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import org.assertj.core.api.*;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -53,7 +50,6 @@ import de.ozgcloud.command.Command;
 import de.ozgcloud.command.VorgangAssignedEvent;
 import de.ozgcloud.command.VorgangCreatedEvent;
 import de.ozgcloud.command.VorgangLockedEvent;
-import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
@@ -352,7 +348,8 @@ class VorgangServiceTest {
 			void shouldThrowAccessDeniedException() {
 				when(vorgangAuthorizationService.authorizeByOrganisationseinheitenId(any(), any())).thenReturn(false);
 
-				assertThrows(AccessDeniedException.class, () -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); // NOSONAR
+				assertThrows(AccessDeniedException.class,
+						() -> service.getById(VorgangTestFactory.ID, FilterCriteriaTestFactory.create())); // NOSONAR
 			}
 		}
 
@@ -516,7 +513,7 @@ class VorgangServiceTest {
 	@Nested
 	class TestLockVorgang {
 
-		private static final Command LOCK_COMMAND = CommandTestFactory.create();
+		private final Lock lock = LockTestFactory.create();
 		private static final Map<String, Object> LOCK_PATCH = Map.of("key", "value");
 
 		@Captor
@@ -524,92 +521,53 @@ class VorgangServiceTest {
 
 		@BeforeEach
 		void init() {
-			doNothing().when(service).validateLockCommand(any());
 			doReturn(LOCK_PATCH).when(service).buildLockPatch(any());
 		}
 
-		@Test
-		void shouldCallValidateLockCommand() {
-			service.lockVorgang(LOCK_COMMAND);
-
-			verify(service).validateLockCommand(LOCK_COMMAND);
-		}
-
 		@Test
 		void shouldCallBuildLockPatch() {
-			service.lockVorgang(LOCK_COMMAND);
+			lockVorgang();
 
-			verify(service).buildLockPatch(LOCK_COMMAND);
+			verify(service).buildLockPatch(lock);
 		}
 
 		@Test
 		void shouldCallRepository() {
-			service.lockVorgang(LOCK_COMMAND);
+			lockVorgang();
 
 			verify(repository).patch(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, LOCK_PATCH);
 		}
 
-		@Test
-		void shouldCallPublishEvent() {
-			service.lockVorgang(LOCK_COMMAND);
-
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue().getCommand()).isSameAs(LOCK_COMMAND);
-		}
-	}
-
-	@Nested
-	class TestValidateLockCommand {
-
-		@Test
-		void shouldThrowExceptionOnMissingClient() {
-			var command = CommandTestFactory.createBuilder().createdByClientName(null).build();
-
-			assertThrows(TechnicalException.class, () -> service.validateLockCommand(command));
-		}
-
-		@Test
-		void shouldThrowExceptionOnMissingReason() {
-			var command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build();
-
-			assertThrows(TechnicalException.class, () -> service.validateLockCommand(command));
-		}
-
-		@Test
-		void shouldAcceptValidCommand() {
-			var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
-
-			assertDoesNotThrow(() -> service.validateLockCommand(command));
+		private void lockVorgang() {
+			service.lockVorgang(lock, VorgangTestFactory.ID, VorgangTestFactory.VERSION);
 		}
 	}
 
 	@Nested
 	class TestBuildLockPatch {
 
-		private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
-
 		@Test
 		void shouldSetClientName() {
-			var result = service.buildLockPatch(command);
+			var result = service.buildLockPatch(LockTestFactory.create());
 
 			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP)
-					.containsEntry(Lock.FIELD_CLIENT_NAME, CommandTestFactory.CREATED_BY_CLIENT);
+					.containsEntry(Lock.FIELD_CLIENT_NAME, LockTestFactory.CLIENT_NAME);
 		}
 
 		@Test
 		void shouldSetLockedSince() {
-			var result = service.buildLockPatch(command);
+			var result = service.buildLockPatch(LockTestFactory.create());
 
 			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP)
-					.extractingByKey(Lock.FIELD_LOCKED_SINCE, InstanceOfAssertFactories.ZONED_DATE_TIME)
-					.isCloseTo(ZonedDateTime.now(), within(1, ChronoUnit.SECONDS));
+					.containsEntry(Lock.FIELD_LOCKED_SINCE, LockTestFactory.LOCKED_SINCE);
 		}
 
 		@Test
 		void shouldSetReason() {
-			var result = service.buildLockPatch(command);
+			var result = service.buildLockPatch(LockTestFactory.create());
 
-			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP).containsEntry(Lock.FIELD_REASON, LockTestFactory.REASON);
+			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP)
+					.containsEntry(Lock.FIELD_REASON, LockTestFactory.REASON);
 		}
 	}
 
@@ -760,7 +718,6 @@ class VorgangServiceTest {
 		}
 	}
 
-
 	@Nested
 	class TestFindDeleted {
 
-- 
GitLab


From a27cf1a15ad64185868a92ad53fe4ae12dfd7fca Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Wed, 12 Mar 2025 14:55:23 +0100
Subject: [PATCH 03/14] OZG-7501 OZG-7899 Lock Vorgang and update status

---
 .../vorgang/status/StatusService.java         | 14 +++--
 .../de/ozgcloud/vorgang/vorgang/Lock.java     |  2 +-
 .../ozgcloud/vorgang/vorgang/LockMapper.java  |  2 +-
 .../redirect/ForwardingEventListener.java     | 12 ++++
 .../vorgang/redirect/ForwardingService.java   |  2 +-
 .../vorgang/status/StatusServiceTest.java     | 61 +++++++++++--------
 .../vorgang/VorgangEventListenerTest.java     |  2 +-
 .../redirect/ForwardingEventListenerTest.java | 56 +++++++++++++++--
 .../redirect/ForwardingServiceTest.java       | 11 ++++
 9 files changed, 119 insertions(+), 43 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
index a87a9901c..055826fd9 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
@@ -29,7 +29,6 @@ import java.util.Objects;
 import java.util.Optional;
 
 import org.apache.commons.collections4.MapUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 
@@ -41,18 +40,17 @@ import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.command.PersistedCommand;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.Vorgang.Status;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
 @Service
+@RequiredArgsConstructor
 @Log4j2
 public class StatusService {
 	private static final String CONCURRENT_MODIFICATION_ERROR_CODE = "concurrent_modification";
 
-	@Autowired
-	private ApplicationEventPublisher publisher;
-
-	@Autowired
-	private StatusRepository repository;
+	private final ApplicationEventPublisher publisher;
+	private final StatusRepository repository;
 
 	void setStatusNeu(Command command) {
 		executeStatusChangeCommand(command, Status.NEU);
@@ -100,6 +98,10 @@ public class StatusService {
 		doUpdateStatus(vorgangId, version, Status.IN_BEARBEITUNG.name());
 	}
 
+	public void setStatusToWeitergeleitet(String vorgangId, long version) {
+			doUpdateStatus(vorgangId, version, Status.WEITERGELEITET.name());
+	}
+
 	public void revokeStatusChange(Command command) {
 		try {
 			doUpdateStatus(command.getRelationId(), command.getRelationVersion() + 1,
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
index 336a0335d..51060326c 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
@@ -29,7 +29,7 @@ import jakarta.validation.constraints.NotNull;
 import lombok.Builder;
 import lombok.Getter;
 
-@Builder
+@Builder(toBuilder = true)
 @Getter
 public class Lock {
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
index c94e7b765..668cccff4 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
@@ -35,7 +35,7 @@ import org.mapstruct.Mapping;
 import de.ozgcloud.command.Command;
 
 @Mapper
-interface LockMapper {
+public interface LockMapper {
 
 	@Mapping(target = "clientName", source = "createdByClientName")
 	@Mapping(target = "lockedSince", expression = "java(getLockedSince())")
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index 7f25cf25b..b8aab024e 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -33,10 +33,13 @@ import org.springframework.stereotype.Component;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
 import de.ozgcloud.nachrichten.email.MailSendErrorEvent;
 import de.ozgcloud.nachrichten.email.MailSendRequest;
 import de.ozgcloud.nachrichten.email.MailSentEvent;
 import de.ozgcloud.vorgang.command.Order;
+import de.ozgcloud.vorgang.vorgang.LockMapper;
+import de.ozgcloud.vorgang.vorgang.VorgangService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
@@ -60,6 +63,8 @@ public class ForwardingEventListener {
 	private final ForwardingService service;
 	private final ApplicationEventPublisher publisher;
 	private final ForwardingRequestMapper forwardingRequestMapper;
+	private final VorgangService vorgangService;
+	private final LockMapper lockMapper;
 
 	@EventListener(condition = IS_FORWARD_ORDER_CONDITION)
 	public void onForwardOrder(CommandCreatedEvent event) {
@@ -92,7 +97,14 @@ public class ForwardingEventListener {
 
 	@EventListener(condition = IS_FORWARD_VORGANG_ORDER_CONDITION)
 	public void onForwardVorgangOrder(CommandCreatedEvent event) {
+		lockVorgangOnForwarding(event.getSource());
 		service.forward(forwardingRequestMapper.fromCommand(event.getSource()));
+		publisher.publishEvent(new VorgangLockedEvent(event.getSource()));
+	}
+
+	private void lockVorgangOnForwarding(Command command) {
+		var lock = lockMapper.fromCommand(command).toBuilder().reason("Vorgang is being forwarded").build();
+		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion());
 	}
 
 	private void handleException(Runnable runnable, String commandId) {
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
index a38f6fcf7..ed26c9e98 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingService.java
@@ -331,6 +331,6 @@ public class ForwardingService {
 	}
 
 	public void forward(ForwardingRequest request) {
-
+		statusService.setStatusToWeitergeleitet(request.getVorgangId(), request.getVersion());
 	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusServiceTest.java
index 17e4694ec..eb96cbe95 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusServiceTest.java
@@ -39,6 +39,8 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.springframework.context.ApplicationEventPublisher;
 
+import com.thedeanda.lorem.LoremIpsum;
+
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandRevokedEvent;
@@ -52,18 +54,17 @@ import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 class StatusServiceTest {
 
+	@Spy
+	@InjectMocks
+	private StatusService service;
+	@Mock
+	private StatusRepository repository;
+	@Mock
+	private ApplicationEventPublisher publisher;
+
 	@DisplayName("Test handling vorgang status changes")
 	@Nested
 	class TestVorgangStatusChanges {
-		@Spy
-		@InjectMocks
-		private StatusService service;
-
-		@Mock
-		private StatusRepository repository;
-
-		@Mock
-		private ApplicationEventPublisher publisher;
 
 		private PersistedCommand command = CommandTestFactory.create();
 
@@ -261,15 +262,6 @@ class StatusServiceTest {
 	@DisplayName("Test status changes when a Vorgang is forwarded")
 	@Nested
 	class TestVorgangWeiterleiten {
-		@Spy
-		@InjectMocks
-		private StatusService service;
-
-		@Mock
-		private StatusRepository repository;
-
-		@Mock
-		private ApplicationEventPublisher publisher;
 
 		@Mock
 		private PersistedCommand command;
@@ -299,15 +291,6 @@ class StatusServiceTest {
 	@DisplayName("Test handling revoke command status changes")
 	@Nested
 	class TestRevokeStatusChanges {
-		@Spy
-		@InjectMocks
-		private StatusService service;
-
-		@Mock
-		private StatusRepository repository;
-
-		@Mock
-		private ApplicationEventPublisher publisher;
 
 		private static final String PREVIOUS_STATUS = Vorgang.Status.BESCHIEDEN.name();
 		private PersistedCommand command = CommandTestFactory.createBuilder()
@@ -381,4 +364,28 @@ class StatusServiceTest {
 			}
 		}
 	}
+
+	@Nested
+	class TestSetStatusToWeitergeleitet {
+
+		@Test
+		void shouldUpdateStatus() {
+			service.setStatusToWeitergeleitet(VorgangTestFactory.ID, VorgangTestFactory.VERSION);
+
+			verify(service).doUpdateStatus(VorgangTestFactory.ID, VorgangTestFactory.VERSION, Status.WEITERGELEITET.name());
+		}
+	}
+
+	@Nested
+	class TestDoUpdateStatus {
+
+		@Test
+		void shouldPatchVorgangWithNewStatus() {
+			var statusName = LoremIpsum.getInstance().getWords(1);
+
+			service.doUpdateStatus(VorgangTestFactory.ID, VorgangTestFactory.VERSION, statusName);
+
+			verify(repository).patch(VorgangTestFactory.ID, VorgangTestFactory.VERSION, Map.of(Vorgang.MONGODB_FIELDNAME_STATUS, statusName));
+		}
+	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
index dc3152d78..68c76516d 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
@@ -269,7 +269,7 @@ class VorgangEventListenerTest {
 		}
 
 		@Test
-		void shouldCallPublishEvent() {
+		void shouldPublishVorgangLockedEvent() {
 			onLockVorgang();
 
 			verify(publisher).publishEvent(lockedEventCaptor.capture());
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 364aa21a9..4ca29c2ac 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -44,10 +44,16 @@ import com.thedeanda.lorem.LoremIpsum;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
 import de.ozgcloud.nachrichten.email.MailSentEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.command.Order;
+import de.ozgcloud.vorgang.vorgang.Lock;
+import de.ozgcloud.vorgang.vorgang.LockMapper;
+import de.ozgcloud.vorgang.vorgang.LockTestFactory;
+import de.ozgcloud.vorgang.vorgang.VorgangService;
+import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 class ForwardingEventListenerTest {
 
@@ -60,6 +66,10 @@ class ForwardingEventListenerTest {
 	private ApplicationEventPublisher publisher;
 	@Mock
 	private ForwardingRequestMapper forwardingRequestMapper;
+	@Mock
+	private VorgangService vorgangService;
+	@Mock
+	private LockMapper lockMapper;
 
 	@Nested
 	class OnForwardOrderCommand {
@@ -74,9 +84,9 @@ class ForwardingEventListenerTest {
 		@Test
 		void shouldPublishFailedEventOnError() {
 			when(forwardingService.forwardByCommand(any())).thenThrow(ConcurrentModificationException.class);
-			
+
 			listener.onForwardOrder(CommandCreatedEventTestFactory.create());
-			
+
 			verify(publisher).publishEvent(any(CommandFailedEvent.class));
 		}
 	}
@@ -99,29 +109,63 @@ class ForwardingEventListenerTest {
 	class TestOnForwardVorgangOrder {
 
 		private final CommandCreatedEvent event = event();
+		private final Lock lock = LockTestFactory.create();
+		@Captor
+		private ArgumentCaptor<Lock> lockCaptor;
 		@Captor
 		private ArgumentCaptor<ForwardingRequest> forwardingRequestCaptor;
+		@Captor
+		private ArgumentCaptor<VorgangLockedEvent> lockedEventCaptor;
 
 		@BeforeEach
 		void init() {
-			when(forwardingRequestMapper.fromCommand(event.getSource())).thenReturn(ForwardingRequestTestFactory.create());
+			when(forwardingRequestMapper.fromCommand(any())).thenReturn(ForwardingRequestTestFactory.create());
+			when(lockMapper.fromCommand(any())).thenReturn(lock);
+		}
+
+		@Test
+		void shouldMapLock() {
+			onForwardVorgangOrder();
+
+			verify(lockMapper).fromCommand(event.getSource());
+		}
+
+		@Test
+		void shouldLockVorgang() {
+			onForwardVorgangOrder();
+
+			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION));
+			assertThat(lockCaptor.getValue()).usingRecursiveComparison()
+					.isEqualTo(LockTestFactory.createBuilder().reason("Vorgang is being forwarded").build());
 		}
 
 		@Test
 		void shouldMapCommandForwardingRequest() {
-			listener.onForwardVorgangOrder(event);
+			onForwardVorgangOrder();
 
 			verify(forwardingRequestMapper).fromCommand(event.getSource());
 		}
 
 		@Test
 		void shouldCallForwardingService() {
-			listener.onForwardVorgangOrder(event);
+			onForwardVorgangOrder();
 
 			verify(forwardingService).forward(forwardingRequestCaptor.capture());
 			assertThat(forwardingRequestCaptor.getValue()).usingRecursiveComparison().isEqualTo(ForwardingRequestTestFactory.create());
 		}
 
+		@Test
+		void shouldPublishVorgangLockedEvent() {
+			onForwardVorgangOrder();
+
+			verify(publisher).publishEvent(lockedEventCaptor.capture());
+			assertThat(lockedEventCaptor.getValue().getCommand()).isSameAs(event.getSource());
+		}
+
+		private void onForwardVorgangOrder() {
+			listener.onForwardVorgangOrder(event);
+		}
+
 		private static CommandCreatedEvent event() {
 			return CommandCreatedEventTestFactory.create(CommandTestFactory.createBuilder().bodyObject(commandBody()).build());
 		}
@@ -129,7 +173,7 @@ class ForwardingEventListenerTest {
 		private static Map<String, Object> commandBody() {
 			return Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1));
 		}
- 	}
+	}
 
 	@Nested
 	class TestMarkAsSuccessfull {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java
index ac84ad8b7..1b864c7a9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingServiceTest.java
@@ -622,4 +622,15 @@ class ForwardingServiceTest {
 		}
 
 	}
+
+	@Nested
+	class TestForward {
+
+		@Test
+		void shouldSetStatusToWeitergeleitet() {
+			service.forward(ForwardingRequestTestFactory.create());
+
+			verify(statusService).setStatusToWeitergeleitet(VorgangTestFactory.ID, VorgangTestFactory.VERSION);
+		}
+	}
 }
\ No newline at end of file
-- 
GitLab


From a1dd8f2477b404c94cc6d388bf991dd40549ec39 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Wed, 12 Mar 2025 15:06:21 +0100
Subject: [PATCH 04/14] OZG-7501 OZG-7899 Fix test

---
 .../java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java  | 2 --
 1 file changed, 2 deletions(-)

diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
index f4a609551..96de483c5 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceITCase.java
@@ -56,8 +56,6 @@ class VorgangServiceITCase {
 	private AntragstellerNotificationEventListener antragstellerNotificationEventListener;
 	@MockitoBean
 	private UserNotificationEventListener userNotificationEventListener;
-	@MockitoBean
-	private VorgangRepository vorgangRepository;
 
 	@DisplayName("Test creating a new Vorgang")
 	@Nested
-- 
GitLab


From 327d395e52e8a2b0ca5634fd58c3eef35075c616 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Wed, 12 Mar 2025 16:46:58 +0100
Subject: [PATCH 05/14] OZG-7501 OZG-7899 Fix concurrent modification

---
 .../redirect/ForwardingEventListener.java     | 17 +++-
 .../vorgang/redirect/ForwardingRequest.java   |  2 +-
 .../redirect/ForwardingEventListenerTest.java | 77 ++++++++++++++-----
 3 files changed, 73 insertions(+), 23 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index b8aab024e..83e00d9f1 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -97,16 +97,25 @@ public class ForwardingEventListener {
 
 	@EventListener(condition = IS_FORWARD_VORGANG_ORDER_CONDITION)
 	public void onForwardVorgangOrder(CommandCreatedEvent event) {
-		lockVorgangOnForwarding(event.getSource());
-		service.forward(forwardingRequestMapper.fromCommand(event.getSource()));
-		publisher.publishEvent(new VorgangLockedEvent(event.getSource()));
+		handleException(() -> handleForwardVorgangCommand(event.getSource()), event.getSource().getId());
+	}
+
+	void handleForwardVorgangCommand(Command command) {
+		lockVorgangOnForwarding(command);
+		service.forward(updateVorgangVersion(forwardingRequestMapper.fromCommand(command)));
+		publisher.publishEvent(new VorgangLockedEvent(command));
 	}
 
 	private void lockVorgangOnForwarding(Command command) {
-		var lock = lockMapper.fromCommand(command).toBuilder().reason("Vorgang is being forwarded").build();
+		var lock = lockMapper.fromCommand(command).toBuilder().reason("Vorgang was forwarded").build();
 		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion());
 	}
 
+	ForwardingRequest updateVorgangVersion(ForwardingRequest request) {
+		var vorgang = vorgangService.getById(request.getVorgangId());
+		return request.toBuilder().version(vorgang.getVersion()).build();
+	}
+
 	private void handleException(Runnable runnable, String commandId) {
 		try {
 			runnable.run();
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
index b8dbf0587..251798656 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequest.java
@@ -27,7 +27,7 @@ import lombok.Builder;
 import lombok.Getter;
 
 @Getter
-@Builder
+@Builder(toBuilder = true)
 public class ForwardingRequest {
 
 	private String vorgangId;
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 4ca29c2ac..588060cef 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -37,6 +37,7 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Spy;
 import org.springframework.context.ApplicationEventPublisher;
 
 import com.thedeanda.lorem.LoremIpsum;
@@ -45,6 +46,7 @@ import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.VorgangLockedEvent;
+import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.nachrichten.email.MailSentEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
@@ -57,6 +59,7 @@ import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 class ForwardingEventListenerTest {
 
+	@Spy
 	@InjectMocks // NOSONAR
 	private ForwardingEventListener listener;
 
@@ -108,8 +111,42 @@ class ForwardingEventListenerTest {
 	@Nested
 	class TestOnForwardVorgangOrder {
 
-		private final CommandCreatedEvent event = event();
+		private final CommandCreatedEvent event = CommandCreatedEventTestFactory.create();
+
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> failedEventCaptor;
+
+		@Test
+		void shouldHandleForwardVorgangCommand() {
+			doNothing().when(listener).handleForwardVorgangCommand(any());
+
+			onForwardVorgangOrder();
+
+			verify(listener).handleForwardVorgangCommand(event.getSource());
+		}
+
+		@Test
+		void shouldPublishFailedEventOnError() {
+			doThrow(TechnicalException.class).when(listener).handleForwardVorgangCommand(any());
+
+			onForwardVorgangOrder();
+
+			verify(publisher).publishEvent(failedEventCaptor.capture());
+			assertThat(failedEventCaptor.getValue().getSource()).isEqualTo(event.getSource().getId());
+		}
+
+		private void onForwardVorgangOrder() {
+			listener.onForwardVorgangOrder(event);
+		}
+	}
+
+	@Nested
+	class TestHandleForwardVorgangCommand {
+
+		private final Command command = CommandTestFactory.createBuilder().bodyObject(commandBody()).build();
 		private final Lock lock = LockTestFactory.create();
+		private final ForwardingRequest request = ForwardingRequestTestFactory.create();
+		private final ForwardingRequest updatedRequest = ForwardingRequestTestFactory.createBuilder().version(request.getVersion() + 1).build();
 		@Captor
 		private ArgumentCaptor<Lock> lockCaptor;
 		@Captor
@@ -119,55 +156,59 @@ class ForwardingEventListenerTest {
 
 		@BeforeEach
 		void init() {
-			when(forwardingRequestMapper.fromCommand(any())).thenReturn(ForwardingRequestTestFactory.create());
+			when(forwardingRequestMapper.fromCommand(any())).thenReturn(request);
 			when(lockMapper.fromCommand(any())).thenReturn(lock);
+			doReturn(updatedRequest).when(listener).updateVorgangVersion(any());
 		}
 
 		@Test
 		void shouldMapLock() {
-			onForwardVorgangOrder();
+			handleForwardVorgangCommand();
 
-			verify(lockMapper).fromCommand(event.getSource());
+			verify(lockMapper).fromCommand(command);
 		}
 
 		@Test
 		void shouldLockVorgang() {
-			onForwardVorgangOrder();
+			handleForwardVorgangCommand();
 
 			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION));
 			assertThat(lockCaptor.getValue()).usingRecursiveComparison()
-					.isEqualTo(LockTestFactory.createBuilder().reason("Vorgang is being forwarded").build());
+					.isEqualTo(LockTestFactory.createBuilder().reason("Vorgang was forwarded").build());
 		}
 
 		@Test
 		void shouldMapCommandForwardingRequest() {
-			onForwardVorgangOrder();
+			handleForwardVorgangCommand();
+
+			verify(forwardingRequestMapper).fromCommand(command);
+		}
+
+		@Test
+		void shouldUpdateVorgangVersionInRequest() {
+			handleForwardVorgangCommand();
 
-			verify(forwardingRequestMapper).fromCommand(event.getSource());
+			verify(listener).updateVorgangVersion(request);
 		}
 
 		@Test
 		void shouldCallForwardingService() {
-			onForwardVorgangOrder();
+			handleForwardVorgangCommand();
 
 			verify(forwardingService).forward(forwardingRequestCaptor.capture());
-			assertThat(forwardingRequestCaptor.getValue()).usingRecursiveComparison().isEqualTo(ForwardingRequestTestFactory.create());
+			assertThat(forwardingRequestCaptor.getValue()).isSameAs(updatedRequest);
 		}
 
 		@Test
 		void shouldPublishVorgangLockedEvent() {
-			onForwardVorgangOrder();
+			handleForwardVorgangCommand();
 
 			verify(publisher).publishEvent(lockedEventCaptor.capture());
-			assertThat(lockedEventCaptor.getValue().getCommand()).isSameAs(event.getSource());
-		}
-
-		private void onForwardVorgangOrder() {
-			listener.onForwardVorgangOrder(event);
+			assertThat(lockedEventCaptor.getValue().getCommand()).isSameAs(command);
 		}
 
-		private static CommandCreatedEvent event() {
-			return CommandCreatedEventTestFactory.create(CommandTestFactory.createBuilder().bodyObject(commandBody()).build());
+		private void handleForwardVorgangCommand() {
+			listener.handleForwardVorgangCommand(command);
 		}
 
 		private static Map<String, Object> commandBody() {
-- 
GitLab


From b14d3ad35e9de9390087e815119e5b1aab8b1193 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Wed, 12 Mar 2025 17:42:34 +0100
Subject: [PATCH 06/14] OZG-7501 OZG-7899 Extend ForwardingEventListenerITCase

---
 .../ForwardingEventListenerITCase.java        | 59 +++++++++++++++++--
 1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerITCase.java
index d196e31bc..52046ba41 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerITCase.java
@@ -23,29 +23,35 @@
  */
 package de.ozgcloud.vorgang.vorgang.redirect;
 
+import static org.assertj.core.api.Assertions.*;
 import static org.awaitility.Awaitility.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.concurrent.TimeUnit;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.EnumSource;
 import org.junit.jupiter.params.provider.EnumSource.Mode;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
 
 import de.ozgcloud.command.Command;
 import de.ozgcloud.common.test.ITCase;
 import de.ozgcloud.nachrichten.email.MailSentEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
+import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.command.Order;
 import de.ozgcloud.vorgang.vorgang.VorgangService;
+import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 @ITCase
 class ForwardingEventListenerITCase {
@@ -53,15 +59,17 @@ class ForwardingEventListenerITCase {
 	@Autowired
 	private ApplicationEventPublisher publisher;
 
-	@MockBean
+	@MockitoBean
 	private ForwardingService service;
-	@MockBean
+	@MockitoBean
 	private JavaMailSender mailSender;
-	@MockBean
+	@MockitoBean
 	private VorgangService vorgangService;
+	@MockitoBean
+	private CommandService commandService;
 
 	@Nested
-	class TestForwardVorgang {
+	class TestRedirectdVorgang {
 
 		@Test
 		void shouldCallForwardingService() {
@@ -109,4 +117,45 @@ class ForwardingEventListenerITCase {
 		}
 	}
 
+	@Nested
+	class TestForwardVorgang {
+
+		private Command command = CommandTestFactory.createBuilder().order(Order.FORWARD_VORGANG.name()).build();
+		@Captor
+		private ArgumentCaptor<ForwardingRequest> requestCaptor;
+
+		@BeforeEach
+		void init() {
+			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
+		}
+
+		@Test
+		void shouldCallForwardingService() {
+			publishEvent();
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(service).forward(requestCaptor.capture()));
+			assertThat(requestCaptor.getValue().getVorgangId()).isEqualTo(command.getVorgangId());
+		}
+
+		@Test
+		void shouldSetCommandFinished() {
+			publishEvent();
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(commandService).setCommandFinished(command.getId(), null));
+		}
+
+		@Test
+		void shouldSetCommandFailed() {
+			doThrow(RuntimeException.class).when(service).forward(any());
+
+			publishEvent();
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(commandService).setCommandError(eq(command.getId()), any()));
+		}
+
+		private void publishEvent() {
+			publisher.publishEvent(CommandCreatedEventTestFactory.create(command));
+		}
+	}
+
 }
-- 
GitLab


From 215cf2c959e118e74b66452084da9edea9498bf4 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Thu, 13 Mar 2025 15:00:08 +0100
Subject: [PATCH 07/14] OZG-7501 OZG-7899 Use ZoneOffset

---
 .../src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java | 4 ++--
 .../test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
index 668cccff4..8260a3e36 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/LockMapper.java
@@ -23,7 +23,7 @@
  */
 package de.ozgcloud.vorgang.vorgang;
 
-import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Map;
 
@@ -47,6 +47,6 @@ public interface LockMapper {
 	}
 
 	default ZonedDateTime getLockedSince() {
-		return ZonedDateTime.now(ZoneId.of("UTC"));
+		return ZonedDateTime.now(ZoneOffset.UTC);
 	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java
index 990b94324..2d0d9f17f 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockMapperTest.java
@@ -26,7 +26,7 @@ package de.ozgcloud.vorgang.vorgang;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.HashMap;
@@ -138,7 +138,7 @@ class LockMapperTest {
 		void shouldReturnCurrentTime() {
 			var lockedSince = mapper.getLockedSince();
 
-			assertThat(lockedSince).isCloseTo(ZonedDateTime.now(ZoneId.of("UTC")), within(2, ChronoUnit.SECONDS));
+			assertThat(lockedSince).isCloseTo(ZonedDateTime.now(ZoneOffset.UTC), within(2, ChronoUnit.SECONDS));
 		}
 	}
 }
-- 
GitLab


From 48d9c324daab334d5d0fdf166220b4eb43eeddc4 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Thu, 13 Mar 2025 15:00:35 +0100
Subject: [PATCH 08/14] OZG-7501 OZG-7899 Fix formatting

---
 .../src/main/java/de/ozgcloud/vorgang/status/StatusService.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
index 055826fd9..bd9df2149 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusService.java
@@ -99,7 +99,7 @@ public class StatusService {
 	}
 
 	public void setStatusToWeitergeleitet(String vorgangId, long version) {
-			doUpdateStatus(vorgangId, version, Status.WEITERGELEITET.name());
+		doUpdateStatus(vorgangId, version, Status.WEITERGELEITET.name());
 	}
 
 	public void revokeStatusChange(Command command) {
-- 
GitLab


From 486d10f3554a72b56d0ad28b0b630c5cddf51c66 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Thu, 13 Mar 2025 15:01:28 +0100
Subject: [PATCH 09/14] OZG-7501 OZG-7899 Rename forwardOrder

---
 .../vorgang/vorgang/redirect/ForwardingEventListener.java | 8 ++++----
 .../vorgang/redirect/ForwardingEventListenerTest.java     | 6 +++---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index 83e00d9f1..56b8691e8 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -51,13 +51,13 @@ public class ForwardingEventListener {
 	private static final String IS_REDIRECT_EVENT_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_REDIRECT_MAIL_REQ.test(event.getSource())}";
 	private static final String IS_SUCCESSFULL_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_SUCCESSFULL_ORDER.test(event.getSource())}";
 	private static final String IS_FAILED_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FAILED_ORDER.test(event.getSource())}";
-	private static final String IS_FORWARD_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FORWARD_ORDER.test(event.getSource())}";
+	private static final String IS_REDIRECT_VORGANG_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_REDIRECT_VORGANG_ORDER.test(event.getSource())}";
 	private static final String IS_FORWARD_VORGANG_ORDER_CONDITION = "{T(de.ozgcloud.vorgang.vorgang.redirect.ForwardingEventListener).IS_FORWARD_VORGANG_ORDER.test(event.getSource())}";
 
 	public static final Predicate<MailSendRequest> IS_REDIRECT_MAIL_REQ = req -> req.getRequestReference() instanceof Forwarding;
 	public static final Predicate<Command> IS_SUCCESSFULL_ORDER = command -> Order.FORWARD_SUCCESSFULL.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_FAILED_ORDER = command -> Order.FORWARD_FAILED.isMeant(command.getOrder());
-	public static final Predicate<Command> IS_FORWARD_ORDER = command -> Order.REDIRECT_VORGANG.isMeant(command.getOrder());
+	public static final Predicate<Command> IS_REDIRECT_VORGANG_ORDER = command -> Order.REDIRECT_VORGANG.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_FORWARD_VORGANG_ORDER = command -> Order.FORWARD_VORGANG.isMeant(command.getOrder());
 
 	private final ForwardingService service;
@@ -66,8 +66,8 @@ public class ForwardingEventListener {
 	private final VorgangService vorgangService;
 	private final LockMapper lockMapper;
 
-	@EventListener(condition = IS_FORWARD_ORDER_CONDITION)
-	public void onForwardOrder(CommandCreatedEvent event) {
+	@EventListener(condition = IS_REDIRECT_VORGANG_ORDER_CONDITION)
+	public void onRedirectVorgangOrder(CommandCreatedEvent event) {
 		handleException(() -> service.forwardByCommand(event.getSource()), event.getSource().getId());
 	}
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 588060cef..acb4c3377 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -75,11 +75,11 @@ class ForwardingEventListenerTest {
 	private LockMapper lockMapper;
 
 	@Nested
-	class OnForwardOrderCommand {
+	class OnRedirectVorgangCommand {
 
 		@Test
 		void shouldCallService() {
-			listener.onForwardOrder(CommandCreatedEventTestFactory.create());
+			listener.onRedirectVorgangOrder(CommandCreatedEventTestFactory.create());
 
 			verify(forwardingService).forwardByCommand(notNull());
 		}
@@ -88,7 +88,7 @@ class ForwardingEventListenerTest {
 		void shouldPublishFailedEventOnError() {
 			when(forwardingService.forwardByCommand(any())).thenThrow(ConcurrentModificationException.class);
 
-			listener.onForwardOrder(CommandCreatedEventTestFactory.create());
+			listener.onRedirectVorgangOrder(CommandCreatedEventTestFactory.create());
 
 			verify(publisher).publishEvent(any(CommandFailedEvent.class));
 		}
-- 
GitLab


From 45c8b861703472377b2d7a4b7873610e62cbd090 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Thu, 13 Mar 2025 17:25:35 +0100
Subject: [PATCH 10/14] OZG-7501 OZG-7899 Lock after forward

---
 .../redirect/ForwardingEventListener.java        |  9 ++-------
 .../redirect/ForwardingEventListenerTest.java    | 16 ++--------------
 2 files changed, 4 insertions(+), 21 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index 56b8691e8..5462a6675 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -101,19 +101,14 @@ public class ForwardingEventListener {
 	}
 
 	void handleForwardVorgangCommand(Command command) {
+		service.forward(forwardingRequestMapper.fromCommand(command));
 		lockVorgangOnForwarding(command);
-		service.forward(updateVorgangVersion(forwardingRequestMapper.fromCommand(command)));
 		publisher.publishEvent(new VorgangLockedEvent(command));
 	}
 
 	private void lockVorgangOnForwarding(Command command) {
 		var lock = lockMapper.fromCommand(command).toBuilder().reason("Vorgang was forwarded").build();
-		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion());
-	}
-
-	ForwardingRequest updateVorgangVersion(ForwardingRequest request) {
-		var vorgang = vorgangService.getById(request.getVorgangId());
-		return request.toBuilder().version(vorgang.getVersion()).build();
+		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion() + 1);
 	}
 
 	private void handleException(Runnable runnable, String commandId) {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index acb4c3377..7ea1432a9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -146,19 +146,15 @@ class ForwardingEventListenerTest {
 		private final Command command = CommandTestFactory.createBuilder().bodyObject(commandBody()).build();
 		private final Lock lock = LockTestFactory.create();
 		private final ForwardingRequest request = ForwardingRequestTestFactory.create();
-		private final ForwardingRequest updatedRequest = ForwardingRequestTestFactory.createBuilder().version(request.getVersion() + 1).build();
 		@Captor
 		private ArgumentCaptor<Lock> lockCaptor;
 		@Captor
-		private ArgumentCaptor<ForwardingRequest> forwardingRequestCaptor;
-		@Captor
 		private ArgumentCaptor<VorgangLockedEvent> lockedEventCaptor;
 
 		@BeforeEach
 		void init() {
 			when(forwardingRequestMapper.fromCommand(any())).thenReturn(request);
 			when(lockMapper.fromCommand(any())).thenReturn(lock);
-			doReturn(updatedRequest).when(listener).updateVorgangVersion(any());
 		}
 
 		@Test
@@ -172,7 +168,7 @@ class ForwardingEventListenerTest {
 		void shouldLockVorgang() {
 			handleForwardVorgangCommand();
 
-			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION));
+			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION + 1));
 			assertThat(lockCaptor.getValue()).usingRecursiveComparison()
 					.isEqualTo(LockTestFactory.createBuilder().reason("Vorgang was forwarded").build());
 		}
@@ -184,19 +180,11 @@ class ForwardingEventListenerTest {
 			verify(forwardingRequestMapper).fromCommand(command);
 		}
 
-		@Test
-		void shouldUpdateVorgangVersionInRequest() {
-			handleForwardVorgangCommand();
-
-			verify(listener).updateVorgangVersion(request);
-		}
-
 		@Test
 		void shouldCallForwardingService() {
 			handleForwardVorgangCommand();
 
-			verify(forwardingService).forward(forwardingRequestCaptor.capture());
-			assertThat(forwardingRequestCaptor.getValue()).isSameAs(updatedRequest);
+			verify(forwardingService).forward(same(request));
 		}
 
 		@Test
-- 
GitLab


From ccc41c07e68ea5eefd37828353cd909f6216fd89 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Thu, 13 Mar 2025 17:49:22 +0100
Subject: [PATCH 11/14] OZG-7501 OZG-7899 Use MapUtils in mapper

---
 .../vorgang/redirect/ForwardingRequestMapper.java | 15 ++++++++-------
 .../redirect/ForwardingRequestMapperTest.java     |  2 +-
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
index 0da7cd2ac..9f6301389 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
@@ -25,26 +25,27 @@ package de.ozgcloud.vorgang.vorgang.redirect;
 
 import java.util.Map;
 
+import org.apache.commons.collections4.MapUtils;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 
 import de.ozgcloud.command.Command;
 
-@Mapper
+@Mapper(imports = MapUtils.class)
 interface ForwardingRequestMapper {
 
 	@Mapping(target = "version", source = "relationVersion")
 	@Mapping(target = "organisationEinheit", source = "bodyObject")
 	ForwardingRequest fromCommand(Command command);
 
-	@Mapping(target = "id", expression = "java((String) body.get(\"organisationsEinheitId\"))")
-	@Mapping(target = "name", expression = "java((String) body.get(\"name\"))")
+	@Mapping(target = "id", expression = "java(MapUtils.getString(body, \"organisationEinheitId\"))")
+	@Mapping(target = "name", expression = "java(MapUtils.getString(body, \"name\"))")
 	@Mapping(target = "address", source = ".")
 	OrganisationEinheit toOrganisationEinheit(Map<String, Object> body);
 
-	@Mapping(target = "street", expression = "java((String) body.get(\"strasse\"))")
-	@Mapping(target = "houseNumber", expression = "java((String) body.get(\"hausnummer\"))")
-	@Mapping(target = "zipCode", expression = "java((String) body.get(\"plz\"))")
-	@Mapping(target = "city", expression = "java((String) body.get(\"ort\"))")
+	@Mapping(target = "street", expression = "java(MapUtils.getString(body, \"strasse\"))")
+	@Mapping(target = "houseNumber", expression = "java(MapUtils.getString(body, \"hausnummer\"))")
+	@Mapping(target = "zipCode", expression = "java(MapUtils.getString(body, \"plz\"))")
+	@Mapping(target = "city", expression = "java(MapUtils.getString(body, \"ort\"))")
 	Address toAddress(Map<String, Object> body);
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
index 08f42edb7..8708b569d 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
@@ -41,7 +41,7 @@ class ForwardingRequestMapperTest {
 	@Spy
 	private ForwardingRequestMapper mapper = Mappers.getMapper(ForwardingRequestMapper.class);
 	private final Map<String, Object> bodyObject = Map.of(
-			"organisationsEinheitId", OrganisationEinheitTestFactory.ID,
+			"organisationEinheitId", OrganisationEinheitTestFactory.ID,
 			"name", OrganisationEinheitTestFactory.NAME,
 			"strasse", AddressTestFactory.STREET,
 			"hausnummer", AddressTestFactory.HOUSE_NUMBER,
-- 
GitLab


From 136a47f0799e85245b27809685d6031c2af4b5af Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Fri, 14 Mar 2025 11:26:11 +0100
Subject: [PATCH 12/14] OZG-7501 OZG-7899 Create constants for fields in
 command body

---
 .../redirect/ForwardingRequestMapper.java     | 21 +++++++++++++------
 .../redirect/ForwardingRequestMapperTest.java | 13 ++++++------
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
index 9f6301389..e47ae180e 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapper.java
@@ -34,18 +34,27 @@ import de.ozgcloud.command.Command;
 @Mapper(imports = MapUtils.class)
 interface ForwardingRequestMapper {
 
+	interface CommandBodyFields {
+		String ORGANISATION_EINHEIT_ID = "organisationEinheitId";
+		String NAME = "name";
+		String STRASSE = "strasse";
+		String HAUSNUMMER = "hausnummer";
+		String PLZ = "plz";
+		String ORT = "ort";
+	}
+	
 	@Mapping(target = "version", source = "relationVersion")
 	@Mapping(target = "organisationEinheit", source = "bodyObject")
 	ForwardingRequest fromCommand(Command command);
 
-	@Mapping(target = "id", expression = "java(MapUtils.getString(body, \"organisationEinheitId\"))")
-	@Mapping(target = "name", expression = "java(MapUtils.getString(body, \"name\"))")
+	@Mapping(target = "id", expression = "java(MapUtils.getString(body, CommandBodyFields.ORGANISATION_EINHEIT_ID))")
+	@Mapping(target = "name", expression = "java(MapUtils.getString(body, CommandBodyFields.NAME))")
 	@Mapping(target = "address", source = ".")
 	OrganisationEinheit toOrganisationEinheit(Map<String, Object> body);
 
-	@Mapping(target = "street", expression = "java(MapUtils.getString(body, \"strasse\"))")
-	@Mapping(target = "houseNumber", expression = "java(MapUtils.getString(body, \"hausnummer\"))")
-	@Mapping(target = "zipCode", expression = "java(MapUtils.getString(body, \"plz\"))")
-	@Mapping(target = "city", expression = "java(MapUtils.getString(body, \"ort\"))")
+	@Mapping(target = "street", expression = "java(MapUtils.getString(body, CommandBodyFields.STRASSE))")
+	@Mapping(target = "houseNumber", expression = "java(MapUtils.getString(body, CommandBodyFields.HAUSNUMMER))")
+	@Mapping(target = "zipCode", expression = "java(MapUtils.getString(body, CommandBodyFields.PLZ))")
+	@Mapping(target = "city", expression = "java(MapUtils.getString(body, CommandBodyFields.ORT))")
 	Address toAddress(Map<String, Object> body);
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
index 8708b569d..715529e26 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingRequestMapperTest.java
@@ -35,18 +35,19 @@ import org.mapstruct.factory.Mappers;
 import org.mockito.Spy;
 
 import de.ozgcloud.vorgang.command.CommandTestFactory;
+import de.ozgcloud.vorgang.vorgang.redirect.ForwardingRequestMapper.CommandBodyFields;
 
 class ForwardingRequestMapperTest {
 
 	@Spy
 	private ForwardingRequestMapper mapper = Mappers.getMapper(ForwardingRequestMapper.class);
 	private final Map<String, Object> bodyObject = Map.of(
-			"organisationEinheitId", OrganisationEinheitTestFactory.ID,
-			"name", OrganisationEinheitTestFactory.NAME,
-			"strasse", AddressTestFactory.STREET,
-			"hausnummer", AddressTestFactory.HOUSE_NUMBER,
-			"plz", AddressTestFactory.ZIP_CODE,
-			"ort", AddressTestFactory.CITY
+			CommandBodyFields.ORGANISATION_EINHEIT_ID, OrganisationEinheitTestFactory.ID,
+			CommandBodyFields.NAME, OrganisationEinheitTestFactory.NAME,
+			CommandBodyFields.STRASSE, AddressTestFactory.STREET,
+			CommandBodyFields.HAUSNUMMER, AddressTestFactory.HOUSE_NUMBER,
+			CommandBodyFields.PLZ, AddressTestFactory.ZIP_CODE,
+			CommandBodyFields.ORT, AddressTestFactory.CITY
 	);
 
 	@Nested
-- 
GitLab


From 4be80922679aa7fc2e6a3e6b0a22db97d456b918 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Fri, 14 Mar 2025 13:44:23 +0100
Subject: [PATCH 13/14] OZG-7501 OZG-7899 Forward after locking

---
 .../redirect/ForwardingEventListener.java     |  8 +++++--
 .../redirect/ForwardingEventListenerTest.java | 21 ++++++++++++++-----
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
index 5462a6675..7303a7b85 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListener.java
@@ -101,14 +101,18 @@ public class ForwardingEventListener {
 	}
 
 	void handleForwardVorgangCommand(Command command) {
-		service.forward(forwardingRequestMapper.fromCommand(command));
 		lockVorgangOnForwarding(command);
+		service.forward(incrementVersion(forwardingRequestMapper.fromCommand(command)));
 		publisher.publishEvent(new VorgangLockedEvent(command));
 	}
 
 	private void lockVorgangOnForwarding(Command command) {
 		var lock = lockMapper.fromCommand(command).toBuilder().reason("Vorgang was forwarded").build();
-		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion() + 1);
+		vorgangService.lockVorgang(lock, command.getVorgangId(), command.getRelationVersion());
+	}
+
+	private ForwardingRequest incrementVersion(ForwardingRequest request) {
+		return request.toBuilder().version(request.getVersion() + 1).build();
 	}
 
 	private void handleException(Runnable runnable, String commandId) {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 7ea1432a9..6e8e2b676 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -97,7 +97,7 @@ class ForwardingEventListenerTest {
 	@Nested
 	class OnMailSentEvent {
 
-		private Forwarding forwarding = ForwardingTestFactory.create();
+		private final Forwarding forwarding = ForwardingTestFactory.create();
 
 		@Test
 		void shouldCallRedirectService() {
@@ -145,15 +145,16 @@ class ForwardingEventListenerTest {
 
 		private final Command command = CommandTestFactory.createBuilder().bodyObject(commandBody()).build();
 		private final Lock lock = LockTestFactory.create();
-		private final ForwardingRequest request = ForwardingRequestTestFactory.create();
 		@Captor
 		private ArgumentCaptor<Lock> lockCaptor;
 		@Captor
 		private ArgumentCaptor<VorgangLockedEvent> lockedEventCaptor;
+		@Captor
+		private ArgumentCaptor<ForwardingRequest> requestCaptor;
 
 		@BeforeEach
 		void init() {
-			when(forwardingRequestMapper.fromCommand(any())).thenReturn(request);
+			when(forwardingRequestMapper.fromCommand(any())).thenReturn(ForwardingRequestTestFactory.create());
 			when(lockMapper.fromCommand(any())).thenReturn(lock);
 		}
 
@@ -168,7 +169,7 @@ class ForwardingEventListenerTest {
 		void shouldLockVorgang() {
 			handleForwardVorgangCommand();
 
-			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION + 1));
+			verify(vorgangService).lockVorgang(lockCaptor.capture(), eq(VorgangTestFactory.ID), eq(CommandTestFactory.RELATION_VERSION));
 			assertThat(lockCaptor.getValue()).usingRecursiveComparison()
 					.isEqualTo(LockTestFactory.createBuilder().reason("Vorgang was forwarded").build());
 		}
@@ -184,7 +185,17 @@ class ForwardingEventListenerTest {
 		void shouldCallForwardingService() {
 			handleForwardVorgangCommand();
 
-			verify(forwardingService).forward(same(request));
+			verify(forwardingService).forward(requestCaptor.capture());
+			assertThat(requestCaptor.getValue()).usingRecursiveComparison().ignoringFields("version")
+					.isEqualTo(ForwardingRequestTestFactory.create());
+		}
+
+		@Test
+		void shouldIncrementVersionInRequest() {
+			handleForwardVorgangCommand();
+
+			verify(forwardingService).forward(requestCaptor.capture());
+			assertThat(requestCaptor.getValue().getVersion()).isEqualTo(VorgangTestFactory.VERSION + 1);
 		}
 
 		@Test
-- 
GitLab


From 7697ea64d80d643c449cad42c32f220fd2d1c121 Mon Sep 17 00:00:00 2001
From: Krzysztof <krzysztof.witukiewicz@mgm-tp.com>
Date: Fri, 14 Mar 2025 15:36:36 +0100
Subject: [PATCH 14/14] OZG-7501 OZG-7899 Renamings

---
 .../vorgang/vorgang/redirect/ForwardingEventListenerTest.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
index 6e8e2b676..529d4a09a 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/redirect/ForwardingEventListenerTest.java
@@ -159,7 +159,7 @@ class ForwardingEventListenerTest {
 		}
 
 		@Test
-		void shouldMapLock() {
+		void shouldMapToLock() {
 			handleForwardVorgangCommand();
 
 			verify(lockMapper).fromCommand(command);
@@ -175,7 +175,7 @@ class ForwardingEventListenerTest {
 		}
 
 		@Test
-		void shouldMapCommandForwardingRequest() {
+		void shouldMapCommandToForwardingRequest() {
 			handleForwardVorgangCommand();
 
 			verify(forwardingRequestMapper).fromCommand(command);
-- 
GitLab