diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java index b3e75f0cd900dd24d9095c7953939ae450d5db5c..4d6d7a40ef312dc1f78f5c74721055e7b164f577 100644 --- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java +++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapter.java @@ -8,6 +8,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -17,11 +19,12 @@ import org.springframework.stereotype.Component; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormHeader; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.ServiceKonto; import de.ozgcloud.eingang.common.formdata.ZustaendigeStelle; -import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import de.ozgcloud.eingang.semantik.common.ServiceKontoFactory; +import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; @@ -35,6 +38,10 @@ public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSema private static final String KEY_FACHNACHRICHT = "Fachnachricht"; private static final String KEY_POSTFACH_ID = "InboxReference"; private static final String KEY_ORGANISATIONS_EINHEIT_ID = "MetaText1"; + private static final String KEY_FORM_NAME = "Title"; + private static final String KEY_FORM_ID = "ProjectTitle"; + + static final String DEFAULT_FORM_NAME = "dFördermittelantrag: Ohne Titel"; @Autowired private ServiceKontoFactory serviceKontoFactory; @@ -48,27 +55,49 @@ public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSema } FormData processFachnachricht(FormData formData) { - @SuppressWarnings("unchecked") - Map<String, Object> fachnachricht = (Map<String, Object>) MapUtils.getMap(formData.getFormData(), KEY_FACHNACHRICHT, - Collections.<String, Object>emptyMap()); + return pipe( + Stream.of( + this::addFormName, + this::addFormEngineName, + this::addServiceKonto, + this::addOrganisationsEinheitId, + this::addFormId + ) + ).apply(formData); + } + + private UnaryOperator<FormData> pipe(Stream<UnaryOperator<FormData>> functions) { + return (formData) -> functions + .reduce(formData, (acc, f) -> f.apply(acc), (a, b) -> a); + } + + FormData addFormId(FormData formData) { + return getNonEmptyFachnachrichtValueByKey(formData, KEY_FORM_ID) + .map(formId -> mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.formId(formId))) + .orElse(formData); + } - var extendedFormData = addFormName(formData); - extendedFormData = addFormEngineName(extendedFormData); - extendedFormData = addServiceKonto(extendedFormData, fachnachricht); - return addOrganisationsEinheitId(extendedFormData, fachnachricht); + private Optional<String> getNonEmptyFachnachrichtValueByKey(FormData formData, String key) { + return Optional.ofNullable((String) getFachnachricht(formData).get(key)) + .filter(StringUtils::isNotBlank); } - FormData addServiceKonto(FormData formData, Map<String, Object> fachnachricht) { - return Optional.ofNullable((String) fachnachricht.get(KEY_POSTFACH_ID)) + private FormData mapWithModifiedHeader(FormData formData, UnaryOperator<FormHeader.FormHeaderBuilder> headerBuilderOperator) { + return formData.toBuilder() + .header(headerBuilderOperator.apply(formData.getHeader().toBuilder()).build()) + .build(); + } + + FormData addServiceKonto(FormData formData) { + return Optional.ofNullable((String) getFachnachricht(formData).get(KEY_POSTFACH_ID)) .map(this::extractPrefix) .map(this::createServiceKonto) - .map(serviceKonto -> formData.getHeader().toBuilder().serviceKonto(serviceKonto).build()) - .map(header -> formData.toBuilder().header(header).build()) + .map(serviceKonto -> mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.serviceKonto(serviceKonto))) .orElse(formData); } - FormData addOrganisationsEinheitId(FormData formData, Map<String, Object> fachnachricht) { - return Optional.ofNullable((String) fachnachricht.get(KEY_ORGANISATIONS_EINHEIT_ID)) + FormData addOrganisationsEinheitId(FormData formData) { + return Optional.ofNullable((String) getFachnachricht(formData).get(KEY_ORGANISATIONS_EINHEIT_ID)) .map(orgaId -> addOrganisationsEinheitId(orgaId, formData.getZustaendigeStelle())) .map(zustStelle -> formData.toBuilder().zustaendigeStelle(zustStelle).build()) .orElse(formData); @@ -86,22 +115,19 @@ public class DFoerdermittelEngineBasedSemantikAdapter implements EngineBasedSema } FormData addFormName(FormData formData) { - return formData.toBuilder() - .header(formData.getHeader().toBuilder() - // TODO replace formName with actual name <Title> from Fachnachricht (KOP-2239) - .formName("dFördermittelantrag") - .build() - ) - .build(); + return mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.formName( + getNonEmptyFachnachrichtValueByKey(formData, KEY_FORM_NAME) + .orElse(DEFAULT_FORM_NAME) + )); + } + + @SuppressWarnings("unchecked") + private Map<String, Object> getFachnachricht(FormData formData) { + return (Map<String, Object>) MapUtils.getMap(formData.getFormData(), KEY_FACHNACHRICHT, Collections.<String, Object>emptyMap()); } FormData addFormEngineName(FormData formData) { - return formData.toBuilder() - .header(formData.getHeader().toBuilder() - .formEngineName("dFördermittelantrag") - .build() - ) - .build(); + return mapWithModifiedHeader(formData, headerBuilder -> headerBuilder.formEngineName("dFördermittelantrag")); } String extractPrefix(@NonNull String postfachId) { diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java index 05473793842bc54d734988d7cf1ad872d5789b7a..110e80b7d0a2f055a9624458e3ae15594ef87d86 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelEngineBasedSemantikAdapterTest.java @@ -1,5 +1,7 @@ package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; +import static de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel.DFoerdermittelEngineBasedSemantikAdapter.*; +import static de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel.DFoerdermittelFormDataTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.InstanceOfAssertFactories.*; import static org.mockito.ArgumentMatchers.*; @@ -9,6 +11,7 @@ import java.util.Collections; import java.util.Map; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -19,6 +22,7 @@ import de.ozgcloud.common.binaryfile.TempFileUtils; import de.ozgcloud.common.test.TestUtils; import de.ozgcloud.eingang.common.formdata.FormData; import de.ozgcloud.eingang.common.formdata.FormDataTestFactory; +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; import de.ozgcloud.eingang.common.formdata.IncomingFile; import de.ozgcloud.eingang.common.formdata.PostfachAddressTestFactory; import de.ozgcloud.eingang.common.formdata.ServiceKontoTestFactory; @@ -150,22 +154,23 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { @Mock FormData formData4; + @Mock + FormData formData5; + @BeforeEach void mock() { - var formData = DFoerdermittelFormDataTestFactory.create(); - var fachnachrichtMap = DFoerdermittelFormDataTestFactory.createFachnachrichtMap(); - when(formData0.getFormData()).thenReturn(formData.getFormData()); doReturn(formData1).when(adapter).addFormName(formData0); doReturn(formData2).when(adapter).addFormEngineName(formData1); - doReturn(formData3).when(adapter).addServiceKonto(formData2, fachnachrichtMap); - doReturn(formData4).when(adapter).addOrganisationsEinheitId(formData3, fachnachrichtMap); + doReturn(formData3).when(adapter).addServiceKonto(formData2); + doReturn(formData4).when(adapter).addOrganisationsEinheitId(formData3); + doReturn(formData5).when(adapter).addFormId(formData4); } @Test void shouldReturn() { var processedFormData = adapter.processFachnachricht(formData0); - assertThat(processedFormData).isEqualTo(formData4); + assertThat(processedFormData).isEqualTo(formData5); } } @@ -179,8 +184,7 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { @Test void shouldHaveServiceKonto() { - var formData = adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), - DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); + var formData = adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create()); assertThat(formData.getHeader().getServiceKonto().getPostfachAddresses().get(0).getIdentifier()) .asInstanceOf(type(StringBasedIdentifier.class)).extracting(StringBasedIdentifier::getPostfachId) @@ -189,7 +193,7 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { @Test void shouldRemovePrefix() { - adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create(), DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); + adapter.addServiceKonto(DFoerdermittelFormDataTestFactory.create()); verify(serviceKontoFactory).buildOsiServiceKonto(DFoerdermittelFormDataTestFactory.POSTFACH_ID); } @@ -216,22 +220,76 @@ class DFoerdermittelEngineBasedSemantikAdapterTest { class TestAddOrganisationsEinheitId { @Test void shouldHaveOrganisationsEinheitId() { - var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create(), - DFoerdermittelFormDataTestFactory.createFachnachrichtMap()); + var formData = adapter.addOrganisationsEinheitId(DFoerdermittelFormDataTestFactory.create()); assertThat(formData.getZustaendigeStelle()).isNotNull().extracting(ZustaendigeStelle::getOrganisationseinheitenId) - .isEqualTo(DFoerdermittelFormDataTestFactory.ORGANISATIONS_EINHEIT_ID); + .isEqualTo(ORGANISATIONS_EINHEIT_ID); } } @Nested class TestAddFormName { + @DisplayName("should have form name from title") + @Test + void shouldHaveFormNameFromTitle() { + var formData = adapter.addFormName(createFormDataWithTitle(FORM_NAME)); + + assertThat(formData.getHeader().getFormName()).isEqualTo(FORM_NAME); + } + + @DisplayName("should have default form name for empty title") + @Test + void shouldHaveDefaultFormNameForEmptyTitle() { + var formData = adapter.addFormName(createFormDataWithTitle("")); + + assertThat(formData.getHeader().getFormName()).isEqualTo(DEFAULT_FORM_NAME); + } + + @DisplayName("should have default form name for missing title") + @Test + void shouldHaveDefaultFormNameForMissingTitle() { + var formData = adapter.addFormName(createFormDataWithTitle(null)); + + assertThat(formData.getHeader().getFormName()).isEqualTo(DEFAULT_FORM_NAME); + } + + FormData createFormDataWithTitle(String title) { + return createFachnachrichtBuilder().title(title).build().createFormData(); + } + + } + + @DisplayName("add form id") + @Nested + class TestAddFormId { + + @DisplayName("should get form id from project title") @Test - void shouldHaveFormName() { - var formData = adapter.addFormName(DFoerdermittelFormDataTestFactory.create()); + void shouldGetFormIdFromProjectTitle() { + var formData = adapter.addFormId(createFormDataWithProjectTitle(FORM_ID)); + + assertThat(formData.getHeader().getFormId()).isEqualTo(FORM_ID); + } + + @DisplayName("should keep form id if project title is empty") + @Test + void shouldKeepFormIdIfProjectTitleIsEmpty() { + var formData = adapter.addFormId(createFormDataWithProjectTitle("")); + + assertThat(formData.getHeader().getFormId()).isEqualTo(FormHeaderTestFactory.FORM_ID); + } + + @DisplayName("should keep form id if project title is null") + @Test + void shouldKeepFormIdIfProjectTitleIsNull() { + var formData = adapter.addFormId(createFormDataWithProjectTitle(null)); + + assertThat(formData.getHeader().getFormId()).isEqualTo(FormHeaderTestFactory.FORM_ID); + } - assertThat(formData.getHeader().getFormName()).isEqualTo("dFördermittelantrag"); + FormData createFormDataWithProjectTitle(String projectTitle) { + return createFachnachrichtBuilder().projectTitle(projectTitle).build().createFormData(); } } diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java index b99c66e48559d39b5c58e747c145a58dc0490363..8b8c9bf4103b13f085a7910361925a11e7b90297 100644 --- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java +++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/dfoerdermittel/DFoerdermittelFormDataTestFactory.java @@ -1,25 +1,74 @@ package de.ozgcloud.eingang.semantik.enginebased.dfoerdermittel; +import static java.util.stream.Collectors.*; + import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.IntStream; import de.ozgcloud.eingang.common.formdata.FormData; +import de.ozgcloud.eingang.common.formdata.FormHeaderTestFactory; +import lombok.Builder; class DFoerdermittelFormDataTestFactory { + static final String FORM_NAME = "Name of form"; + static final String FORM_ID = "Wert von ProjectTitle"; static final String POSTFACH_ID = "4dd01647-b9d9-4775-1b50-08da3d83800a"; static final String ORGANISATIONS_EINHEIT_ID = "9795669"; + static Fachnachricht.FachnachrichtBuilder createFachnachrichtBuilder() { + return Fachnachricht.builder() + .title(FORM_NAME) + .projectTitle(FORM_ID) + .postfachId(POSTFACH_ID) + .organisationsEinheitId(ORGANISATIONS_EINHEIT_ID); + } + static FormData create() { return createBuilder().build(); } static FormData.FormDataBuilder createBuilder() { + return createBuilderWithFachnachricht(createFachnachrichtBuilder().build()); + } + + static FormData.FormDataBuilder createBuilderWithFachnachricht(Fachnachricht fachnachricht) { return FormData.builder() - .formData(Map.of("Fachnachricht", createFachnachrichtMap())); + .header(FormHeaderTestFactory.create()) + .formData(Map.of("Fachnachricht", createFachnachrichtMapWithFachnachricht(fachnachricht))); } static Map<String, Object> createFachnachrichtMap() { - return Map.of("InboxReference", "sh/sh/4dd01647-b9d9-4775-1b50-08da3d83800a", - "MetaText1", ORGANISATIONS_EINHEIT_ID); + return createFachnachrichtMapWithFachnachricht(createFachnachrichtBuilder().build()); + } + + static Map<String, Object> createFachnachrichtMapWithFachnachricht(Fachnachricht fachnachricht) { + return createMapWithValueFilter( + Objects::nonNull, + "Title", fachnachricht.title(), + "ProjectTitle", fachnachricht.projectTitle(), + "InboxReference", "sh/sh/" + fachnachricht.postfachId(), + "MetaText1", fachnachricht.organisationsEinheitId() + ); + } + + private static Map<String, Object> createMapWithValueFilter(Predicate<String> valuePredicate, String... keyValuePairs) { + if (keyValuePairs.length % 2 != 0) { + throw new IllegalArgumentException("Array length must be even to form key-value pairs."); + } + + return IntStream.range(0, keyValuePairs.length / 2) + .boxed() + .filter(i -> valuePredicate.test(keyValuePairs[2 * i + 1])) + .collect(toMap(i -> keyValuePairs[2 * i], i -> keyValuePairs[2 * i + 1])); + } + + @Builder + record Fachnachricht(String title, String projectTitle, String postfachId, String organisationsEinheitId) { + FormData createFormData() { + return createBuilderWithFachnachricht(this).build(); + } } }