diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java index 231090b96c06be539ba68fe68213163869d49202..96b2d58709780761d8bbc82baa57bd18d781e928 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java @@ -28,7 +28,7 @@ import lombok.Getter; @Builder @Getter -class Anschrift { +public class Anschrift { private String strasse; private String hausnummer; diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java index aeccb1786c7795171c5a65a07674a5cb36484512..56e5510b8ada0b536e60a9f8e215f5d509124843 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java @@ -30,7 +30,7 @@ import lombok.extern.jackson.Jacksonized; @Builder @Getter @Jacksonized -class OrganisationsEinheit { +public class OrganisationsEinheit { private String id; private XzufiId xzufiId; diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java index 911717902889dfc59197573842a89151a6792c83..bee8310c017f2c8658c917d34f86d2d229720eb3 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java @@ -40,7 +40,7 @@ import lombok.RequiredArgsConstructor; @RestController @RequestMapping(OrganisationsEinheitController.PATH) @RequiredArgsConstructor -class OrganisationsEinheitController { +public class OrganisationsEinheitController { static final String PATH = "/api/organisationseinheits"; // NOSONAR static final String SEARCH_BY_PARAM = "searchBy"; diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java index b62a4788a8fd963365a2e7e3833572917297a816..ab2b3b4c6a2e8e3efcbbcf636cc11ef7946e6f4d 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java @@ -30,7 +30,7 @@ import lombok.Getter; @Builder @Getter -class OrganisationsEinheitHeader { +public class OrganisationsEinheitHeader { @JsonIgnore private String id; diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java index 46db2e9b657a09f9d98f4a25c77d800a07cdba1b..1f288483dc782a92baade909ff64f582c2ae53f9 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java @@ -30,6 +30,7 @@ import de.ozgcloud.alfa.aktenzeichen.AktenzeichenCommandBody; import de.ozgcloud.alfa.bescheid.Bescheid; import de.ozgcloud.alfa.bescheid.BescheidDocumentFromFileBody; import de.ozgcloud.alfa.collaboration.CollaborationCommandBody; +import de.ozgcloud.alfa.forwarding.ForwardVorgangCommandBody; import de.ozgcloud.alfa.forwarding.RedirectRequest; import de.ozgcloud.alfa.kommentar.Kommentar; import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung; @@ -57,7 +58,8 @@ import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage; @Type(value = AktenzeichenCommandBody.class, name = "SET_AKTENZEICHEN"), @Type(value = BescheidDocumentFromFileBody.class, name = "CREATE_BESCHEID_DOCUMENT_FROM_FILE"), @Type(value = CollaborationCommandBody.class, name = "CREATE_COLLABORATION_REQUEST"), - @Type(value = EmptyCommandBody.class, name = "ARCHIVE_VORGANG") + @Type(value = EmptyCommandBody.class, name = "ARCHIVE_VORGANG"), + @Type(value = ForwardVorgangCommandBody.class, name = "FORWARD_VORGANG") }) public interface CommandBody { } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java index 5e97b02673c16a2ada39fd7c79ee931507668d46..16b13bd448c11814c6c41e8db031de579b1d9897 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java @@ -73,6 +73,8 @@ public enum CommandOrder { PROCESS_VORGANG(false, Type.VORGANG), + FORWARD_VORGANG(false, Type.VORGANG), + CREATE_COLLABORATION_REQUEST(false, Type.COLLABORATION), UNBEKANNT(false, Type.NONE); diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandController.java new file mode 100644 index 0000000000000000000000000000000000000000..c9928a5d9a9fb5aef10250ac69e87dd849b79685 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandController.java @@ -0,0 +1,78 @@ +/* + * 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.alfa.forwarding; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import de.ozgcloud.alfa.collaboration.OrganisationsEinheit; +import de.ozgcloud.alfa.collaboration.OrganisationsEinheitController; +import de.ozgcloud.alfa.common.command.CommandController; +import de.ozgcloud.alfa.common.command.CommandService; +import de.ozgcloud.alfa.common.command.CreateCommand; +import de.ozgcloud.common.errorhandling.TechnicalException; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping(ForwardByVorgangCommandController.PATH) +@RequiredArgsConstructor +class ForwardByVorgangCommandController { + static final String PATH = "/api/vorgangs/{vorgangId}/{vorgangVersion}/forwarding"; + + private final CommandService commandService; + private final OrganisationsEinheitController organisationsEinheitController; + + @PostMapping + public ResponseEntity<Void> createCommand(@PathVariable String vorgangId, @PathVariable long vorgangVersion, @RequestBody CreateCommand command) { + var body = (ForwardVorgangCommandBody) command.getBody(); + var enrichedCommand = command.toBuilder() + .vorgangId(vorgangId) + .relationId(vorgangId) + .body(addOrganisationsEinheitData(getOrganisationsEinheitById(body.getOrganisationsEinheitId()), body)) + .build(); + var created = commandService.createCommand(enrichedCommand, vorgangVersion); + return ResponseEntity.created(linkTo(CommandController.class).slash(created.getId()).toUri()).build(); + } + + private OrganisationsEinheit getOrganisationsEinheitById(String id) { + var response = organisationsEinheitController.getById(id); + if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null) { + throw new TechnicalException("Could not get Organisationseinheit by id: " + id); + } + return response.getBody().getContent(); + } + + private ForwardVorgangCommandBody addOrganisationsEinheitData(OrganisationsEinheit organisationsEinheit, ForwardVorgangCommandBody body) { + return body.toBuilder() + .name(organisationsEinheit.getName()) + .anschrift(organisationsEinheit.getAnschrift()) + .build(); + } +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBody.java b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBody.java new file mode 100644 index 0000000000000000000000000000000000000000..14c6d31e0e3f116481ad4fcb40dda6adf66c15b7 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBody.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.alfa.forwarding; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import de.ozgcloud.alfa.collaboration.Anschrift; +import de.ozgcloud.alfa.common.LinkedResourceDeserializer; +import de.ozgcloud.alfa.common.command.CommandBody; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +public class ForwardVorgangCommandBody implements CommandBody { + + @JsonDeserialize(using = LinkedResourceDeserializer.class) + private String organisationsEinheitId; + + private String name; + private Anschrift anschrift; +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/CreateForwardVorgangCommandTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/CreateForwardVorgangCommandTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..077816660e80ee50cc565e12efcc0c6215071f66 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/CreateForwardVorgangCommandTestFactory.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.alfa.forwarding; + +import de.ozgcloud.alfa.common.command.CommandOrder; +import de.ozgcloud.alfa.common.command.CreateCommand; +import de.ozgcloud.alfa.common.command.CreateCommand.CreateCommandBuilder; +import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; + +class CreateForwardVorgangCommandTestFactory { + + static CreateCommand create() { + return createBuilder().build(); + } + + static CreateCommandBuilder createBuilder() { + return CreateCommand.builder() + .order(CommandOrder.FORWARD_VORGANG.name()) + .vorgangId(VorgangHeaderTestFactory.ID) + .relationId(VorgangHeaderTestFactory.ID) + .body(ForwardVorgangCommandBodyTestFactory.create()); + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..196916013cc0773203ec71b28db595a4b0bce594 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardByVorgangCommandControllerTest.java @@ -0,0 +1,163 @@ +/* + * 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.alfa.forwarding; + +import static de.ozgcloud.alfa.common.command.CommandController.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +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.mockito.Spy; +import org.springframework.hateoas.EntityModel; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import de.ozgcloud.alfa.collaboration.OrganisationsEinheitController; +import de.ozgcloud.alfa.collaboration.OrganisationsEinheitTestFactory; +import de.ozgcloud.alfa.common.command.CommandOrder; +import de.ozgcloud.alfa.common.command.CommandService; +import de.ozgcloud.alfa.common.command.CommandTestFactory; +import de.ozgcloud.alfa.common.command.CreateCommand; +import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; +import de.ozgcloud.common.errorhandling.TechnicalException; +import lombok.SneakyThrows; + +class ForwardByVorgangCommandControllerTest { + + @Mock + private CommandService commandService; + @Mock + private OrganisationsEinheitController organisationsEinheitController; + @Spy + @InjectMocks + private ForwardByVorgangCommandController controller; + + private MockMvc mockMvc; + + @BeforeEach + void init() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Nested + class TestCreateCommand { + + @Nested + class OnOrganisationsEinheitAvailable { + + @Captor + private ArgumentCaptor<CreateCommand> commandCaptor; + + @BeforeEach + void init() { + when(organisationsEinheitController.getById(any())).thenReturn( + new ResponseEntity<>(EntityModel.of(OrganisationsEinheitTestFactory.create()), HttpStatus.OK)); + when(commandService.createCommand(any(), anyLong())).thenReturn(CommandTestFactory.create()); + } + + @Test + void shouldCallOrganisationsEinheitController() { + doRequest(); + + verify(organisationsEinheitController).getById(OrganisationsEinheitTestFactory.ID); + } + + @Test + void shouldCallCommandService() { + doRequest(); + + verify(commandService).createCommand(commandCaptor.capture(), eq(VorgangHeaderTestFactory.VERSION)); + assertThat(commandCaptor.getValue()).usingRecursiveComparison().isEqualTo(CreateForwardVorgangCommandTestFactory.create()); + } + + @SneakyThrows + @Test + void shouldReturnCreated() { + var response = doRequest(); + + response.andExpect(status().isCreated()); + } + + @SneakyThrows + @Test + void shouldReturnLinkToCreatedCommand() { + var response = doRequest(); + + response.andExpect(header().stringValues("location", "http://localhost" + COMMANDS_PATH + "/" + CommandTestFactory.ID)); + } + } + + @Nested + class OnOrganisationsEinheitMissing { + + @SneakyThrows + @Test + void shouldThrowExceptionIfNotFound() { + when(organisationsEinheitController.getById(OrganisationsEinheitTestFactory.ID)) + .thenReturn(new ResponseEntity<>(HttpStatus.NOT_FOUND)); + + assertTechnicalExceptionThrown(); + } + + @SneakyThrows + @Test + void shouldThrowExceptionIfBodyIsEmpty() { + when(organisationsEinheitController.getById(OrganisationsEinheitTestFactory.ID)) + .thenReturn(new ResponseEntity<>(null, HttpStatus.OK)); + + assertTechnicalExceptionThrown(); + } + + private void assertTechnicalExceptionThrown() { + assertThatThrownBy(() -> doRequest()).rootCause().isInstanceOf(TechnicalException.class) + .hasMessageStartingWith("Could not get Organisationseinheit by id: %s", OrganisationsEinheitTestFactory.ID); + } + } + + @SneakyThrows + private ResultActions doRequest() { + return mockMvc.perform(post(ForwardByVorgangCommandController.PATH, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION) + .contentType(MediaType.APPLICATION_JSON) + .content(createContent())); + } + + private String createContent() { + return CommandTestFactory.buildCreateCommandWithBodyContent( + CommandOrder.FORWARD_VORGANG, + "{\"organisationsEinheitId\":\"%s\"}".formatted(OrganisationsEinheitTestFactory.ID)); + } + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBodyTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBodyTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ac8f4a4d34f56639ace3aa31e26a40eee693d6ab --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardVorgangCommandBodyTestFactory.java @@ -0,0 +1,41 @@ +/* + * 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.alfa.forwarding; + +import de.ozgcloud.alfa.collaboration.OrganisationsEinheitTestFactory; +import de.ozgcloud.alfa.forwarding.ForwardVorgangCommandBody.ForwardVorgangCommandBodyBuilder; + +class ForwardVorgangCommandBodyTestFactory { + + static ForwardVorgangCommandBody create() { + return createBuilder().build(); + } + + static ForwardVorgangCommandBodyBuilder createBuilder() { + return ForwardVorgangCommandBody.builder() + .organisationsEinheitId(OrganisationsEinheitTestFactory.ID) + .name(OrganisationsEinheitTestFactory.NAME) + .anschrift(OrganisationsEinheitTestFactory.ANSCHRIFT); + } +}