From c87bb142a49f61a15987d2f065cd69bc621263fa Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 17 Apr 2025 20:16:49 +0200 Subject: [PATCH 01/41] Add Customer Profile module and configuration files --- pom.xml | 1 + .../customer-profile-core/pom.xml | 25 +++++++++++++ .../CustomerProfileConfiguration.java | 5 +++ stream-customer-profile/pom.xml | 19 ++++++++++ stream-dbs-clients/pom.xml | 36 +++++++++++++++++++ 5 files changed, 86 insertions(+) create mode 100644 stream-customer-profile/customer-profile-core/pom.xml create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java create mode 100644 stream-customer-profile/pom.xml diff --git a/pom.xml b/pom.xml index 55d320100..a81cb206d 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ stream-audiences stream-compositions stream-plan-manager + stream-customer-profile diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml new file mode 100644 index 000000000..d8cd380af --- /dev/null +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + + com.backbase.stream + stream-customer-profile + 6.17.0 + + + customer-profile-core + jar + Stream :: Customer Profile Core + + + true + + + + + + + \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java new file mode 100644 index 000000000..7fc318a36 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java @@ -0,0 +1,5 @@ +package com.backbase.stream.configuration; + +public class CustomerProfileConfiguration { + +} diff --git a/stream-customer-profile/pom.xml b/stream-customer-profile/pom.xml new file mode 100644 index 000000000..9a872d5db --- /dev/null +++ b/stream-customer-profile/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + + + com.backbase.stream + stream-services + 6.17.0 + + + stream-customer-profile + + pom + Stream :: Customer Profile + + + customer-profile-core + + diff --git a/stream-dbs-clients/pom.xml b/stream-dbs-clients/pom.xml index c38fce4ee..c42fc5e23 100644 --- a/stream-dbs-clients/pom.xml +++ b/stream-dbs-clients/pom.xml @@ -218,6 +218,16 @@ ${project.build.directory}/yaml true + + com.backbase.flow.customer-profile.api + customer-profile + 1.17.1 + + api + zip + ${project.build.directory}/yaml + true + **/*.yaml, **/*.json @@ -482,6 +492,32 @@ com.backbase.tailoredvalue.planmanager.service.api.v1.model + + generate-customer-profile-integration-api-code + + generate-webclient-embedded + + generate-sources + + REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true + ${project.build.directory}/yaml/customer-profile/customer-profile-integration-api-v*.yaml + com.backbase.customerprofile.api.integration.v1 + com.backbase.customerprofile.api.integration.v1.model + + + + generate-customer-profile-service-api-code + + generate-webclient-embedded + + generate-sources + + REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true + ${project.build.directory}/yaml/customer-profile/customer-profile-service-api-v*.yaml + com.backbase.customerprofile.api.service.v1 + com.backbase.customerprofile.api.service.v1.model + + From 6e4cff9af1b8b61f60fc2bf93eb1df7f6e0f6efb Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 18 Apr 2025 17:03:09 +0200 Subject: [PATCH 02/41] Add Customer Profile client configuration --- .../CustomerProfileConfiguration.java | 5 -- .../DbsApiClientsAutoConfiguration.java | 4 +- .../config/CustomerProfileClientConfig.java | 67 +++++++++++++++++++ 3 files changed, 70 insertions(+), 6 deletions(-) delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java create mode 100644 stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java deleted file mode 100644 index 7fc318a36..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com.backbase.stream/configuration/CustomerProfileConfiguration.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.backbase.stream.configuration; - -public class CustomerProfileConfiguration { - -} diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/autoconfigure/DbsApiClientsAutoConfiguration.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/autoconfigure/DbsApiClientsAutoConfiguration.java index 2547408b9..e2e23b076 100644 --- a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/autoconfigure/DbsApiClientsAutoConfiguration.java +++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/autoconfigure/DbsApiClientsAutoConfiguration.java @@ -4,6 +4,7 @@ import com.backbase.stream.clients.config.ApprovalClientConfig; import com.backbase.stream.clients.config.ArrangementManagerClientConfig; import com.backbase.stream.clients.config.ContactManagerClientConfig; +import com.backbase.stream.clients.config.CustomerProfileClientConfig; import com.backbase.stream.clients.config.IdentityIntegrationClientConfig; import com.backbase.stream.clients.config.InstrumentApiConfiguration; import com.backbase.stream.clients.config.LimitsClientConfig; @@ -42,7 +43,8 @@ UserProfileManagerClientConfig.class, InstrumentApiConfiguration.class, PortfolioApiConfiguration.class, - PlanManagerClientConfig.class + PlanManagerClientConfig.class, + CustomerProfileClientConfig.class }) @EnableConfigurationProperties public class DbsApiClientsAutoConfiguration { diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java new file mode 100644 index 000000000..5246e51b4 --- /dev/null +++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java @@ -0,0 +1,67 @@ +package com.backbase.stream.clients.config; + + +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; +import com.backbase.customerprofile.api.service.ApiClient; +import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; +import com.backbase.customerprofile.api.service.v1.PartyManagementServiceApi; +import com.backbase.customerprofile.api.service.v1.PartyRelationshipsManagementServiceApi; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.text.DateFormat; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties("backbase.communication.services.customer-profile") +public class CustomerProfileClientConfig extends CompositeApiClientConfig { + + public static final String CUSTOMER_PROFILE_SERVICE_ID = "customer-profile"; + + public CustomerProfileClientConfig() { + super(CUSTOMER_PROFILE_SERVICE_ID); + } + + @Bean + @ConditionalOnMissingBean + public ApiClient customerProfileApiClient(ObjectMapper objectMapper, DateFormat dateFormat) { + return new ApiClient(getWebClient(), objectMapper, dateFormat).setBasePath(createBasePath()); + } + + @Bean + @ConditionalOnMissingBean + public com.backbase.customerprofile.api.integration.ApiClient customerProfileApiIntegrationClient( + ObjectMapper objectMapper, DateFormat dateFormat) { + return new com.backbase.customerprofile.api.integration.ApiClient(getWebClient(), objectMapper, dateFormat) + .setBasePath(createBasePath()); + } + + @Bean + @ConditionalOnMissingBean + public CustomerManagementServiceApi customerManagementServiceApi(ApiClient customerProfileApiClient) { + return new CustomerManagementServiceApi(customerProfileApiClient); + } + + @Bean + @ConditionalOnMissingBean + public PartyManagementServiceApi partyManagementServiceApi(ApiClient customerProfileApiClient) { + return new PartyManagementServiceApi(customerProfileApiClient); + } + + @Bean + @ConditionalOnMissingBean + public PartyRelationshipsManagementServiceApi partyRelationshipsManagementServiceApi( + ApiClient customerProfileApiClient) { + return new PartyRelationshipsManagementServiceApi(customerProfileApiClient); + } + + @Bean + @ConditionalOnMissingBean + public PartyManagementIntegrationApi partyManagementIntegrationApi( + com.backbase.customerprofile.api.integration.ApiClient customerProfileApiIntegrationClient) { + return new PartyManagementIntegrationApi(customerProfileApiIntegrationClient); + } + + +} From d37f812329c7fc6f4215482f6d6958fbe878b8c7 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 22 Apr 2025 11:45:47 +0200 Subject: [PATCH 03/41] Add CustomerProfileService and corresponding tests --- .../customer-profile-core/pom.xml | 27 +++++ .../service/CustomerProfileService.java | 31 ++++++ .../service/CustomerProfileServiceTest.java | 98 +++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java create mode 100644 stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml index d8cd380af..e7800c0fa 100644 --- a/stream-customer-profile/customer-profile-core/pom.xml +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -20,6 +20,33 @@ + + com.backbase.stream + stream-dbs-clients + 6.17.0 + compile + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-junit-jupiter + test + + + com.navercorp.fixturemonkey + fixture-monkey-starter + 1.1.11 + test + + + io.projectreactor + reactor-test + test + \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java new file mode 100644 index 000000000..5ee6752ca --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -0,0 +1,31 @@ +package com.backbase.stream.service; + +import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; +import com.backbase.customerprofile.api.service.v1.model.CustomerCreationRequestDto; +import com.backbase.customerprofile.api.service.v1.model.CustomerResponseDto; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; + +@Slf4j +@RequiredArgsConstructor +public class CustomerProfileService { + + @NonNull + private final CustomerManagementServiceApi customerManagementServiceApi; + + public Mono createCustomer(CustomerCreationRequestDto customerCreationRequestDto) + throws WebClientResponseException { + return customerManagementServiceApi.createCustomer(customerCreationRequestDto) + .doOnError(WebClientResponseException.class, e -> { + log.error("Error creating customer profile: {}", e.getMessage()); + throw e; + }) + .doOnSuccess(customerResponseDto -> + log.info("Customer profile created successfully: {}", customerResponseDto)); + + } + +} diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java new file mode 100644 index 000000000..ec417e6b6 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -0,0 +1,98 @@ +package com.backbase.stream.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; +import com.backbase.customerprofile.api.service.v1.model.CustomerCreationRequestDto; +import com.backbase.customerprofile.api.service.v1.model.CustomerResponseDto; +import com.navercorp.fixturemonkey.FixtureMonkey; +import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@ExtendWith(MockitoExtension.class) +class CustomerProfileServiceTest { + + private CustomerProfileService customerProfileService; + + private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) + .build(); + @Mock + private CustomerManagementServiceApi customerManagementServiceApiMock; + + + @BeforeEach + void setup() { + customerProfileService = new CustomerProfileService(customerManagementServiceApiMock); + } + + @Test + @DisplayName("createCustomer should return CustomerResponseDto when API call is successful") + void createCustomer_success() { + var legalEntityId = UUID.randomUUID().toString(); + var requestDto = fixtureMonkey.giveMeBuilder(CustomerCreationRequestDto.class) + .set("legalEntityId", legalEntityId) + .sample(); + var expectedResponseDto = fixtureMonkey.giveMeBuilder(CustomerResponseDto.class) + .set("legalEntityId", legalEntityId).sample(); + + when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + .thenReturn(Mono.just(expectedResponseDto)); + + var result = customerProfileService.createCustomer(requestDto); + + StepVerifier.create(result) + .assertNext(response -> { + assertEquals(expectedResponseDto.getLegalEntityId(), response.getLegalEntityId()); + }) + .verifyComplete(); + } + + @Test + @DisplayName("createCustomer should propagate WebClientResponseException when API call fails") + void createCustomer_apiError() { + var requestDto = fixtureMonkey.giveMeOne(CustomerCreationRequestDto.class); + var expectedException = new WebClientResponseException( + HttpStatus.BAD_REQUEST.value(), + "Bad Request from API", + null, + null, + StandardCharsets.UTF_8); + when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + .thenReturn(Mono.error(expectedException)); + var result = customerProfileService.createCustomer(requestDto); + StepVerifier.create(result) + .expectErrorMatches(throwable -> + throwable instanceof WebClientResponseException && + ((WebClientResponseException) throwable).getStatusCode() == HttpStatus.BAD_REQUEST && + throwable.getMessage().contains("Bad Request from API") + ) + .verify(); + } + + @Test + @DisplayName("createCustomer should propagate other RuntimeExceptions when API call fails unexpectedly") + void createCustomer_otherError() { + var requestDto = fixtureMonkey.giveMeOne(CustomerCreationRequestDto.class); + var expectedException = new RuntimeException("Unexpected error"); + when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + .thenReturn(Mono.error(expectedException)); + var result = customerProfileService.createCustomer(requestDto); + StepVerifier.create(result) + .expectErrorMatches(throwable -> throwable == expectedException) + .verify(); + } +} From f5bd68a4822c33b05c6c4bff62428215f44a94ec Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 22 Apr 2025 11:59:05 +0200 Subject: [PATCH 04/41] Add tests for CustomerProfileClientConfig to validate base path configurations --- .../config/CompositeApiClientConfigTest.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/stream-dbs-clients/src/test/java/com/backbase/stream/clients/config/CompositeApiClientConfigTest.java b/stream-dbs-clients/src/test/java/com/backbase/stream/clients/config/CompositeApiClientConfigTest.java index 2cbb80637..213c5a923 100644 --- a/stream-dbs-clients/src/test/java/com/backbase/stream/clients/config/CompositeApiClientConfigTest.java +++ b/stream-dbs-clients/src/test/java/com/backbase/stream/clients/config/CompositeApiClientConfigTest.java @@ -98,5 +98,72 @@ void shouldReturnDefaultServicePortWhenServicePortIsEmptyTest() { assertEquals("http://user-profile-manager:8181", config.createBasePath()); }); } + @Test + void shouldReturnServiceIdWhenCustomerProfileWithLoadBalancerTest() { + contextRunner + .withBean(Factory.class, () -> loadBalancerFactory) + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withUserConfiguration(CustomerProfileClientConfig.class) + .run(context -> { + var config = context.getBean(CustomerProfileClientConfig.class); + assertEquals("http://customer-profile", config.createBasePath()); + }); + } + + @Test + void shouldReturnDirectUriWhenCustomerProfileWithoutLoadBalancerAndWithDirectUriTest() { + contextRunner + .withPropertyValues("backbase.communication.services.customer-profile.direct-uri=http://custom-profile-uri/api") + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withBean(CustomerProfileClientConfig.class) + .run(context -> { + var config = context.getBean(CustomerProfileClientConfig.class); + assertEquals("http://custom-profile-uri/api", config.createBasePath()); + }); + } + + @Test + void shouldReturnServiceIdWhenCustomerProfileWithLoadBalancerAndWithDirectUriTest() { + contextRunner + .withPropertyValues("backbase.communication.services.customer-profile.direct-uri=http://custom-profile-uri/api") + .withBean(Factory.class, () -> loadBalancerFactory) + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withUserConfiguration(CustomerProfileClientConfig.class) + .run(context -> { + var config = context.getBean(CustomerProfileClientConfig.class); + assertEquals("http://customer-profile", config.createBasePath()); + }); + } + + @Test + void shouldNotReturnDefaultServicePortWhenCustomerProfileServicePortIsSetTest() { + contextRunner + .withPropertyValues("backbase.communication.http.default-service-port=8181", + "backbase.communication.services.customer-profile.service-port=8080") + .withBean(Factory.class, () -> loadBalancerFactory) + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withUserConfiguration(CustomerProfileClientConfig.class) + .run(context -> { + var config = context.getBean(CustomerProfileClientConfig.class); + assertEquals("http://customer-profile:8080", config.createBasePath()); + }); + } + + @Test + void shouldReturnDefaultServicePortWhenCustomerProfileServicePortIsEmptyTest() { + contextRunner + .withPropertyValues("backbase.communication.http.default-service-port=8080") + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withUserConfiguration(CustomerProfileClientConfig.class) + .run(context -> { + var config = context.getBean(CustomerProfileClientConfig.class); + assertEquals("http://customer-profile:8080", config.createBasePath()); + }); + } } From 4f45a9589d30e759e1e01ba93a35c6065e36cde8 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 22 Apr 2025 12:45:51 +0200 Subject: [PATCH 05/41] Refactor CustomerProfileService to use integration API and remove deprecated service references --- .../service/CustomerProfileService.java | 17 ++++------ .../service/CustomerProfileServiceTest.java | 22 ++++++------- stream-dbs-clients/pom.xml | 13 -------- .../config/CustomerProfileClientConfig.java | 32 ++----------------- 4 files changed, 20 insertions(+), 64 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 5ee6752ca..8dc1aab65 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -1,9 +1,8 @@ package com.backbase.stream.service; -import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; -import com.backbase.customerprofile.api.service.v1.model.CustomerCreationRequestDto; -import com.backbase.customerprofile.api.service.v1.model.CustomerResponseDto; -import lombok.NonNull; +import com.backbase.customerprofile.api.integration.v1.CustomerManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.model.CustomerPartyDto; +import com.backbase.customerprofile.api.integration.v1.model.CustomerResponseDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.reactive.function.client.WebClientResponseException; @@ -13,19 +12,17 @@ @RequiredArgsConstructor public class CustomerProfileService { - @NonNull - private final CustomerManagementServiceApi customerManagementServiceApi; + private final CustomerManagementIntegrationApi customerManagementIntegrationApi; - public Mono createCustomer(CustomerCreationRequestDto customerCreationRequestDto) + public Mono createCustomer( + CustomerPartyDto customerPartyDto) throws WebClientResponseException { - return customerManagementServiceApi.createCustomer(customerCreationRequestDto) + return customerManagementIntegrationApi.createCustomer(customerPartyDto) .doOnError(WebClientResponseException.class, e -> { log.error("Error creating customer profile: {}", e.getMessage()); throw e; }) .doOnSuccess(customerResponseDto -> log.info("Customer profile created successfully: {}", customerResponseDto)); - } - } diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index ec417e6b6..16a4c2f4b 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -4,9 +4,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; -import com.backbase.customerprofile.api.service.v1.model.CustomerCreationRequestDto; -import com.backbase.customerprofile.api.service.v1.model.CustomerResponseDto; +import com.backbase.customerprofile.api.integration.v1.CustomerManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.model.CustomerPartyDto; +import com.backbase.customerprofile.api.integration.v1.model.CustomerResponseDto; import com.navercorp.fixturemonkey.FixtureMonkey; import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; import java.nio.charset.StandardCharsets; @@ -31,25 +31,25 @@ class CustomerProfileServiceTest { .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) .build(); @Mock - private CustomerManagementServiceApi customerManagementServiceApiMock; + private CustomerManagementIntegrationApi customerManagementIntegrationApiMock; @BeforeEach void setup() { - customerProfileService = new CustomerProfileService(customerManagementServiceApiMock); + customerProfileService = new CustomerProfileService(customerManagementIntegrationApiMock); } @Test @DisplayName("createCustomer should return CustomerResponseDto when API call is successful") void createCustomer_success() { var legalEntityId = UUID.randomUUID().toString(); - var requestDto = fixtureMonkey.giveMeBuilder(CustomerCreationRequestDto.class) + var requestDto = fixtureMonkey.giveMeBuilder(CustomerPartyDto.class) .set("legalEntityId", legalEntityId) .sample(); var expectedResponseDto = fixtureMonkey.giveMeBuilder(CustomerResponseDto.class) .set("legalEntityId", legalEntityId).sample(); - when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) .thenReturn(Mono.just(expectedResponseDto)); var result = customerProfileService.createCustomer(requestDto); @@ -64,14 +64,14 @@ void createCustomer_success() { @Test @DisplayName("createCustomer should propagate WebClientResponseException when API call fails") void createCustomer_apiError() { - var requestDto = fixtureMonkey.giveMeOne(CustomerCreationRequestDto.class); + var requestDto = fixtureMonkey.giveMeOne(CustomerPartyDto.class); var expectedException = new WebClientResponseException( HttpStatus.BAD_REQUEST.value(), "Bad Request from API", null, null, StandardCharsets.UTF_8); - when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) .thenReturn(Mono.error(expectedException)); var result = customerProfileService.createCustomer(requestDto); StepVerifier.create(result) @@ -86,9 +86,9 @@ void createCustomer_apiError() { @Test @DisplayName("createCustomer should propagate other RuntimeExceptions when API call fails unexpectedly") void createCustomer_otherError() { - var requestDto = fixtureMonkey.giveMeOne(CustomerCreationRequestDto.class); + var requestDto = fixtureMonkey.giveMeOne(CustomerPartyDto.class); var expectedException = new RuntimeException("Unexpected error"); - when(customerManagementServiceApiMock.createCustomer(any(CustomerCreationRequestDto.class))) + when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) .thenReturn(Mono.error(expectedException)); var result = customerProfileService.createCustomer(requestDto); StepVerifier.create(result) diff --git a/stream-dbs-clients/pom.xml b/stream-dbs-clients/pom.xml index c42fc5e23..7857a74f2 100644 --- a/stream-dbs-clients/pom.xml +++ b/stream-dbs-clients/pom.xml @@ -505,19 +505,6 @@ com.backbase.customerprofile.api.integration.v1.model - - generate-customer-profile-service-api-code - - generate-webclient-embedded - - generate-sources - - REFACTOR_ALLOF_WITH_PROPERTIES_ONLY=true - ${project.build.directory}/yaml/customer-profile/customer-profile-service-api-v*.yaml - com.backbase.customerprofile.api.service.v1 - com.backbase.customerprofile.api.service.v1.model - - diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java index 5246e51b4..00ea73271 100644 --- a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java +++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java @@ -1,11 +1,8 @@ package com.backbase.stream.clients.config; +import com.backbase.customerprofile.api.integration.ApiClient; import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; -import com.backbase.customerprofile.api.service.ApiClient; -import com.backbase.customerprofile.api.service.v1.CustomerManagementServiceApi; -import com.backbase.customerprofile.api.service.v1.PartyManagementServiceApi; -import com.backbase.customerprofile.api.service.v1.PartyRelationshipsManagementServiceApi; import com.fasterxml.jackson.databind.ObjectMapper; import java.text.DateFormat; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -23,39 +20,15 @@ public CustomerProfileClientConfig() { super(CUSTOMER_PROFILE_SERVICE_ID); } - @Bean - @ConditionalOnMissingBean - public ApiClient customerProfileApiClient(ObjectMapper objectMapper, DateFormat dateFormat) { - return new ApiClient(getWebClient(), objectMapper, dateFormat).setBasePath(createBasePath()); - } @Bean @ConditionalOnMissingBean - public com.backbase.customerprofile.api.integration.ApiClient customerProfileApiIntegrationClient( + public ApiClient customerProfileApiIntegrationClient( ObjectMapper objectMapper, DateFormat dateFormat) { return new com.backbase.customerprofile.api.integration.ApiClient(getWebClient(), objectMapper, dateFormat) .setBasePath(createBasePath()); } - @Bean - @ConditionalOnMissingBean - public CustomerManagementServiceApi customerManagementServiceApi(ApiClient customerProfileApiClient) { - return new CustomerManagementServiceApi(customerProfileApiClient); - } - - @Bean - @ConditionalOnMissingBean - public PartyManagementServiceApi partyManagementServiceApi(ApiClient customerProfileApiClient) { - return new PartyManagementServiceApi(customerProfileApiClient); - } - - @Bean - @ConditionalOnMissingBean - public PartyRelationshipsManagementServiceApi partyRelationshipsManagementServiceApi( - ApiClient customerProfileApiClient) { - return new PartyRelationshipsManagementServiceApi(customerProfileApiClient); - } - @Bean @ConditionalOnMissingBean public PartyManagementIntegrationApi partyManagementIntegrationApi( @@ -63,5 +36,4 @@ public PartyManagementIntegrationApi partyManagementIntegrationApi( return new PartyManagementIntegrationApi(customerProfileApiIntegrationClient); } - } From 92ef578e5e0137de1e72c18fc175e719709f1942 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 22 Apr 2025 18:25:25 +0200 Subject: [PATCH 06/41] Add FixtureMonkey dependency and update OpenAPI schema for Party and related entities --- api/stream-legal-entity/openapi.yaml | 227 +++++++++++++++++- .../customer-profile-core/pom.xml | 29 +-- .../service/CustomerProfileServiceTest.java | 16 +- stream-customer-profile/pom.xml | 4 +- .../stream-parent/stream-test-support/pom.xml | 5 + 5 files changed, 250 insertions(+), 31 deletions(-) diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index f505b4b26..0932b5c0b 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1126,6 +1126,10 @@ components: type: array items: $ref: '#/components/schemas/JobProfileUser' + parties: + type: array + items: + $ref: '#/components/schemas/Party' referenceJobRoles: type: array items: @@ -1244,6 +1248,160 @@ components: $ref: '#/components/schemas/ExternalContact' required: - user + Party: + type: object + properties: + partyId: + $ref: '#/components/schemas/ExternalIdentifier' + isDigital: + type: boolean + isCustomer: + type: boolean + partyType: + type: string + person: + $ref: '#/components/schemas/Person' + organisation: + $ref: '#/components/schemas/Organisation' + partyPartyRelationships: + type: array + items: + $ref: '#/components/schemas/PartyRelationship' + organisationName: + type: string + closingDateTime: + type: string + format: date + approvedDateTime: + type: string + format: date + lastUpdatedDateTime: + type: string + format: date + openingDateTime: + type: string + format: date + status: + type: string + postalAddresses: + type: array + items: + $ref: '#/components/schemas/PartyPostalAddress' + phoneAddresses: + type: array + items: + $ref: '#/components/schemas/PhoneAddress' + electronicAddress: + type: array + items: + $ref: '#/components/schemas/ElectronicAddress' + preferredLanguage: + type: string + description: Language code, e.g. en, de, fr, nl + notes: + type: array + items: + type: string + customFields: + type: object + additionalProperties: + type: string + Person: + type: object + properties: + identifications: + type: array + items: + $ref: '#/components/schemas/Identification' + personName: + $ref: '#/components/schemas/PersonName' + gender: + type: string + birthDate: + type: string + format: date + demographics: + type: object + properties: + occupation: + type: object + properties: + employer: + type: string + employment: + type: string + education: + type: object + properties: + yearOfPassing: + type: string + educationLevel: + type: string + Organisation: + type: object + properties: + legalStructureType: + type: string + establishmentDate: + type: string + name: + type: string + type: + type: string + sector: + type: string + liveDateTime: + type: string + format: date + identifications: + type: array + items: + $ref: '#/components/schemas/Identification' + Identification: + type: object + properties: + expiryDate: + type: string + format: date + issuingCountry: + type: string + issuingAuthority: + type: string + identificationNumber: + type: string + identificationType: + type: string + issueDate: + type: string + format: date + PartyRelationship: + type: object + properties: + partyRole: + type: string + ownershipPercent: + type: number + format: double + roleEndDate: + type: string + format: date + partyId: + $ref: '#/components/schemas/ExternalIdentifier' + roleStartDate: + type: string + format: date + PersonName: + type: object + properties: + firstName: + type: string + middleName: + type: string + familyName: + type: string + salutation: + type: string + LegalEntityType: type: string title: Legal Entity Type @@ -1338,6 +1496,16 @@ components: minLength: 1 type: string description: Address. + Url: + type: object + properties: + primary: + type: boolean + address: + maxLength: 255 + minLength: 1 + type: string + PhoneNumber: required: - key @@ -1418,6 +1586,57 @@ components: maxLength: 3 type: string description: Country code - ISO 3166. + PartyPostalAddress: + type: object + properties: + country: + type: string + streetName: + type: string + townName: + type: string + countrySubDivision: + type: string + postalCode: + type: string + buildingNumber: + type: string + subDepartment: + type: string + type: + type: string + department: + type: string + addressLine: + type: string + primary: + type: boolean + + PhoneAddress: + type: object + properties: + number: + type: string + countryIsoCode: + type: string + countryCode: + type: string + type: + type: string + primary: + type: boolean + ElectronicAddress: + type: object + properties: + emails: + type: array + items: + $ref: '#/components/schemas/EmailAddress' + urls: + type: array + items: + $ref: '#/components/schemas/Url' + Limit: title: Limit type: object @@ -1623,7 +1842,7 @@ components: type: boolean ServiceAgreement: - title: Service Agreement + title: Service Agreement description: | The formal vehicle that allows users of one entity to access products of that or other entities A Service agreement is: @@ -1854,7 +2073,7 @@ components: title: External Identifier maxLength: 64 minLength: 1 -# pattern: ^{1,64}$ + # pattern: ^{1,64}$ type: string description: External legal entity identifier. UrgentTransfer: @@ -2386,7 +2605,7 @@ components: maxLength: 255 type: string description: Email-id of the contact -# format: email + # format: email addressLine1: maxLength: 70 type: string @@ -2554,7 +2773,7 @@ components: type: string description: "An email account identifier. At least one of the account identifiers\ \ (accountNumber, IBAN, phoneNumber or email) is mandatory." -# format: email + # format: email Additions: title: Additions type: object diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml index e7800c0fa..59cda3e09 100644 --- a/stream-customer-profile/customer-profile-core/pom.xml +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -1,7 +1,5 @@ - + 4.0.0 @@ -26,27 +24,14 @@ 6.17.0 compile + + - org.junit.jupiter - junit-jupiter-api - test - - - org.mockito - mockito-junit-jupiter - test - - - com.navercorp.fixturemonkey - fixture-monkey-starter - 1.1.11 - test - - - io.projectreactor - reactor-test + com.backbase.stream + stream-test-support + ${project.version} test - \ No newline at end of file + diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index 16a4c2f4b..250879990 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -9,8 +9,12 @@ import com.backbase.customerprofile.api.integration.v1.model.CustomerResponseDto; import com.navercorp.fixturemonkey.FixtureMonkey; import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; +import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; +import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; import java.nio.charset.StandardCharsets; import java.util.UUID; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.arbitraries.StringArbitrary; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,6 +33,12 @@ class CustomerProfileServiceTest { private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) + .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { + @Override + public StringArbitrary strings() { + return Arbitraries.strings().alpha(); + } + })) .build(); @Mock private CustomerManagementIntegrationApi customerManagementIntegrationApiMock; @@ -76,9 +86,9 @@ void createCustomer_apiError() { var result = customerProfileService.createCustomer(requestDto); StepVerifier.create(result) .expectErrorMatches(throwable -> - throwable instanceof WebClientResponseException && - ((WebClientResponseException) throwable).getStatusCode() == HttpStatus.BAD_REQUEST && - throwable.getMessage().contains("Bad Request from API") + throwable instanceof WebClientResponseException && + ((WebClientResponseException) throwable).getStatusCode() == HttpStatus.BAD_REQUEST && + throwable.getMessage().contains("Bad Request from API") ) .verify(); } diff --git a/stream-customer-profile/pom.xml b/stream-customer-profile/pom.xml index 9a872d5db..f21c9070e 100644 --- a/stream-customer-profile/pom.xml +++ b/stream-customer-profile/pom.xml @@ -1,5 +1,5 @@ - + + 4.0.0 diff --git a/stream-sdk/stream-parent/stream-test-support/pom.xml b/stream-sdk/stream-parent/stream-test-support/pom.xml index 311b3e1bf..3c0fe5950 100644 --- a/stream-sdk/stream-parent/stream-test-support/pom.xml +++ b/stream-sdk/stream-parent/stream-test-support/pom.xml @@ -82,6 +82,11 @@ wiremock-jre8-standalone 2.35.1 + + com.navercorp.fixturemonkey + fixture-monkey-starter + 1.1.11 + From d1e9fea09a59cfccc26e653b4aff57c4daabe9ad Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 22 Apr 2025 18:48:55 +0200 Subject: [PATCH 07/41] Refactor test dependencies --- stream-legal-entity/legal-entity-core/pom.xml | 17 +++++++---------- .../stream-parent/stream-test-support/pom.xml | 7 +++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/stream-legal-entity/legal-entity-core/pom.xml b/stream-legal-entity/legal-entity-core/pom.xml index c59174e75..26cc0b361 100644 --- a/stream-legal-entity/legal-entity-core/pom.xml +++ b/stream-legal-entity/legal-entity-core/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -14,7 +15,8 @@ Stream :: Legal Entity Core - ${project.basedir}/../../api/stream-legal-entity/openapi.yaml + ${project.basedir}/../../api/stream-legal-entity/openapi.yaml + ${project.build.directory}/openapi.yaml true @@ -105,14 +107,9 @@ - io.projectreactor - reactor-test - test - - - - com.backbase.buildingblocks - service-sdk-starter-test + com.backbase.stream + stream-test-support + ${project.version} test diff --git a/stream-sdk/stream-parent/stream-test-support/pom.xml b/stream-sdk/stream-parent/stream-test-support/pom.xml index 3c0fe5950..dee26ffb9 100644 --- a/stream-sdk/stream-parent/stream-test-support/pom.xml +++ b/stream-sdk/stream-parent/stream-test-support/pom.xml @@ -82,6 +82,13 @@ wiremock-jre8-standalone 2.35.1 + + + com.backbase.buildingblocks + service-sdk-starter-test + test + + com.navercorp.fixturemonkey fixture-monkey-starter From 9decfb119cffc75ca94c1871c729f9f04d1add4f Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 13:13:35 +0200 Subject: [PATCH 08/41] Add CustomerProfileConfiguration and update dependencies for integration with PartyManagement API --- .../customer-profile-core/pom.xml | 20 +- .../CustomerProfileConfiguration.java | 21 + .../service/CustomerProfileService.java | 18 +- .../service/CustomerProfileServiceTest.java | 48 +-- .../config/CustomerProfileClientConfig.java | 28 +- stream-legal-entity/legal-entity-core/pom.xml | 13 +- .../com/backbase/stream/LegalEntitySaga.java | 388 +++++++++++------- .../LegalEntitySagaConfiguration.java | 12 +- .../ServiceAgreementControllerTest.java | 11 + .../stream-parent/stream-test-support/pom.xml | 12 +- 10 files changed, 385 insertions(+), 186 deletions(-) create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml index 59cda3e09..074b255b8 100644 --- a/stream-customer-profile/customer-profile-core/pom.xml +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -17,15 +17,31 @@ + + com.backbase.stream + legal-entity-model + ${project.version} + compile + + + + org.mapstruct + mapstruct-processor + + + + org.springframework.boot + spring-boot-configuration-processor + true + com.backbase.stream stream-dbs-clients - 6.17.0 + ${project.version} compile - com.backbase.stream stream-test-support diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java new file mode 100644 index 000000000..d19a4ffff --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java @@ -0,0 +1,21 @@ +package com.backbase.configuration; + +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; +import com.backbase.stream.clients.config.CustomerProfileClientConfig; +import com.backbase.stream.service.CustomerProfileService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Slf4j +@EnableConfigurationProperties(CustomerProfileClientConfig.class) +public class CustomerProfileConfiguration { + + @Bean + public CustomerProfileService createCustomerProfileService( + PartyManagementIntegrationApi partyManagementIntegrationApi) { + return new CustomerProfileService(partyManagementIntegrationApi); + } +} diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 8dc1aab65..8bac27855 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -1,8 +1,9 @@ package com.backbase.stream.service; -import com.backbase.customerprofile.api.integration.v1.CustomerManagementIntegrationApi; -import com.backbase.customerprofile.api.integration.v1.model.CustomerPartyDto; -import com.backbase.customerprofile.api.integration.v1.model.CustomerResponseDto; +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; +import com.backbase.stream.legalentity.model.Party; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.reactive.function.client.WebClientResponseException; @@ -12,12 +13,11 @@ @RequiredArgsConstructor public class CustomerProfileService { - private final CustomerManagementIntegrationApi customerManagementIntegrationApi; + private final PartyManagementIntegrationApi partyManagementIntegrationApi; - public Mono createCustomer( - CustomerPartyDto customerPartyDto) + public Mono upsertParty(PartyUpsertDto partyUpsertDto) throws WebClientResponseException { - return customerManagementIntegrationApi.createCustomer(customerPartyDto) + return partyManagementIntegrationApi.upsertParty(partyUpsertDto) .doOnError(WebClientResponseException.class, e -> { log.error("Error creating customer profile: {}", e.getMessage()); throw e; @@ -25,4 +25,8 @@ public Mono createCustomer( .doOnSuccess(customerResponseDto -> log.info("Customer profile created successfully: {}", customerResponseDto)); } + + public Mono upsertParty(Party party) { + return Mono.firstWithSignal(); + } } diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index 250879990..85d171a8c 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -1,12 +1,12 @@ package com.backbase.stream.service; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import com.backbase.customerprofile.api.integration.v1.CustomerManagementIntegrationApi; -import com.backbase.customerprofile.api.integration.v1.model.CustomerPartyDto; -import com.backbase.customerprofile.api.integration.v1.model.CustomerResponseDto; +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; import com.navercorp.fixturemonkey.FixtureMonkey; import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; @@ -41,49 +41,51 @@ public StringArbitrary strings() { })) .build(); @Mock - private CustomerManagementIntegrationApi customerManagementIntegrationApiMock; + private PartyManagementIntegrationApi partyManagementIntegrationApiMock; @BeforeEach void setup() { - customerProfileService = new CustomerProfileService(customerManagementIntegrationApiMock); + customerProfileService = new CustomerProfileService(partyManagementIntegrationApiMock); } @Test - @DisplayName("createCustomer should return CustomerResponseDto when API call is successful") + @DisplayName("Upsert party should return PartyResponseUpsertDto when API call is successful") void createCustomer_success() { var legalEntityId = UUID.randomUUID().toString(); - var requestDto = fixtureMonkey.giveMeBuilder(CustomerPartyDto.class) + var requestDto = fixtureMonkey.giveMeBuilder(PartyUpsertDto.class) .set("legalEntityId", legalEntityId) .sample(); - var expectedResponseDto = fixtureMonkey.giveMeBuilder(CustomerResponseDto.class) - .set("legalEntityId", legalEntityId).sample(); + var expectedResponseDto = fixtureMonkey.giveMeBuilder(PartyResponseUpsertDto.class) + .set("partyReferenceId", legalEntityId).sample(); - when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) + when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.just(expectedResponseDto)); - var result = customerProfileService.createCustomer(requestDto); + var result = customerProfileService.upsertParty(requestDto); StepVerifier.create(result) .assertNext(response -> { - assertEquals(expectedResponseDto.getLegalEntityId(), response.getLegalEntityId()); + assertNotNull(response); + assertNotNull(response.getCustomerReferenceId()); + assertNotNull(response.getPartyReferenceId()); }) .verifyComplete(); } @Test - @DisplayName("createCustomer should propagate WebClientResponseException when API call fails") - void createCustomer_apiError() { - var requestDto = fixtureMonkey.giveMeOne(CustomerPartyDto.class); + @DisplayName("Upsert party should propagate WebClientResponseException when API call fails") + void upsertParty_apiError() { + var requestDto = fixtureMonkey.giveMeOne(PartyUpsertDto.class); var expectedException = new WebClientResponseException( HttpStatus.BAD_REQUEST.value(), "Bad Request from API", null, null, StandardCharsets.UTF_8); - when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) + when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.error(expectedException)); - var result = customerProfileService.createCustomer(requestDto); + var result = customerProfileService.upsertParty(requestDto); StepVerifier.create(result) .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException && @@ -94,13 +96,13 @@ void createCustomer_apiError() { } @Test - @DisplayName("createCustomer should propagate other RuntimeExceptions when API call fails unexpectedly") - void createCustomer_otherError() { - var requestDto = fixtureMonkey.giveMeOne(CustomerPartyDto.class); + @DisplayName("Upsert party should propagate other RuntimeExceptions when API call fails unexpectedly") + void upsertParty_otherError() { + var requestDto = fixtureMonkey.giveMeOne(PartyUpsertDto.class); var expectedException = new RuntimeException("Unexpected error"); - when(customerManagementIntegrationApiMock.createCustomer(any(CustomerPartyDto.class))) + when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.error(expectedException)); - var result = customerProfileService.createCustomer(requestDto); + var result = customerProfileService.upsertParty(requestDto); StepVerifier.create(result) .expectErrorMatches(throwable -> throwable == expectedException) .verify(); diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java index 00ea73271..625d7e587 100644 --- a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java +++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java @@ -2,6 +2,9 @@ import com.backbase.customerprofile.api.integration.ApiClient; +import com.backbase.customerprofile.api.integration.v1.CustomerLifeCycleManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.CustomerManagementIntegrationApi; +import com.backbase.customerprofile.api.integration.v1.CustomerProfileManagementIntegrationApi; import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.fasterxml.jackson.databind.ObjectMapper; import java.text.DateFormat; @@ -25,15 +28,36 @@ public CustomerProfileClientConfig() { @ConditionalOnMissingBean public ApiClient customerProfileApiIntegrationClient( ObjectMapper objectMapper, DateFormat dateFormat) { - return new com.backbase.customerprofile.api.integration.ApiClient(getWebClient(), objectMapper, dateFormat) + return new ApiClient(getWebClient(), objectMapper, dateFormat) .setBasePath(createBasePath()); } @Bean @ConditionalOnMissingBean public PartyManagementIntegrationApi partyManagementIntegrationApi( - com.backbase.customerprofile.api.integration.ApiClient customerProfileApiIntegrationClient) { + ApiClient customerProfileApiIntegrationClient) { return new PartyManagementIntegrationApi(customerProfileApiIntegrationClient); } + @Bean + @ConditionalOnMissingBean + public CustomerManagementIntegrationApi createCustomerManagementIntegrationApi( + ApiClient customerProfileClientConfig) { + return new CustomerManagementIntegrationApi(customerProfileClientConfig); + } + + @Bean + @ConditionalOnMissingBean + public CustomerProfileManagementIntegrationApi createCustomerProfileManagementIntegrationApi( + ApiClient customerProfileClientConfig) { + return new CustomerProfileManagementIntegrationApi(customerProfileClientConfig); + } + + @Bean + @ConditionalOnMissingBean + public CustomerLifeCycleManagementIntegrationApi createCustomerLifeCycleManagementIntegrationApi( + ApiClient customerProfileClientConfig) { + return new CustomerLifeCycleManagementIntegrationApi(customerProfileClientConfig); + } + } diff --git a/stream-legal-entity/legal-entity-core/pom.xml b/stream-legal-entity/legal-entity-core/pom.xml index 26cc0b361..bd582a9ae 100644 --- a/stream-legal-entity/legal-entity-core/pom.xml +++ b/stream-legal-entity/legal-entity-core/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -15,8 +14,7 @@ Stream :: Legal Entity Core - ${project.basedir}/../../api/stream-legal-entity/openapi.yaml - + ${project.basedir}/../../api/stream-legal-entity/openapi.yaml ${project.build.directory}/openapi.yaml true @@ -42,6 +40,13 @@ ${project.version} + + com.backbase.stream + customer-profile-core + ${project.version} + compile + + com.backbase.stream legal-entity-model diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index b19be0b00..188bd23ec 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -47,6 +47,7 @@ import com.backbase.stream.legalentity.model.LegalEntityStatus; import com.backbase.stream.legalentity.model.LegalEntityType; import com.backbase.stream.legalentity.model.Limit; +import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.legalentity.model.Privilege; import com.backbase.stream.legalentity.model.ProductGroup; import com.backbase.stream.legalentity.model.ServiceAgreement; @@ -64,6 +65,7 @@ import com.backbase.stream.product.task.ProductGroupTask; import com.backbase.stream.product.utils.StreamUtils; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.stream.service.LegalEntityService; import com.backbase.stream.service.UserProfileService; import com.backbase.stream.service.UserService; @@ -135,8 +137,11 @@ public class LegalEntitySaga implements StreamTaskExecutor { private static final String JOB_ROLE_LIMITS = "job-role-limits"; private static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; + // private static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; - private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper(BusinessFunctionGroupMapper.class); + + private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper( + BusinessFunctionGroupMapper.class); private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class); private final LegalEntityService legalEntityService; @@ -148,10 +153,11 @@ public class LegalEntitySaga implements StreamTaskExecutor { private final ContactsSaga contactsSaga; private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties; private final UserKindSegmentationSaga userKindSegmentationSaga; - + // private final CustomerProfileService customerProfileService; private static final ExternalContactMapper externalContactMapper = ExternalContactMapper.INSTANCE; - public LegalEntitySaga(LegalEntityService legalEntityService, + public LegalEntitySaga( + LegalEntityService legalEntityService, UserService userService, UserProfileService userProfileService, AccessGroupService accessGroupService, @@ -159,7 +165,8 @@ public LegalEntitySaga(LegalEntityService legalEntityService, LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga) { + UserKindSegmentationSaga userKindSegmentationSaga + /* CustomerProfileService customerProfileService*/) { this.legalEntityService = legalEntityService; this.userService = userService; this.userProfileService = userProfileService; @@ -169,6 +176,7 @@ public LegalEntitySaga(LegalEntityService legalEntityService, this.contactsSaga = contactsSaga; this.legalEntitySagaConfigurationProperties = legalEntitySagaConfigurationProperties; this.userKindSegmentationSaga = userKindSegmentationSaga; + // this.customerProfileService = customerProfileService; } @Override @@ -185,7 +193,8 @@ public Mono executeTask(@SpanTag(value = "streamTask") LegalEnt .flatMap(this::setupLimits) .flatMap(this::processProducts) .flatMap(this::postContacts) - .flatMap(this::processSubsidiaries); + .flatMap(this::processSubsidiaries) + /*.flatMap(this::processCustomerProfile)*/; } private Mono processAudiencesSegmentation(LegalEntityTask streamTask) { @@ -250,37 +259,42 @@ private UserKindEnum customerCategoryToUserKind(CustomerCategory customerCategor private Mono postContacts(LegalEntityTask streamTask) { return Mono.just(streamTask) - .flatMap(this::postLegalEntityContacts) - .flatMap(this::postServiceAgreementContacts) - .flatMap(this::postUserContacts); + .flatMap(this::postLegalEntityContacts) + .flatMap(this::postServiceAgreementContacts) + .flatMap(this::postUserContacts); } private Mono postLegalEntityContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (isEmpty(legalEntity.getContacts())) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), - "Legal Entity: %s does not have any Contacts defined", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), + legalEntity.getInternalId(), + "Legal Entity: %s does not have any Contacts defined", legalEntity.getExternalId()); return Mono.just(streamTask); } ServiceAgreement serviceAgreement = getServiceAgreement(legalEntity); log.info("Creating Contacts for Legal Entity Id {}", legalEntity.getExternalId()); Optional externalUserOptional = getUserExternalId(legalEntity.getUsers()); if (externalUserOptional.isEmpty()) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), - "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), + legalEntity.getInternalId(), + "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); return Mono.just(streamTask); } - return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), externalUserOptional.get(), AccessContextScope.LE, legalEntity.getContacts())) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + return contactsSaga.executeTask( + createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), + externalUserOptional.get(), AccessContextScope.LE, legalEntity.getContacts())) + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private Mono postServiceAgreementContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = getServiceAgreement(legalEntity); if (isEmpty(serviceAgreement.getContacts())) { - streamTask.info(SERVICE_AGREEMENT, PROCESS_CONTACTS, FAILED, serviceAgreement.getExternalId(), serviceAgreement.getInternalId(), - "Master Service Agreement: %s does not have any Contacts defined", serviceAgreement.getExternalId()); + streamTask.info(SERVICE_AGREEMENT, PROCESS_CONTACTS, FAILED, serviceAgreement.getExternalId(), + serviceAgreement.getInternalId(), + "Master Service Agreement: %s does not have any Contacts defined", serviceAgreement.getExternalId()); return Mono.just(streamTask); } log.info("Creating Contacts for Service Agreement Id {}", serviceAgreement.getExternalId()); @@ -289,24 +303,27 @@ private Mono postServiceAgreementContacts(LegalEntityTask strea if (externalUserOptional.isEmpty()) { externalUserId = getParticipantUser(serviceAgreement); if (externalUserId == null) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), - "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), + legalEntity.getInternalId(), + "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); return Mono.just(streamTask); } } else { externalUserId = externalUserOptional.get(); } - return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), externalUserId, AccessContextScope.SA, serviceAgreement.getContacts())) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + return contactsSaga.executeTask( + createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), + externalUserId, AccessContextScope.SA, serviceAgreement.getContacts())) + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private String getParticipantUser(ServiceAgreement serviceAgreement) { if (!isEmpty(serviceAgreement.getParticipants())) { Optional participants = serviceAgreement.getParticipants() - .stream() - .filter(LegalEntityParticipant::getSharingUsers) - .findFirst(); + .stream() + .filter(LegalEntityParticipant::getSharingUsers) + .findFirst(); if (participants.isPresent()) { LegalEntityParticipant participant = participants.get(); if (!isEmpty(participant.getAdmins())) { @@ -323,15 +340,19 @@ private String getOptionalUserId(Optional optionalUserId) { return optionalUserId.isPresent() ? optionalUserId.get() : null; } - private ContactsTask createContactsTask(String streamTaskId, String externalLegalEntityId, String externalServiceAgreementId, String externalUserId, AccessContextScope scope, List contacts) { + private ContactsTask createContactsTask(String streamTaskId, String externalLegalEntityId, + String externalServiceAgreementId, String externalUserId, AccessContextScope scope, + List contacts) { var contactData = new ContactsBulkPostRequestBody(); contactData.setIngestMode(IngestMode.UPSERT); - contactData.setAccessContext(createExternalAccessContext(externalLegalEntityId, externalServiceAgreementId, externalUserId, scope)); + contactData.setAccessContext( + createExternalAccessContext(externalLegalEntityId, externalServiceAgreementId, externalUserId, scope)); contactData.setContacts(externalContactMapper.toMapList(contacts)); return new ContactsTask(streamTaskId + "-" + "contacts-task", contactData); } - private ExternalAccessContext createExternalAccessContext(String externalLegalEntityId, String externalServiceAgreementId, String externalUserId, AccessContextScope scope) { + private ExternalAccessContext createExternalAccessContext(String externalLegalEntityId, + String externalServiceAgreementId, String externalUserId, AccessContextScope scope) { ExternalAccessContext accessContext = new ExternalAccessContext(); accessContext.setExternalLegalEntityId(externalLegalEntityId); accessContext.setExternalServiceAgreementId(externalServiceAgreementId); @@ -345,13 +366,14 @@ private Optional getUserExternalId(List users) { return Optional.empty(); } Optional optionalUser = users.stream().findFirst(); - return optionalUser.map(jobProfileUser -> Optional.ofNullable(jobProfileUser.getUser().getExternalId())).orElse(Optional.empty()); + return optionalUser.map(jobProfileUser -> Optional.ofNullable(jobProfileUser.getUser().getExternalId())) + .orElse(Optional.empty()); } private ServiceAgreement getServiceAgreement(LegalEntity legalEntity) { - return legalEntity.getMasterServiceAgreement() != null? - legalEntity.getMasterServiceAgreement() : - legalEntity.getCustomServiceAgreement(); + return legalEntity.getMasterServiceAgreement() != null ? + legalEntity.getMasterServiceAgreement() : + legalEntity.getCustomServiceAgreement(); } @Override @@ -362,7 +384,8 @@ public Mono rollBack(LegalEntityTask streamTask) { /** * Delete Legal Entity by provided Legal Entity external ID. - * This call doesn't cover arrangements and transactions removal. Should be done before caling this method. + * This call doesn't cover arrangements and transactions removal. Should be done before caling this + * method. *
* Flow is the following: *
    @@ -425,10 +448,12 @@ public Mono deleteLegalEntity(String legalEntityExternalId) { } private Mono upsertLegalEntity(LegalEntityTask task) { - task.info(LEGAL_ENTITY, UPSERT, "", task.getData().getExternalId(), null, "Upsert Legal Entity with External ID: %s", task.getData().getExternalId()); + task.info(LEGAL_ENTITY, UPSERT, "", task.getData().getExternalId(), null, + "Upsert Legal Entity with External ID: %s", task.getData().getExternalId()); LegalEntity legalEntity = task.getData(); // Pipeline for Existing Legal Entity - Mono existingLegalEntity = legalEntityService.getLegalEntityByExternalId(legalEntity.getExternalId()) + Mono existingLegalEntity = legalEntityService.getLegalEntityByExternalId( + legalEntity.getExternalId()) .flatMap(actual -> { task.getData().setInternalId(actual.getInternalId()); return legalEntityService.getLegalEntityByInternalId(actual.getInternalId()) @@ -437,7 +462,8 @@ private Mono upsertLegalEntity(LegalEntityTask task) { return legalEntityService.putLegalEntity(task.getData()).flatMap(leUpdated -> { log.info("Updated LegalEntity: {}", leUpdated.getName()); - task.info(LEGAL_ENTITY, UPSERT_LEGAL_ENTITY, UPDATED, legalEntity.getExternalId(), actual.getInternalId(), "Legal Entity: %s updated", legalEntity.getName()); + task.info(LEGAL_ENTITY, UPSERT_LEGAL_ENTITY, UPDATED, legalEntity.getExternalId(), + actual.getInternalId(), "Legal Entity: %s updated", legalEntity.getName()); return Mono.just(task); }); }); @@ -478,7 +504,9 @@ private Mono upsertLegalEntity(LegalEntityTask task) { private Mono processProducts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (legalEntity.getProductGroups() == null || legalEntity.getProductGroups().isEmpty()) { - streamTask.info(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any products defied", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), "Legal Entity: %s does not have any products defied", + legalEntity.getExternalId()); return Mono.just(streamTask); } @@ -490,8 +518,10 @@ private Mono processProducts(LegalEntityTask streamTask) { if (throwable.getClass().isAssignableFrom(WebClientResponseException.class)) { message = ((WebClientResponseException) throwable).getResponseBodyAsString(); } - streamTask.error(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), throwable, message, "Unexpected error processing"); - log.error("Unexpected error processing product group {}: {}", productGroupStreamTask.getData().getName(), message); + streamTask.error(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), throwable, message, "Unexpected error processing"); + log.error("Unexpected error processing product group {}: {}", + productGroupStreamTask.getData().getName(), message); productGroupStreamTask.setState(StreamTask.State.FAILED); return Mono.error(throwable); })) @@ -560,7 +590,7 @@ private Mono createJobRoles(LegalEntityTask streamTask) { log.info("Creating Job Roles..."); return Flux.fromStream(Stream.of(serviceAgreement.getJobRoles(), legalEntity.getReferenceJobRoles()) - .filter(Objects::nonNull) + .filter(Objects::nonNull) .flatMap(Collection::stream)) .flatMap(jobRole -> accessGroupService.setupJobRole(streamTask, serviceAgreement, jobRole)) .flatMap(jobRole -> { @@ -575,41 +605,57 @@ private Mono processJobProfiles(LegalEntityTask streamTask) { log.info("Processing Job Profiles for: {}", streamTask.getName()); LegalEntity legalEntity = streamTask.getData(); if (legalEntity.getUsers() == null) { - streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), legalEntity.getInternalId(), "No Job Profile Users defined in Legal Entity. No Business Function Groups will be assigned between a User and Legal Entity. "); + streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), + legalEntity.getInternalId(), + "No Job Profile Users defined in Legal Entity. No Business Function Groups will be assigned between a User and Legal Entity. "); return Mono.just(streamTask); } if (legalEntity.getUsers().stream().allMatch(jobProfileUser -> jobProfileUser.getUser() == null)) { - streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), legalEntity.getInternalId(), "No Users defined in Job Profiles"); + streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), + legalEntity.getInternalId(), "No Users defined in Job Profiles"); return Mono.just(streamTask); } return Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())) .flatMap(jobProfileUser -> { ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); return getBusinessFunctionGroupTemplates(streamTask, jobProfileUser) - .flatMap(businessFunctionGroups -> accessGroupService.setupFunctionGroups(streamTask, serviceAgreement, businessFunctionGroups)) + .flatMap( + businessFunctionGroups -> accessGroupService.setupFunctionGroups(streamTask, serviceAgreement, + businessFunctionGroups)) .flatMap(list -> { - log.info("Assigning {} Business Function Groups to Job Profile User: {}", list.size(), jobProfileUser.getUser().getExternalId()); + log.info("Assigning {} Business Function Groups to Job Profile User: {}", list.size(), + jobProfileUser.getUser().getExternalId()); jobProfileUser.setBusinessFunctionGroups(list); - list.forEach(bfg -> streamTask.info(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, "assigned", legalEntity.getExternalId(), legalEntity.getInternalId(), "Assigned Business Function Group: %s with functions: %s to Service Agreement: %s", bfg.getName(), - ofNullable(bfg.getFunctions()).orElse(Collections.singletonList(new BusinessFunction().name(""))).stream().map(BusinessFunction::getFunctionCode).collect(Collectors.joining(", ")), serviceAgreement.getExternalId())); + list.forEach(bfg -> streamTask.info(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, "assigned", + legalEntity.getExternalId(), legalEntity.getInternalId(), + "Assigned Business Function Group: %s with functions: %s to Service Agreement: %s", + bfg.getName(), + ofNullable(bfg.getFunctions()).orElse( + Collections.singletonList(new BusinessFunction().name(""))).stream() + .map(BusinessFunction::getFunctionCode).collect(Collectors.joining(", ")), + serviceAgreement.getExternalId())); return setupUserPermissions(streamTask, jobProfileUser); }) .map(actual -> jobProfileUser); }) .collectList() .map(jobProfileUsers -> { - if (!jobProfileUsers.isEmpty()) + if (!jobProfileUsers.isEmpty()) { streamTask.getData().setUsers(jobProfileUsers); + } return streamTask; }); } - private Mono> getBusinessFunctionGroupTemplates(LegalEntityTask streamTask, JobProfileUser jobProfileUser) { - streamTask.info(LEGAL_ENTITY, BUSINESS_FUNCTION_GROUP, "getBusinessFunctionGroupTemplates", "", "", "Using Reference Job Roles and Custom Job Roles defined in Job Profile User"); + private Mono> getBusinessFunctionGroupTemplates(LegalEntityTask streamTask, + JobProfileUser jobProfileUser) { + streamTask.info(LEGAL_ENTITY, BUSINESS_FUNCTION_GROUP, "getBusinessFunctionGroupTemplates", "", "", + "Using Reference Job Roles and Custom Job Roles defined in Job Profile User"); List businessFunctionGroups = jobProfileUser.getBusinessFunctionGroups(); if (!isEmpty(jobProfileUser.getReferenceJobRoleNames())) { - return accessGroupService.getFunctionGroupsForServiceAgreement(retrieveServiceAgreement(streamTask.getData()).getInternalId()) + return accessGroupService.getFunctionGroupsForServiceAgreement( + retrieveServiceAgreement(streamTask.getData()).getInternalId()) .map(functionGroups -> { Map idByFunctionGroupName = functionGroups .stream() @@ -622,8 +668,9 @@ private Mono> getBusinessFunctionGroupTemplates(Lega .collect(Collectors.toList()); }) .map(bf -> { - if (!isEmpty(businessFunctionGroups)) + if (!isEmpty(businessFunctionGroups)) { bf.addAll(businessFunctionGroups); + } return bf; }); } @@ -640,7 +687,7 @@ private Mono setupAdministrators(LegalEntityTask streamTask) { .map(streamTask::data); } - private Mono setupUsers(LegalEntityTask streamTask) { + private Mono setupUsers(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); Flux jobProfileUsers = Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())); @@ -670,24 +717,26 @@ private Mono postUserContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); Flux jobProfileUsers = Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())); return jobProfileUsers - .flatMap(jobProfileUser -> postUserContacts(streamTask, jobProfileUser.getContacts(), jobProfileUser.getUser().getExternalId())) - .collectList() - .thenReturn(streamTask); + .flatMap(jobProfileUser -> postUserContacts(streamTask, jobProfileUser.getContacts(), + jobProfileUser.getUser().getExternalId())) + .collectList() + .thenReturn(streamTask); } - private Mono postUserContacts(LegalEntityTask streamTask, List externalContacts, String externalUserId) { + private Mono postUserContacts(LegalEntityTask streamTask, List externalContacts, + String externalUserId) { if (isEmpty(externalContacts)) { log.info("Creating Contacts for User {}", externalUserId); streamTask.info(USER, PROCESS_CONTACTS, FAILED, externalUserId, null, - "User: %s does not have any Contacts", externalUserId); + "User: %s does not have any Contacts", externalUserId); return Mono.just(streamTask); } LegalEntity legalEntity = streamTask.getData(); log.info("Creating Contacts for User {}", externalUserId); return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), null, externalUserId, AccessContextScope.USER, externalContacts)) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private Mono upsertUserProfile(User user) { @@ -729,7 +778,8 @@ public Mono setupUserPermissions(LegalEntityTask legalEntityTas public Mono setupAdministratorPermissions(LegalEntityTask legalEntityTask) { // Assign permissions for the user for all business function groups. LegalEntity legalEntity = legalEntityTask.getData(); - Map>> request = nullableCollectionToStream(legalEntity.getUsers()) + Map>> request = nullableCollectionToStream( + legalEntity.getUsers()) .filter(jobProfileUser -> !isEmpty(jobProfileUser.getBusinessFunctionGroups())) .collect(Collectors.toMap( jobProfileUser -> setupAdminInternalId(legalEntity, jobProfileUser), @@ -772,7 +822,8 @@ public Mono upsertUser(LegalEntityTask streamTask, User user) { && !IdentityUserLinkStrategy.IDENTITY_AGNOSTIC.equals(user.getIdentityLinkStrategy())) { return upsertIdentityUser(streamTask, user); } else { - log.debug("Fallback to Identity Agnostic identityLinkStrategy. Either identity integration is disabled or User identityLinkStrategy is not set to identity."); + log.debug( + "Fallback to Identity Agnostic identityLinkStrategy. Either identity integration is disabled or User identityLinkStrategy is not set to identity."); return upsertUser(user, streamTask); } } @@ -782,14 +833,16 @@ private Mono upsertUserBulk(User user, LegalEntityTask streamTask) { streamTask.info(USER, UPSERT, "", user.getExternalId(), user.getInternalId(), "Upsert User with External ID: %s", user.getExternalId()); - Mono getExistingUser = Mono.zip(Mono.just(user), userService.getUserByExternalId(user.getExternalId()), (u, existingUser) -> { - u.setInternalId(existingUser.getInternalId()); - streamTask.info(USER, UPSERT, EXISTS, u.getExternalId(), u.getInternalId(), "User %s already exists", - existingUser.getExternalId()); - return u; - }); + Mono getExistingUser = Mono.zip(Mono.just(user), userService.getUserByExternalId(user.getExternalId()), + (u, existingUser) -> { + u.setInternalId(existingUser.getInternalId()); + streamTask.info(USER, UPSERT, EXISTS, u.getExternalId(), u.getInternalId(), "User %s already exists", + existingUser.getExternalId()); + return u; + }); - Mono createNewUser = Mono.zip(Mono.just(user), userService.createUser(user, legalEntity.getExternalId(), streamTask), + Mono createNewUser = Mono.zip(Mono.just(user), + userService.createUser(user, legalEntity.getExternalId(), streamTask), (u, newUser) -> { u.setInternalId(newUser.getInternalId()); streamTask.info(USER, UPSERT, CREATED, u.getExternalId(), user.getInternalId(), "User %s created", @@ -801,7 +854,8 @@ private Mono upsertUserBulk(User user, LegalEntityTask streamTask) { private Mono upsertUser(User user, LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); - streamTask.info(USER, UPSERT, "", user.getExternalId(), "Upsert User with External ID: %s", user.getExternalId()); + streamTask.info(USER, UPSERT, "", user.getExternalId(), "Upsert User with External ID: %s", + user.getExternalId()); Mono existingUser = userService.getUserByExternalId(user.getExternalId()).flatMap(existUser -> { user.setInternalId(existUser.getInternalId()); @@ -815,7 +869,8 @@ private Mono upsertUser(User user, LegalEntityTask streamTask) { }); }); - Mono createNewUser = Mono.zip(Mono.just(user), userService.createUser(user, legalEntity.getExternalId(), streamTask), + Mono createNewUser = Mono.zip(Mono.just(user), + userService.createUser(user, legalEntity.getExternalId(), streamTask), (u, newUser) -> { u.setInternalId(newUser.getInternalId()); streamTask.info(USER, UPSERT, CREATED, u.getExternalId(), user.getInternalId(), "User %s created", @@ -826,13 +881,14 @@ private Mono upsertUser(User user, LegalEntityTask streamTask) { } private Mono upsertIdentityUser(LegalEntityTask streamTask, User user) { - streamTask.info(IDENTITY_USER, UPSERT, "", user.getExternalId(), user.getInternalId(), - "Upsert User to Identity with External ID: %s", user.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, "", user.getExternalId(), user.getInternalId(), + "Upsert User to Identity with External ID: %s", user.getExternalId()); LegalEntity legalEntity = streamTask.getData(); Mono getExistingIdentityUser = userService.getUserByExternalId(user.getExternalId()) .map(existingUser -> { user.setInternalId(existingUser.getInternalId()); - streamTask.info(IDENTITY_USER, UPSERT, EXISTS, user.getExternalId(), user.getInternalId(), "User %s already exists", existingUser.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, EXISTS, user.getExternalId(), user.getInternalId(), + "User %s already exists", existingUser.getExternalId()); return user; }) .flatMap(userService::updateIdentity); @@ -842,7 +898,8 @@ private Mono upsertIdentityUser(LegalEntityTask streamTask, User user) { .flatMap(currentUser -> userService.updateUserState(currentUser, legalEntity.getRealmName())) .map(existingUser -> { user.setInternalId(existingUser.getInternalId()); - streamTask.info(IDENTITY_USER, UPSERT, CREATED, user.getExternalId(), user.getInternalId(), "User %s created", existingUser.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, CREATED, user.getExternalId(), user.getInternalId(), + "User %s created", existingUser.getExternalId()); return user; }); return getExistingIdentityUser.switchIfEmpty(createNewIdentityUser); @@ -854,7 +911,8 @@ private Mono setupServiceAgreement(LegalEntityTask streamTask) if (legalEntity.getCustomServiceAgreement() != null) { return setupCustomServiceAgreement(streamTask, legalEntity); - } else if (legalEntity.getMasterServiceAgreement() == null || StringUtils.isEmpty(legalEntity.getMasterServiceAgreement().getInternalId())) { + } else if (legalEntity.getMasterServiceAgreement() == null || StringUtils.isEmpty( + legalEntity.getMasterServiceAgreement().getInternalId())) { // Fetch existing master service agreement or create a new one return fetchExistingMasterServiceAgreement(legalEntity, streamTask) @@ -998,16 +1056,17 @@ private Mono setupCustomServiceAgreement(LegalEntityTask stream .getServiceAgreementByExternalId(newSa.getExternalId()) .flatMap(sa -> { newSa.setInternalId(sa.getInternalId()); - streamTask.info(SERVICE_AGREEMENT, SETUP_SERVICE_AGREEMENT, EXISTS, sa.getExternalId(), sa.getInternalId(), + streamTask.info(SERVICE_AGREEMENT, SETUP_SERVICE_AGREEMENT, EXISTS, sa.getExternalId(), + sa.getInternalId(), "Existing Service Agreement: %s found for Legal Entity: %s", sa.getExternalId(), legalEntity.getExternalId()); if (legalEntitySagaConfigurationProperties.isServiceAgreementUpdateEnabled()) { return accessGroupService.updateServiceAgreementItem(streamTask, newSa) - .then(accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions)) - .thenReturn(streamTask); + .then(accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions)) + .thenReturn(streamTask); } else { return accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions) - .thenReturn(streamTask); + .thenReturn(streamTask); } }); // As creatorLegalEntity doesnt accept external ID @@ -1064,7 +1123,7 @@ private ServiceAgreement createMasterServiceAgreement(LegalEntity legalEntity, @ } serviceAgreement.setIsMaster(true); - if(isEmpty(serviceAgreement.getParticipants())) { + if (isEmpty(serviceAgreement.getParticipants())) { serviceAgreement.addParticipantsItem(legalEntityParticipant); } @@ -1091,6 +1150,32 @@ private Mono processSubsidiaries(LegalEntityTask streamTask) { }); } +// private Mono processCustomerProfile(LegalEntityTask legalEntityTask) { +// //TODO: Uncomment when upsert party moder ready +// /*var parentLegalEntity = legalEntityTask.getData(); +// +// Flux parties = +// parentLegalEntity.getParties() == null ? Flux.empty() : Flux.fromIterable(parentLegalEntity.getParties()); +// var users = +// parentLegalEntity.getUsers() == null ? Flux.empty() : Flux.fromIterable(parentLegalEntity.getUsers()); +// +// parties.hasElements() +// .flatMap(hasParties -> { +// if (hasParties) { +// parties.flatMap(party -> { +// customerProfileService.upsertParty(party); +// return Mono.just(party); +// }).subscribe(); +// } +// legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, FAILED, +// parentLegalEntity.getInternalId(), parentLegalEntity.getExternalId(), +// "Legal Entity: %s does not have any parties defined", parentLegalEntity.getExternalId()); +// return Mono.just(legalEntityTask); +// });*/ +// +// return Mono.just(legalEntityTask); +// } + private Mono linkLegalEntityToRealm(LegalEntityTask streamTask) { return Mono.just(streamTask) .filter(task -> legalEntitySagaConfigurationProperties.isUseIdentityIntegration()) @@ -1109,7 +1194,7 @@ private ServiceAgreement retrieveServiceAgreement(LegalEntity legalEntity) { } private Flux setSubsidiaryParentLegalEntityId(LegalEntity parentLegalEntity, - Flux subsidiaries) { + Flux subsidiaries) { return subsidiaries.map(subsidiary -> { subsidiary.setParentExternalId(parentLegalEntity.getExternalId()); return subsidiary; @@ -1128,12 +1213,15 @@ private Mono setupLimits(LegalEntityTask streamTask) { private Mono setupLegalEntityLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); - if(isNull(legalEntity.getLimit()) || !validateLimit(legalEntity.getLimit())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", legalEntity.getExternalId()); + if (isNull(legalEntity.getLimit()) || !validateLimit(legalEntity.getLimit())) { + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", + legalEntity.getExternalId()); return Mono.just(streamTask); } - return limitsSaga.executeTask(createLimitsTask(streamTask, null, legalEntity.getInternalId(), legalEntity.getLimit())) + return limitsSaga.executeTask( + createLimitsTask(streamTask, null, legalEntity.getInternalId(), legalEntity.getLimit())) .flatMap(limitsTask -> requireNonNull(Mono.just(streamTask))) .then(Mono.just(streamTask)); } @@ -1141,44 +1229,49 @@ private Mono setupLegalEntityLimits(LegalEntityTask streamTask) private boolean validateLimit(Limit limit) { return nonNull(limit) && - (nonNull(limit.getTransactional()) || - nonNull(limit.getDaily()) || - nonNull(limit.getWeekly()) || - nonNull(limit.getMonthly()) || - nonNull(limit.getQuarterly()) || - nonNull(limit.getYearly())); + (nonNull(limit.getTransactional()) || + nonNull(limit.getDaily()) || + nonNull(limit.getWeekly()) || + nonNull(limit.getMonthly()) || + nonNull(limit.getQuarterly()) || + nonNull(limit.getYearly())); } private Mono setupLegalEntityLevelBusinessFunctionLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (isNull(legalEntity.getLimit()) || isEmpty(legalEntity.getLimit().getBusinessFunctionLimits())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", + legalEntity.getExternalId()); return Mono.just(streamTask); } return Flux.fromStream(legalEntity.getLimit().getBusinessFunctionLimits() .stream() .filter(businessFunctionLimit -> nonNull(businessFunctionLimit) - && !CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) - .flatMap(businessFunctionLimit -> createLimitsTask(streamTask, legalEntity.getInternalId(), businessFunctionLimit))) - .concatMap(limitsSaga::executeTask) - .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) - .collectList() - .map(tasks -> { - boolean failed = tasks.stream().anyMatch(StreamTask::isFailed); - if (failed) { - streamTask.setState(StreamTask.State.FAILED); - } else { - streamTask.setState(StreamTask.State.COMPLETED); - } - return streamTask; - }); + && !CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) + .flatMap(businessFunctionLimit -> createLimitsTask(streamTask, legalEntity.getInternalId(), + businessFunctionLimit))) + .concatMap(limitsSaga::executeTask) + .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) + .collectList() + .map(tasks -> { + boolean failed = tasks.stream().anyMatch(StreamTask::isFailed); + if (failed) { + streamTask.setState(StreamTask.State.FAILED); + } else { + streamTask.setState(StreamTask.State.COMPLETED); + } + return streamTask; + }); } private Mono setupServiceAgreementLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); if (isNull(serviceAgreement.getLimit())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Service Agreement limits defined", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), "Legal Entity: %s does not have any Service Agreement limits defined", + legalEntity.getExternalId()); return Mono.just(streamTask); } return limitsSaga.executeTask(createLimitsTask(streamTask, serviceAgreement, null, serviceAgreement.getLimit())) @@ -1186,9 +1279,10 @@ private Mono setupServiceAgreementLimits(LegalEntityTask stream .then(Mono.just(streamTask)); } - private Stream createLimitsTask(LegalEntityTask streamTask, String legalEntityId, BusinessFunctionLimit businessFunctionLimit) { + private Stream createLimitsTask(LegalEntityTask streamTask, String legalEntityId, + BusinessFunctionLimit businessFunctionLimit) { - if(isNull(businessFunctionLimit) || CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())){ + if (isNull(businessFunctionLimit) || CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) { return Stream.of(); } return businessFunctionLimit.getPrivileges() @@ -1197,28 +1291,31 @@ private Stream createLimitsTask(LegalEntityTask streamTask, String l .map(privilege -> { var limitData = new CreateLimitRequestBody(); var entities = new ArrayList(); - ofNullable(legalEntityId).ifPresent(le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); + ofNullable(legalEntityId).ifPresent( + le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); ofNullable(businessFunctionLimit.getFunctionId()) - .ifPresent(functionId -> entities.add(new Entity().etype(FUNCTION_E_TYPE).eref(functionId))); + .ifPresent(functionId -> entities.add(new Entity().etype(FUNCTION_E_TYPE).eref(functionId))); ofNullable(privilege.getPrivilege()) - .ifPresent(prv -> entities.add(new Entity().etype(PRIVILEGE_E_TYPE).eref(prv))); + .ifPresent(prv -> entities.add(new Entity().etype(PRIVILEGE_E_TYPE).eref(prv))); limitData.entities(entities); Optional.of(privilege) .map(Privilege::getLimit).ifPresent(limit -> limitData.periodicLimitsBounds(periodicLimits(limit)) - .transactionalLimitsBound(transactionalLimits(limit)) - .shadow(businessFunctionLimit.getShadow()) - .currency(limit.getCurrencyCode())); + .transactionalLimitsBound(transactionalLimits(limit)) + .shadow(businessFunctionLimit.getShadow()) + .currency(limit.getCurrencyCode())); return new LimitsTask(streamTask.getId() + "-" + LEGAL_ENTITY_LIMITS, limitData); }); } - private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement serviceAgreement, String legalEntityId, Limit limit) { + private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement serviceAgreement, + String legalEntityId, Limit limit) { var limitData = new CreateLimitRequestBody(); var entities = new ArrayList(); ofNullable(legalEntityId).ifPresent(le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); - ofNullable(serviceAgreement).ifPresent(sa -> entities.add(new Entity().etype(SERVICE_AGREEMENT_E_TYPE).eref(sa.getInternalId()))); + ofNullable(serviceAgreement).ifPresent( + sa -> entities.add(new Entity().etype(SERVICE_AGREEMENT_E_TYPE).eref(sa.getInternalId()))); limitData.entities(entities); limitData.periodicLimitsBounds(periodicLimits(limit)) .transactionalLimitsBound(transactionalLimits(limit)) @@ -1230,14 +1327,21 @@ private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement private Mono setupServiceAgreementParticipantLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); - if(isNull(serviceAgreement.getParticipants()) - || serviceAgreement.getParticipants().stream().noneMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Participant with Limits in Service Agreement", legalEntity.getExternalId()); + if (isNull(serviceAgreement.getParticipants()) + || serviceAgreement.getParticipants().stream() + .noneMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) { + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), + legalEntity.getExternalId(), + "Legal Entity: %s does not have any Participant with Limits in Service Agreement", + legalEntity.getExternalId()); return Mono.just(streamTask); } return accessGroupService.getServiceAgreementParticipants(streamTask, serviceAgreement) - .filter(participant -> serviceAgreement.getParticipants().stream().filter(p -> p.getExternalId().equalsIgnoreCase(participant.getExternalId())).anyMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) - .flatMapIterable(participant -> List.of(createLimitsTask(streamTask, serviceAgreement, participant.getId(), getLimits(serviceAgreement, participant)))) + .filter(participant -> serviceAgreement.getParticipants().stream() + .filter(p -> p.getExternalId().equalsIgnoreCase(participant.getExternalId())) + .anyMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) + .flatMapIterable(participant -> List.of(createLimitsTask(streamTask, serviceAgreement, participant.getId(), + getLimits(serviceAgreement, participant)))) .flatMap(limitsSaga::executeTask) .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) .collectList() @@ -1252,9 +1356,11 @@ private Mono setupServiceAgreementParticipantLimits(LegalEntity }); } - private Limit getLimits(ServiceAgreement serviceAgreement, ServiceAgreementParticipantsGetResponseBody participant) { + private Limit getLimits(ServiceAgreement serviceAgreement, + ServiceAgreementParticipantsGetResponseBody participant) { return serviceAgreement.getParticipants().stream() - .filter(legalEntityParticipant -> legalEntityParticipant.getExternalId().equalsIgnoreCase(participant.getExternalId())) + .filter(legalEntityParticipant -> legalEntityParticipant.getExternalId() + .equalsIgnoreCase(participant.getExternalId())) .map(LegalEntityParticipant::getLimit) .findFirst().orElseGet(Limit::new); } @@ -1280,14 +1386,15 @@ && noLimitsInJobRole(legalEntity.getReferenceJobRoles())) { .filter(jobProfileUser -> nonNull(jobProfileUser.getUser()) && nonNull( jobProfileUser.getUser().getSupportsLimit()) && !isEmpty(jobProfileUser.getReferenceJobRoleNames())) .forEach(jobProfileUser -> jobProfileUser.getReferenceJobRoleNames().forEach(jobRoleName -> { - if(userJobRoleMap.get(jobRoleName) != null) { - var users = userJobRoleMap.get(jobRoleName); - users.add(jobProfileUser.getUser().getInternalId()); - userJobRoleMap.put(jobRoleName, users); - } else { - userJobRoleMap.put(jobRoleName, new HashSet<>(List.of(jobProfileUser.getUser().getInternalId()))); - } - })); + if (userJobRoleMap.get(jobRoleName) != null) { + var users = userJobRoleMap.get(jobRoleName); + users.add(jobProfileUser.getUser().getInternalId()); + userJobRoleMap.put(jobRoleName, users); + } else { + userJobRoleMap.put(jobRoleName, + new HashSet<>(List.of(jobProfileUser.getUser().getInternalId()))); + } + })); } return Flux.fromStream(Stream.of(serviceAgreement.getJobRoles(), legalEntity.getReferenceJobRoles()) @@ -1310,20 +1417,24 @@ && noLimitsInJobRole(legalEntity.getReferenceJobRoles())) { private Mono retrieveUsersInternalIds(LegalEntityTask streamTask) { var le = streamTask.getData(); - if(le.getProductGroups() == null || le.getProductGroups().stream().allMatch(productGroup -> Objects.isNull(productGroup.getUsers())) + if (le.getProductGroups() == null || le.getProductGroups().stream() + .allMatch(productGroup -> Objects.isNull(productGroup.getUsers())) || le.getProductGroups().stream().filter(productGroup -> nonNull(productGroup.getUsers())) .flatMap(productGroup -> productGroup.getUsers().stream()) - .noneMatch(jobProfileUser -> nonNull(jobProfileUser) && nonNull(jobProfileUser.getUser()) && nonNull(jobProfileUser.getUser().getSupportsLimit()) && jobProfileUser.getUser().getSupportsLimit())) { + .noneMatch(jobProfileUser -> nonNull(jobProfileUser) && nonNull(jobProfileUser.getUser()) && nonNull( + jobProfileUser.getUser().getSupportsLimit()) && jobProfileUser.getUser().getSupportsLimit())) { return Mono.just(streamTask); } - var users = le.getProductGroups().stream().flatMap(productGroup -> productGroup.getUsers().stream()).collect(Collectors.toSet()); + var users = le.getProductGroups().stream().flatMap(productGroup -> productGroup.getUsers().stream()) + .collect(Collectors.toSet()); return Flux.fromIterable(users) .flatMap(jpu -> accessGroupService.getUserByExternalId(jpu.getUser().getExternalId(), true)) .collectList() .flatMap(internalUsers -> { Map usersByExternalId = - internalUsers.stream().collect(Collectors.toMap(GetUser::getExternalId, Function.identity(), (a1, a2) -> a1)); + internalUsers.stream() + .collect(Collectors.toMap(GetUser::getExternalId, Function.identity(), (a1, a2) -> a1)); users.forEach(jp -> { String externalId = jp.getUser().getExternalId(); GetUser internalUser = usersByExternalId.get(externalId); @@ -1339,8 +1450,9 @@ private List createLimitsTask(LegalEntityTask streamTask, JobRole ac ServiceAgreement serviceAgreement, Map> userJobRoleMap) { List userJobRoleLimits = new ArrayList<>(); - if(!CollectionUtils.isEmpty(userJobRoleMap) && userJobRoleMap.containsKey(actual.getName())) { - userJobRoleMap.get(actual.getName()).forEach(userId -> userJobRoleLimits.addAll(actual.getFunctionGroups().stream() + if (!CollectionUtils.isEmpty(userJobRoleMap) && userJobRoleMap.containsKey(actual.getName())) { + userJobRoleMap.get(actual.getName()) + .forEach(userId -> userJobRoleLimits.addAll(actual.getFunctionGroups().stream() .filter(this::limitsExist) .flatMap(businessFunctionGroup -> businessFunctionGroup.getFunctions().stream() .flatMap(businessFunction -> businessFunction.getPrivileges().stream() @@ -1351,7 +1463,7 @@ private List createLimitsTask(LegalEntityTask streamTask, JobRole ac businessFunction, privilege, actual.getId(), userId)))) .map(limitData -> new LimitsTask(streamTask.getId() + "-" + USER_JOB_ROLE_LIMITS, limitData)) .collect(Collectors.toList()))); - } + } var jobRoleLimits = actual.getFunctionGroups().stream() .filter(this::limitsExist) diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java index d39239923..3609e5376 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java @@ -1,5 +1,6 @@ package com.backbase.stream.configuration; +import com.backbase.configuration.CustomerProfileConfiguration; import com.backbase.stream.LegalEntitySaga; import com.backbase.stream.LegalEntitySagaV2; import com.backbase.stream.LegalEntityTask; @@ -13,6 +14,7 @@ import com.backbase.stream.product.ProductIngestionSagaConfiguration; import com.backbase.stream.product.configuration.ProductConfiguration; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.stream.service.LegalEntityService; import com.backbase.stream.service.UserProfileService; import com.backbase.stream.service.UserService; @@ -34,8 +36,8 @@ ContactsServiceConfiguration.class, LoansServiceConfiguration.class, AudiencesSegmentationConfiguration.class, - PlanServiceConfiguration.class - + PlanServiceConfiguration.class/*, + CustomerProfileConfiguration.class*/ }) @EnableConfigurationProperties( {LegalEntitySagaConfigurationProperties.class} @@ -51,7 +53,8 @@ public LegalEntitySaga reactiveLegalEntitySaga(LegalEntityService legalEntitySer LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties sinkConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga + UserKindSegmentationSaga userKindSegmentationSaga/*, + CustomerProfileService customerProfileService*/ ) { return new LegalEntitySaga( legalEntityService, @@ -62,7 +65,8 @@ public LegalEntitySaga reactiveLegalEntitySaga(LegalEntityService legalEntitySer limitsSaga, contactsSaga, sinkConfigurationProperties, - userKindSegmentationSaga + userKindSegmentationSaga/*, + customerProfileService*/ ); } diff --git a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java index df271a0b5..ed159cc8a 100644 --- a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java +++ b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java @@ -7,6 +7,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.dbs.accesscontrol.api.service.v3.LegalEntitiesApi; import com.backbase.dbs.accesscontrol.api.service.v3.model.FunctionGroupItem; import com.backbase.dbs.arrangement.api.service.v3.ArrangementsApi; @@ -35,6 +36,7 @@ import com.backbase.stream.product.task.BatchProductGroupTask; import com.backbase.stream.product.task.ProductGroupTask; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.streams.tailoredvalue.PlansService; import java.net.URI; import java.util.List; @@ -82,6 +84,9 @@ class ServiceAgreementControllerTest { @MockBean private com.backbase.identity.integration.api.service.ApiClient identityApiClient; + @MockBean + private com.backbase.customerprofile.api.integration.ApiClient customerProfileApiClient; + @MockBean private LimitsServiceApi limitsApi; @@ -106,6 +111,9 @@ class ServiceAgreementControllerTest { @MockBean private UserProfileManagementApi userProfileManagementApi; + @MockBean + private PartyManagementIntegrationApi partyManagementIntegrationApi; + @MockBean private com.backbase.dbs.user.profile.api.service.v2.UserProfileManagementApi userProfileManagement; @@ -121,6 +129,9 @@ class ServiceAgreementControllerTest { @MockBean private PlansService plansService; + @MockBean + private CustomerProfileService customerProfileService; + @Autowired private WebTestClient webTestClient; diff --git a/stream-sdk/stream-parent/stream-test-support/pom.xml b/stream-sdk/stream-parent/stream-test-support/pom.xml index dee26ffb9..52e026d05 100644 --- a/stream-sdk/stream-parent/stream-test-support/pom.xml +++ b/stream-sdk/stream-parent/stream-test-support/pom.xml @@ -25,6 +25,12 @@ 1.2 + + com.navercorp.fixturemonkey + fixture-monkey-starter + 1.1.11 + + org.iban4j iban4j @@ -88,12 +94,6 @@ service-sdk-starter-test test - - - com.navercorp.fixturemonkey - fixture-monkey-starter - 1.1.11 - From 71e40565297dee801292b2b05a6ed24211d74453 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 14:14:05 +0200 Subject: [PATCH 09/41] Refactor package structure and update CustomerProfileService references in LegalEntitySaga --- .../CustomerProfileConfiguration.java | 2 +- .../stream/configuration/package-info.java | 1 + .../backbase/stream/service/package-info.java | 1 + .../com/backbase/stream/LegalEntitySaga.java | 13 ++++++------- .../LegalEntitySagaConfiguration.java | 17 ++++++++--------- .../ServiceAgreementControllerTest.java | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) rename stream-customer-profile/customer-profile-core/src/main/java/com/backbase/{ => stream}/configuration/CustomerProfileConfiguration.java (94%) create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/package-info.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/package-info.java diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java similarity index 94% rename from stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java rename to stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java index d19a4ffff..fd781cbfc 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/configuration/CustomerProfileConfiguration.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java @@ -1,4 +1,4 @@ -package com.backbase.configuration; +package com.backbase.stream.configuration; import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.stream.clients.config.CustomerProfileClientConfig; diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/package-info.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/package-info.java new file mode 100644 index 000000000..3b4bde136 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/package-info.java @@ -0,0 +1 @@ +package com.backbase.stream.configuration; \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/package-info.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/package-info.java new file mode 100644 index 000000000..29590942e --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/package-info.java @@ -0,0 +1 @@ +package com.backbase.stream.service; \ No newline at end of file diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index 188bd23ec..d8e15282c 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -47,7 +47,6 @@ import com.backbase.stream.legalentity.model.LegalEntityStatus; import com.backbase.stream.legalentity.model.LegalEntityType; import com.backbase.stream.legalentity.model.Limit; -import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.legalentity.model.Privilege; import com.backbase.stream.legalentity.model.ProductGroup; import com.backbase.stream.legalentity.model.ServiceAgreement; @@ -137,7 +136,7 @@ public class LegalEntitySaga implements StreamTaskExecutor { private static final String JOB_ROLE_LIMITS = "job-role-limits"; private static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; - // private static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; + private static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper( @@ -153,7 +152,7 @@ public class LegalEntitySaga implements StreamTaskExecutor { private final ContactsSaga contactsSaga; private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties; private final UserKindSegmentationSaga userKindSegmentationSaga; - // private final CustomerProfileService customerProfileService; + private final CustomerProfileService customerProfileService; private static final ExternalContactMapper externalContactMapper = ExternalContactMapper.INSTANCE; public LegalEntitySaga( @@ -165,8 +164,8 @@ public LegalEntitySaga( LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga - /* CustomerProfileService customerProfileService*/) { + UserKindSegmentationSaga userKindSegmentationSaga, + CustomerProfileService customerProfileService) { this.legalEntityService = legalEntityService; this.userService = userService; this.userProfileService = userProfileService; @@ -176,7 +175,7 @@ public LegalEntitySaga( this.contactsSaga = contactsSaga; this.legalEntitySagaConfigurationProperties = legalEntitySagaConfigurationProperties; this.userKindSegmentationSaga = userKindSegmentationSaga; - // this.customerProfileService = customerProfileService; + this.customerProfileService = customerProfileService; } @Override @@ -590,7 +589,7 @@ private Mono createJobRoles(LegalEntityTask streamTask) { log.info("Creating Job Roles..."); return Flux.fromStream(Stream.of(serviceAgreement.getJobRoles(), legalEntity.getReferenceJobRoles()) - .filter(Objects::nonNull) + .filter(Objects::nonNull) .flatMap(Collection::stream)) .flatMap(jobRole -> accessGroupService.setupJobRole(streamTask, serviceAgreement, jobRole)) .flatMap(jobRole -> { diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java index 3609e5376..6e2b0841c 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java @@ -1,6 +1,5 @@ package com.backbase.stream.configuration; -import com.backbase.configuration.CustomerProfileConfiguration; import com.backbase.stream.LegalEntitySaga; import com.backbase.stream.LegalEntitySagaV2; import com.backbase.stream.LegalEntityTask; @@ -19,8 +18,8 @@ import com.backbase.stream.service.UserProfileService; import com.backbase.stream.service.UserService; import com.backbase.stream.worker.repository.impl.InMemoryReactiveUnitOfWorkRepository; -import com.backbase.streams.tailoredvalue.configuration.PlanServiceConfiguration; import com.backbase.streams.tailoredvalue.PlansService; +import com.backbase.streams.tailoredvalue.configuration.PlanServiceConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -36,8 +35,8 @@ ContactsServiceConfiguration.class, LoansServiceConfiguration.class, AudiencesSegmentationConfiguration.class, - PlanServiceConfiguration.class/*, - CustomerProfileConfiguration.class*/ + PlanServiceConfiguration.class, + CustomerProfileConfiguration.class }) @EnableConfigurationProperties( {LegalEntitySagaConfigurationProperties.class} @@ -53,8 +52,8 @@ public LegalEntitySaga reactiveLegalEntitySaga(LegalEntityService legalEntitySer LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties sinkConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga/*, - CustomerProfileService customerProfileService*/ + UserKindSegmentationSaga userKindSegmentationSaga, + CustomerProfileService customerProfileService ) { return new LegalEntitySaga( legalEntityService, @@ -65,8 +64,8 @@ public LegalEntitySaga reactiveLegalEntitySaga(LegalEntityService legalEntitySer limitsSaga, contactsSaga, sinkConfigurationProperties, - userKindSegmentationSaga/*, - customerProfileService*/ + userKindSegmentationSaga, + customerProfileService ); } @@ -107,7 +106,7 @@ public ServiceAgreementSagaV2 reactiveServiceAgreementV2Saga(LegalEntityService batchProductIngestionSaga, limitsSaga, contactsSaga, - plansService, + plansService, sinkConfigurationProperties ); } diff --git a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java index ed159cc8a..a4907522a 100644 --- a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java +++ b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java @@ -19,6 +19,7 @@ import com.backbase.dbs.user.api.service.v2.model.GetUser; import com.backbase.loan.inbound.api.service.v1.LoansApi; import com.backbase.stream.audiences.UserKindSegmentationSaga; +import com.backbase.stream.clients.config.CustomerProfileClientConfig; import com.backbase.stream.config.LegalEntityHttpConfiguration; import com.backbase.stream.configuration.LegalEntitySagaConfiguration; import com.backbase.stream.configuration.UpdatedServiceAgreementSagaConfiguration; @@ -36,7 +37,6 @@ import com.backbase.stream.product.task.BatchProductGroupTask; import com.backbase.stream.product.task.ProductGroupTask; import com.backbase.stream.service.AccessGroupService; -import com.backbase.stream.service.CustomerProfileService; import com.backbase.streams.tailoredvalue.PlansService; import java.net.URI; import java.util.List; @@ -130,7 +130,7 @@ class ServiceAgreementControllerTest { private PlansService plansService; @MockBean - private CustomerProfileService customerProfileService; + private CustomerProfileClientConfig customerProfileClientConfig; @Autowired private WebTestClient webTestClient; From 442b19c01edcdd818411a5e93597c359598cbecb Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 15:35:44 +0200 Subject: [PATCH 10/41] Enhance OpenAPI schema with detailed descriptions and new properties for party and identification entities --- api/stream-legal-entity/openapi.yaml | 201 ++++++++++++++++++++++----- 1 file changed, 166 insertions(+), 35 deletions(-) diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index 0932b5c0b..65f7fa589 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1257,8 +1257,13 @@ components: type: boolean isCustomer: type: boolean + description: Indicates if it is a customer or not. partyType: type: string + enum: + - PERSON + - ORGANISATION + description: Type of party in different business contexts. person: $ref: '#/components/schemas/Person' organisation: @@ -1267,22 +1272,31 @@ components: type: array items: $ref: '#/components/schemas/PartyRelationship' - organisationName: - type: string closingDateTime: type: string - format: date + format: date-time + description: Date on which the party and related services cease effectively to be operational for the party. approvedDateTime: type: string - format: date + format: date-time + description: Date on which the party and related basic services are approved. lastUpdatedDateTime: type: string - format: date + format: date-time + description: Date on which there was any update to the party and related basic services. openingDateTime: type: string - format: date - status: + format: date-time + description: Date on which the party and related basic services are effectively operational for the party. + liveDateTime: + type: string + format: date-time + description: Date of the first movement on the party. + state: type: string + enum: + - ENROLLED + - EXITED postalAddresses: type: array items: @@ -1297,110 +1311,227 @@ components: $ref: '#/components/schemas/ElectronicAddress' preferredLanguage: type: string - description: Language code, e.g. en, de, fr, nl + maxLength: 50 + description: Language preferred by party. notes: - type: array - items: - type: string + type: string + maxLength: 100 + description: Notes on the party. customFields: type: object additionalProperties: type: string + required: + - partyId + - isCustomer + - partyType Person: type: object properties: identifications: type: array + description: List of specific identification assigned to a party. + minItems: 1 items: $ref: '#/components/schemas/Identification' personName: $ref: '#/components/schemas/PersonName' gender: type: string + enum: + - MALE + - FEMALE + - NON_BINARY + description: Person's gender birthDate: type: string format: date + description: Indicates person birthdate demographics: type: object properties: occupation: type: object properties: - employer: - type: string employment: type: string + description: Type of employment of the party. + maxLength: 100 + employer: + type: string + description: Details of the party's employment. + maxLength: 100 education: type: object properties: - yearOfPassing: - type: string educationLevel: type: string + description: Party's education level, such as qualifications and certifications. + maxLength: 100 + yearOfPassing: + type: string + maxLength: 20 + description: Year of completing the qualification. + required: + - personName + - identifications Organisation: type: object properties: - legalStructureType: - type: string - establishmentDate: - type: string name: type: string + description: Organisation Name + maxLength: 64 type: type: string + maxLength: 64 + description: Specifies a type of organisation. sector: type: string - liveDateTime: + maxLength: 255 + description: Sector of business of the organisation, for example, pharmaceutical. (ISO20022) + establishmentDate: type: string format: date + description: Date when the organisation was established. + legalStructure: + type: object + properties: + type: + type: string + maxLength: 64 + description: Individual, Partnership and Corporation + required: + - type identifications: type: array + description: List of specific identification assigned to a party. + minItems: 1 items: $ref: '#/components/schemas/Identification' + required: + - name + - identifications Identification: type: object properties: - expiryDate: + identificationType: type: string - format: date + enum: + - TaxIdentificationNumber + - NationalRegistrationNumber + - RegistrationAuthorityIdentification + - LegalEntityIdentifier + - AlienRegistrationNumber + - PassportNumber + - TaxExemptionIdentificationNumber + - CorporateIdentification + - DriverLicenseNumber + - ForeignInvestmentIdentityNumber + - SocialSecurityNumber + - IdentityCardNumber + - Concat + - NationalRegistrationIdentificationNumber + - CustomerIdentificationNumber + - EmployeeIdentificationNumber + - NationalIdentityNumber + - TelephoneNumber + - EmployerIdentificationNumber + - CentralBankIdentificationNumber + - ClearingIdentificationNumber + - BankPartyIdentification + - CertificateOfIncorporationNumber + - CountryIdentificationCode + - CustomerNumber + - DataUniversalNumberingSystem + - GS1GLNIdentifier + - ELF + - SIREN + - SIRET + - MIC + - BICFI + - DUNS + - EANGLN + description: Identification Type of the identity document. + identificationNumber: + type: string + maxLength: 100 + description: Number or code assigned by the government authority to an entity issuingCountry: type: string + maxLength: 100 + description: Identifies issuing country of the identity document. issuingAuthority: type: string - identificationNumber: - type: string - identificationType: - type: string + maxLength: 100 + description: Identifies issuing authority of the identity document. issueDate: type: string format: date + description: Identifies issue date of the identity document. + expiryDate: + type: string + format: date + description: Identifies expiry date of the identity document. + required: + - identificationType + - identificationNumber PartyRelationship: type: object properties: + partyId: + $ref: '#/components/schemas/ExternalIdentifier' + partyType: + type: string + enum: + - PERSON + - ORGANISATION + description: Specifies the type of party in different business contexts. partyRole: type: string - ownershipPercent: - type: number - format: double - roleEndDate: + description: Identifies role of a party + enum: + - COMPANY_ROLE + - COMPANY_OWNERSHIP + - COMPANY_CONTROL_PERSON + - COMPANY_SIGNATORY + - GUARDIAN + roleStartDate: type: string format: date - partyId: - $ref: '#/components/schemas/ExternalIdentifier' - roleStartDate: + description: Identifies start date of the party role + roleEndDate: type: string format: date + description: Identifies end date of the party role + ownershipPercent: + type: integer + description: Identifies the percentage of stake/ownership for a related person/organisation in this organisation. Total ownership percent must not exceed 100% + minimum: 0 + maximum: 100 + required: + - partyId + - partyRole PersonName: type: object properties: + salutation: + type: string + maxLength: 20 firstName: type: string + description: First name of the person. + maxLength: 64 middleName: type: string + description: Middle name of the person. + maxLength: 64 familyName: type: string - salutation: - type: string + description: Family name of the person. + maxLength: 64 + required: + - firstName LegalEntityType: type: string From e7d88b9edba03ba3843192f31f16c8c9e11e44ee Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 18:27:29 +0200 Subject: [PATCH 11/41] Implement upsertParty method in CustomerProfileService and enhance processCustomerProfile in LegalEntitySaga --- .../service/CustomerProfileService.java | 7 +- .../com/backbase/stream/LegalEntitySaga.java | 82 ++++--- .../backbase/stream/LegalEntitySagaTest.java | 225 +++++++++++------- 3 files changed, 199 insertions(+), 115 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 8bac27855..0d6f7b688 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -26,7 +26,10 @@ public Mono upsertParty(PartyUpsertDto partyUpsertDto) log.info("Customer profile created successfully: {}", customerResponseDto)); } - public Mono upsertParty(Party party) { - return Mono.firstWithSignal(); + public Mono upsertParty(Party party) { + + // TODO: Implement the conversion from Party to PartyUpsertDto + + return upsertParty(new PartyUpsertDto()); } } diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index d8e15282c..b243c5a91 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -83,6 +83,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -127,6 +128,8 @@ public class LegalEntitySaga implements StreamTaskExecutor { public static final String UPSERT = "upsert"; public static final String SETUP_SERVICE_AGREEMENT = "setup-service-agreement"; private static final String BATCH_PRODUCT_GROUP_ID = "batch_product_group_task-"; + public static final String PARTY = "party"; + public static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; private static final String LEGAL_ENTITY_E_TYPE = "LE"; private static final String SERVICE_AGREEMENT_E_TYPE = "SA"; @@ -136,7 +139,6 @@ public class LegalEntitySaga implements StreamTaskExecutor { private static final String JOB_ROLE_LIMITS = "job-role-limits"; private static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; - private static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper( @@ -193,7 +195,7 @@ public Mono executeTask(@SpanTag(value = "streamTask") LegalEnt .flatMap(this::processProducts) .flatMap(this::postContacts) .flatMap(this::processSubsidiaries) - /*.flatMap(this::processCustomerProfile)*/; + .flatMap(this::processCustomerProfile); } private Mono processAudiencesSegmentation(LegalEntityTask streamTask) { @@ -1149,31 +1151,57 @@ private Mono processSubsidiaries(LegalEntityTask streamTask) { }); } -// private Mono processCustomerProfile(LegalEntityTask legalEntityTask) { -// //TODO: Uncomment when upsert party moder ready -// /*var parentLegalEntity = legalEntityTask.getData(); -// -// Flux parties = -// parentLegalEntity.getParties() == null ? Flux.empty() : Flux.fromIterable(parentLegalEntity.getParties()); -// var users = -// parentLegalEntity.getUsers() == null ? Flux.empty() : Flux.fromIterable(parentLegalEntity.getUsers()); -// -// parties.hasElements() -// .flatMap(hasParties -> { -// if (hasParties) { -// parties.flatMap(party -> { -// customerProfileService.upsertParty(party); -// return Mono.just(party); -// }).subscribe(); -// } -// legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, FAILED, -// parentLegalEntity.getInternalId(), parentLegalEntity.getExternalId(), -// "Legal Entity: %s does not have any parties defined", parentLegalEntity.getExternalId()); -// return Mono.just(legalEntityTask); -// });*/ -// -// return Mono.just(legalEntityTask); -// } + private Mono processCustomerProfile(LegalEntityTask legalEntityTask) { + + log.info("Processing Customer Profile Parties for: {}", legalEntityTask.getName()); + var legalEntity = legalEntityTask.getData(); + + if (isEmpty(legalEntity.getParties())) { + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntity.getExternalId(), + legalEntity.getInternalId(), "No parties found in Legal Entity to process."); + return Mono.just(legalEntityTask); + } + var processingErrors = new CopyOnWriteArrayList<>(); + + return Flux.fromStream(nullableCollectionToStream(legalEntity.getParties())) + .filter(Objects::nonNull) + .concatMap(party -> { + log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); + return customerProfileService.upsertParty(party) + .doOnSuccess(result -> { + legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, + "Successfully upserted party: %s for LE: %s", party.getPartyId(), + legalEntity.getExternalId()); + }) + .onErrorResume(throwable -> { + log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), + throwable); + processingErrors.add(throwable); + legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, + throwable, + throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), + legalEntity.getExternalId()); + return Mono.empty(); + }) + .then(Mono.just(true)); + }) + .then(Mono.fromRunnable(() -> { + if (!processingErrors.isEmpty()) { + log.warn("Completed processing parties for LE {} with {} errors.", legalEntity.getExternalId(), + processingErrors.size()); + legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", + legalEntity.getExternalId(), + legalEntity.getInternalId(), "Party processing completed with %d errors.", + processingErrors.size()); + } else { + log.info("Successfully processed all parties for LE {}.", legalEntity.getExternalId()); + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", + legalEntity.getExternalId(), + legalEntity.getInternalId(), "Party processing completed successfully."); + } + })) + .thenReturn(legalEntityTask); + } private Mono linkLegalEntityToRealm(LegalEntityTask streamTask) { return Mono.just(streamTask) diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 0db62d36f..aa499deb0 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -5,12 +5,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.Mockito.lenient; +import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; import com.backbase.dbs.accesscontrol.api.service.v3.model.ServiceAgreementParticipantsGetResponseBody; import com.backbase.dbs.contact.api.service.v2.model.AccessContextScope; import com.backbase.dbs.contact.api.service.v2.model.ContactsBulkPostRequestBody; @@ -45,6 +46,7 @@ import com.backbase.stream.legalentity.model.Limit; import com.backbase.stream.legalentity.model.Loan; import com.backbase.stream.legalentity.model.Multivalued; +import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.legalentity.model.PhoneNumber; import com.backbase.stream.legalentity.model.Privilege; import com.backbase.stream.legalentity.model.ProductGroup; @@ -58,10 +60,15 @@ import com.backbase.stream.product.task.BatchProductGroupTask; import com.backbase.stream.product.task.ProductGroupTask; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.stream.service.LegalEntityService; import com.backbase.stream.service.UserProfileService; import com.backbase.stream.service.UserService; import com.backbase.stream.worker.exception.StreamTaskException; +import com.navercorp.fixturemonkey.FixtureMonkey; +import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; +import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; +import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; import java.math.BigDecimal; import java.nio.charset.Charset; import java.time.Duration; @@ -73,6 +80,8 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.arbitraries.StringArbitrary; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -122,10 +131,25 @@ class LegalEntitySagaTest { @Mock private UserKindSegmentationSaga userKindSegmentationSaga; + @Mock + private CustomerProfileService customerProfileService; + @Spy private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties = getLegalEntitySagaConfigurationProperties(); + private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) + .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { + @Override + public StringArbitrary strings() { + return Arbitraries.strings().alpha(); + } + })) + .build(); + + private static final int PARTY_SIZE = 10; + String leExternalId = "someLeExternalId"; String leParentExternalId = "someParentLeExternalId"; String leInternalId = "someLeInternalId"; @@ -152,12 +176,14 @@ void customServiceAgreementCreation() { .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); - legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).addAdministratorsItem(adminUser) + legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId) + .addAdministratorsItem(adminUser) .parentExternalId(leParentExternalId).customServiceAgreement(customSa).users(singletonList(regularUser)) .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -168,7 +194,8 @@ void customServiceAgreementCreation() { when(accessGroupService.getServiceAgreementByExternalId(eq(customSaExId))).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( + Mono.just(customSa)); when(userService.getUserByExternalId(eq(regularUserExId))).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(eq(adminExId))).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -252,16 +279,19 @@ void masterServiceAgreementCreation() { BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).parentExternalId(leExternalId) - .activateSingleServiceAgreement(false).masterServiceAgreement(sa).productGroups(singletonList(productGroup)); + .activateSingleServiceAgreement(false).masterServiceAgreement(sa) + .productGroups(singletonList(productGroup)); LegalEntityTask task = mockLegalEntityTask(legalEntity); when(task.getLegalEntity()).thenReturn(legalEntity); when(legalEntityService.getLegalEntityByExternalId(eq(leExternalId))).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(eq(leInternalId))).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn(Mono.just(sa)); + when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn( + Mono.just(sa)); when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(legalEntity)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))) @@ -301,14 +331,16 @@ void masterServiceAgreementCreation_activateSingleServiceAgreement() { JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).parentExternalId(leExternalId) .productGroups(singletonList(productGroup)); - ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); LegalEntityTask task = mockLegalEntityTask(legalEntity); when(task.getLegalEntity()).thenReturn(legalEntity); when(legalEntityService.getLegalEntityByExternalId(eq(leExternalId))).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(eq(leInternalId))).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn(Mono.empty()); + when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn( + Mono.empty()); when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(legalEntity)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); when(accessGroupService.createServiceAgreement(any(), any())).thenReturn(Mono.just(sa)); @@ -388,6 +420,17 @@ void testCustomServiceAgreement_IfNoUserDataFoundWhileServiceAgreementFetch_thro verifyUserService(); } + @Test + void testProcessCustomerProfile_IfPartyFound_ThenUpsertParty() { + var task = setupLegalEntityTask(); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + mockAccessGroupService(userId); + mockUserService(userId); + legalEntitySaga.executeTask(task).block(); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class)); + } + private void mockUserService(String userId) { when(userService.getUsersByLegalEntity(any(), anyInt(), anyInt())) .thenReturn(Mono.just(new GetUsersList().totalElements(1L) @@ -427,6 +470,7 @@ private LegalEntityTask setupLegalEntityTask() { legalEntity.setExternalId(leExternalId); legalEntity.setParentExternalId(leExternalId); legalEntity.setProductGroups(singletonList(productGroup)); + legalEntity.setParties(fixtureMonkey.giveMe(Party.class, PARTY_SIZE)); var sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) .creatorLegalEntity(leExternalId); @@ -463,9 +507,8 @@ private void executeAndVerifyTask(LegalEntityTask task, int createServiceAgreeme } /** - * Intention of this test is to verify that {@link ProductGroupTask} are processed in order at - * (in short that .concatMap is used instead of .flatMap). - * Otherwise it may happen that during permission assignment at + * Intention of this test is to verify that {@link ProductGroupTask} are processed in order at (in short that + * .concatMap is used instead of .flatMap). Otherwise it may happen that during permission assignment at * {@link AccessGroupService#assignPermissionsBatch(BatchProductGroupTask, Map)} there will be stale set of * permissions which will lead to state when not all of desired applied */ @@ -483,8 +526,8 @@ void productGroupsProcessedSequentially() { .referenceJobRoles(Collections.singletonList(new JobRole() .name("Job Role with Limits").functionGroups(Collections.singletonList(new BusinessFunctionGroup() .name("someFunctionGroup") - .addFunctionsItem(new BusinessFunction().functionId("1071").name("US Domestic Wire") - .addPrivilegesItem(new Privilege().privilege("create").limit(limit))))))) + .addFunctionsItem(new BusinessFunction().functionId("1071").name("US Domestic Wire") + .addPrivilegesItem(new Privilege().privilege("create").limit(limit))))))) .productGroups(Arrays.asList( (ProductGroup) new ProductGroup() .productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS) @@ -575,13 +618,13 @@ void productGroupsProcessedSequentially() { when(legalEntitySagaConfigurationProperties.isUseIdentityIntegration()) .thenReturn(true); when(legalEntitySagaConfigurationProperties.isServiceAgreementUpdateEnabled()) - .thenReturn(true); + .thenReturn(true); when(userService.setupRealm(legalEntityTask.getLegalEntity())) .thenReturn(Mono.empty()); when(userService.linkLegalEntityToRealm(legalEntityTask.getLegalEntity())) .thenReturn(Mono.empty()); when(userService.updateIdentity(any())) - .thenReturn(Mono.empty()); + .thenReturn(Mono.empty()); when(userService.getUserByExternalId("john.doe")) .thenReturn(Mono.just(new User().internalId("100").externalId("john.doe"))); when(userService.createOrImportIdentityUser(any(), any(), any())) @@ -589,7 +632,7 @@ void productGroupsProcessedSequentially() { when(accessGroupService.getServiceAgreementByExternalId("Service_Agreement_Id")) .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); lenient().when(accessGroupService.updateServiceAgreementItem(any(), any())) - .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); + .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); when(accessGroupService.updateServiceAgreementAssociations(any(), any(), any())) .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); when(accessGroupService.createServiceAgreement(any(), (ServiceAgreement) any())) @@ -602,7 +645,7 @@ void productGroupsProcessedSequentially() { when(accessGroupService.getUserByExternalId("john.doe", true)) .thenReturn(Mono.just(new GetUser().externalId("john.doe").id("internalId"))); when(limitsSaga.executeTask(any())).thenReturn(Mono.just(new LimitsTask("1", new CreateLimitRequestBody()))); - // when(contactsSaga.executeTask(any())).thenReturn(Mono.just(new ContactsTask("1", new ContactsBulkPostRequestBody()))); + // when(contactsSaga.executeTask(any())).thenReturn(Mono.just(new ContactsTask("1", new ContactsBulkPostRequestBody()))); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))) .thenAnswer((Answer>) invocationOnMock -> { ProductGroupTask productGroupTask = invocationOnMock.getArgument(0); @@ -714,30 +757,31 @@ void updateLegalEntityName() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntity newLE = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("New Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(newLE); @@ -747,7 +791,8 @@ void updateLegalEntityName() { when(accessGroupService.getServiceAgreementByExternalId(eq(customSaExId))).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( + Mono.just(customSa)); when(userService.getUserByExternalId(eq(regularUserExId))).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(eq(adminExId))).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -757,7 +802,7 @@ void updateLegalEntityName() { when(userService.updateUser(any())).thenReturn(Mono.empty()); LegalEntityTask result = legalEntitySaga.executeTask(task) - .block(); + .block(); Assertions.assertNotNull(result); Assertions.assertEquals(newLE.getName(), result.getData().getName()); @@ -774,25 +819,26 @@ void updateUserName() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); JobProfileUser newRegularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId).fullName("New Name Regular User")); + .externalId(regularUserExId).fullName("New Name Regular User")); JobProfileUser oldRegularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId).fullName("Old Name Regular User")); + .externalId(regularUserExId).fullName("Old Name Regular User")); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId).fullName("Admin"); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(newRegularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(newRegularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -815,13 +861,13 @@ void updateUserName() { when(userService.updateUser(any())).thenReturn(Mono.just(newRegularUser.getUser())); LegalEntityTask result = legalEntitySaga.executeTask(task) - .block(); + .block(); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getData().getUsers()); Assertions.assertNotNull(result.getData().getUsers().get(0)); Assertions.assertEquals(newRegularUser.getUser().getFullName(), - result.getData().getUsers().get(0).getUser().getFullName()); + result.getData().getUsers().get(0).getUser().getFullName()); verify(accessGroupService).createServiceAgreement(eq(task), eq(customSa)); verify(accessGroupService).updateServiceAgreementRegularUsers(eq(task), eq(customSa), any()); @@ -834,29 +880,30 @@ void getMockLegalEntity() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); legalEntity = new LegalEntity() - .internalId(leInternalId) - .externalId(leExternalId) - .addAdministratorsItem(adminUser) - .parentExternalId(leParentExternalId) - .customServiceAgreement(customSa) - .users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)) - .subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .internalId(leInternalId) + .externalId(leExternalId) + .addAdministratorsItem(adminUser) + .parentExternalId(leParentExternalId) + .customServiceAgreement(customSa) + .users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)) + .subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); when(legalEntityService.getLegalEntityByExternalId(leExternalId)).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(leInternalId)).thenReturn(Mono.just(legalEntity)); @@ -864,7 +911,8 @@ void getMockLegalEntity() { when(accessGroupService.getServiceAgreementByExternalId(customSaExId)).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( + Mono.just(customSa)); when(userService.getUserByExternalId(regularUserExId)).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(adminExId)).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -897,31 +945,32 @@ void test_PostLegalContacts_NoUser() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) + .creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); ExternalContact contact = getMockExternalContact(); legalEntity = new LegalEntity() - .internalId(leInternalId) - .externalId(leExternalId) - .addAdministratorsItem(adminUser) - .parentExternalId(leParentExternalId) - .customServiceAgreement(customSa) - .productGroups(singletonList(productGroup)) - .contacts(Collections.singletonList(contact)) - .subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .internalId(leInternalId) + .externalId(leExternalId) + .addAdministratorsItem(adminUser) + .parentExternalId(leParentExternalId) + .customServiceAgreement(customSa) + .productGroups(singletonList(productGroup)) + .contacts(Collections.singletonList(contact)) + .subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -931,7 +980,8 @@ void test_PostLegalContacts_NoUser() { when(accessGroupService.getServiceAgreementByExternalId(customSaExId)).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( + Mono.just(customSa)); when(userService.getUserByExternalId(adminExId)).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))).thenReturn(productGroupTaskMono); @@ -958,22 +1008,25 @@ void test_PostSAContacts() { customSa.setContacts(Collections.singletonList(contact)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals(leExternalId, result.getData().getCustomServiceAgreement().getContacts().get(0).getExternalId()); + Assertions.assertEquals(leExternalId, + result.getData().getCustomServiceAgreement().getContacts().get(0).getExternalId()); LegalEntityParticipant participant = new LegalEntityParticipant() - .externalId(leExternalId) - .sharingUsers(true) - .users(singletonList("USER1")); + .externalId(leExternalId) + .sharingUsers(true) + .users(singletonList("USER1")); customSa.setParticipants(singletonList(participant)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals("USER1", result.getData().getCustomServiceAgreement().getParticipants().get(0).getUsers().get(0)); + Assertions.assertEquals("USER1", + result.getData().getCustomServiceAgreement().getParticipants().get(0).getUsers().get(0)); participant = participant.users(null).admins(singletonList("ADMIN1")); customSa.setParticipants(singletonList(participant)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals("ADMIN1", result.getData().getCustomServiceAgreement().getParticipants().get(0).getAdmins().get(0)); + Assertions.assertEquals("ADMIN1", + result.getData().getCustomServiceAgreement().getParticipants().get(0).getAdmins().get(0)); } @@ -1133,7 +1186,7 @@ private LegalEntityTask mockLegalEntityTask(LegalEntity legalEntity) { } private LegalEntitySagaConfigurationProperties getLegalEntitySagaConfigurationProperties() { - LegalEntitySagaConfigurationProperties sagaConfiguration = new LegalEntitySagaConfigurationProperties(); + LegalEntitySagaConfigurationProperties sagaConfiguration = new LegalEntitySagaConfigurationProperties(); sagaConfiguration.setUseIdentityIntegration(true); sagaConfiguration.setUserProfileEnabled(true); return sagaConfiguration; @@ -1142,13 +1195,13 @@ private LegalEntitySagaConfigurationProperties getLegalEntitySagaConfigurationPr private ExternalContact getMockExternalContact() { ExternalAccountInformation externalAccount = new ExternalAccountInformation() - .name("ACC1") - .externalId("ACCEXT1") - .accountNumber("12345"); + .name("ACC1") + .externalId("ACCEXT1") + .accountNumber("12345"); return new ExternalContact() - .name("Sam") - .externalId(leExternalId) - .accounts(Collections.singletonList(externalAccount)); + .name("Sam") + .externalId(leExternalId) + .accounts(Collections.singletonList(externalAccount)); } private ContactsBulkPostRequestBody getMockContactsBulkRequest(AccessContextScope accessContextScope) { From 1c38790e63d00ed6a09496a99c699435eb608324 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 18:51:45 +0200 Subject: [PATCH 12/41] Enhance OpenAPI schema with improved descriptions and new properties for email, URL, phone, and postal address entities --- api/stream-legal-entity/openapi.yaml | 124 +++++-- .../com/backbase/stream/LegalEntitySaga.java | 345 +++++++----------- .../backbase/stream/LegalEntitySagaTest.java | 187 +++++----- 3 files changed, 306 insertions(+), 350 deletions(-) diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index 65f7fa589..f265b6dfe 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1602,40 +1602,45 @@ components: - externalId - fullName EmailAddress: - title: "The email addresses the user can be reached by." - required: - - address - - key - - type type: object properties: - key: - maxLength: 70 - minLength: 1 - type: string - description: Unique key identifying the email address. type: - maxLength: 36 - minLength: 1 type: string - description: Key identifying the type of electronic address, e.g. work or personal. + enum: + - WORK + - PERSONAL + - HOME + - OTHERS + description: Identifies the type of email. Possible values - WORK, PERSONAL, HOME, OTHERS. primary: type: boolean - description: Flag denoting whether this is the main electronic address. + description: Flag denoting whether this is the primary email address of the party. address: - maxLength: 255 - minLength: 1 type: string - description: Address. + maxLength: 100 + description: Address for electronic mail (e-mail) (ISO20022). + required: + - type + - address Url: type: object properties: + type: + type: string + enum: + - WORK + - PERSONAL + description: Identifies the type of URL. Possible Values - WORK, PERSONAL. primary: type: boolean + description: Flag denoting whether this is the primary url address of the party. address: - maxLength: 255 - minLength: 1 type: string + maxLength: 255 + description: Address for the Universal Resource Locator (URL), used over the www (HTTP) service. + required: + - address + - type PhoneNumber: required: @@ -1720,42 +1725,89 @@ components: PartyPostalAddress: type: object properties: - country: - type: string - streetName: + type: type: string - townName: + enum: + - Business + - Correspondence + - DeliveryTo + - MailTo + - POBox + - Postal + - Residential + - Statement + description: Identifies the type of postal address. + primary: + type: boolean + description: Flag denoting whether this is the primary postal address of the party. + department: type: string - countrySubDivision: + maxLength: 100 + description: Identification of a division of a large organisation or building (ISO20022). + subDepartment: type: string - postalCode: + maxLength: 100 + description: Identification of a sub-division of a large organisation or building (ISO20022). + addressLine: type: string + maxLength: 100 + description: Information that locates and identifies a specific address, as defined by postal services, presented in free format text (ISO20022). buildingNumber: type: string - subDepartment: + maxLength: 50 + description: Number that identifies the position of a building on a street (ISO20022). + streetName: type: string - type: + maxLength: 100 + description: Name of a street or thoroughfare (ISO20022). + townName: type: string - department: + maxLength: 100 + description: Name of a built-up area, with defined boundaries, and a local government (ISO20022). + postalCode: type: string - addressLine: + maxLength: 12 + description: Identifier consisting of a group of letters and/or numbers that is added to a postal address to assist the sorting of mail (ISO20022). + countrySubDivision: type: string - primary: - type: boolean + maxLength: 100 + description: Identifies name of a country subdivision such as state, region, county. For example - Oregon. + country: + type: string + maxLength: 100 + description: Country name. + required: + - type PhoneAddress: type: object properties: - number: + type: type: string - countryIsoCode: + enum: + - MOBILE + - HOME + - WORK + - OTHER + description: Identifies the type of the phone address. For example - MOBILE, LANDLINE, HOME, WORK, FAX. + primary: + type: boolean + description: Flag denoting if its the primary phone address of the party. + number: type: string + maxLength: 50 + description: Collection of information that identifies a phone address, as defined by telecom services (ISO20022). countryCode: type: string - type: + maxLength: 3 + description: Phone’s country calling code. Country calling code can be obtained from https://countrycode.org/. + countryIsoCode: type: string - primary: - type: boolean + maxLength: 3 + description: Phone’s ISO country code. Country code can be obtained from the United Nations (ISO 3166, Alpha-2 code)- https://www.iban.com/country-codes. + required: + - type + - number ElectronicAddress: type: object properties: diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index b243c5a91..60cbb4938 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -140,9 +140,7 @@ public class LegalEntitySaga implements StreamTaskExecutor { private static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; - - private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper( - BusinessFunctionGroupMapper.class); + private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper(BusinessFunctionGroupMapper.class); private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class); private final LegalEntityService legalEntityService; @@ -260,42 +258,37 @@ private UserKindEnum customerCategoryToUserKind(CustomerCategory customerCategor private Mono postContacts(LegalEntityTask streamTask) { return Mono.just(streamTask) - .flatMap(this::postLegalEntityContacts) - .flatMap(this::postServiceAgreementContacts) - .flatMap(this::postUserContacts); + .flatMap(this::postLegalEntityContacts) + .flatMap(this::postServiceAgreementContacts) + .flatMap(this::postUserContacts); } private Mono postLegalEntityContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (isEmpty(legalEntity.getContacts())) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), - legalEntity.getInternalId(), - "Legal Entity: %s does not have any Contacts defined", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), + "Legal Entity: %s does not have any Contacts defined", legalEntity.getExternalId()); return Mono.just(streamTask); } ServiceAgreement serviceAgreement = getServiceAgreement(legalEntity); log.info("Creating Contacts for Legal Entity Id {}", legalEntity.getExternalId()); Optional externalUserOptional = getUserExternalId(legalEntity.getUsers()); if (externalUserOptional.isEmpty()) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), - legalEntity.getInternalId(), - "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), + "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); return Mono.just(streamTask); } - return contactsSaga.executeTask( - createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), - externalUserOptional.get(), AccessContextScope.LE, legalEntity.getContacts())) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), externalUserOptional.get(), AccessContextScope.LE, legalEntity.getContacts())) + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private Mono postServiceAgreementContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = getServiceAgreement(legalEntity); if (isEmpty(serviceAgreement.getContacts())) { - streamTask.info(SERVICE_AGREEMENT, PROCESS_CONTACTS, FAILED, serviceAgreement.getExternalId(), - serviceAgreement.getInternalId(), - "Master Service Agreement: %s does not have any Contacts defined", serviceAgreement.getExternalId()); + streamTask.info(SERVICE_AGREEMENT, PROCESS_CONTACTS, FAILED, serviceAgreement.getExternalId(), serviceAgreement.getInternalId(), + "Master Service Agreement: %s does not have any Contacts defined", serviceAgreement.getExternalId()); return Mono.just(streamTask); } log.info("Creating Contacts for Service Agreement Id {}", serviceAgreement.getExternalId()); @@ -304,27 +297,24 @@ private Mono postServiceAgreementContacts(LegalEntityTask strea if (externalUserOptional.isEmpty()) { externalUserId = getParticipantUser(serviceAgreement); if (externalUserId == null) { - streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), - legalEntity.getInternalId(), - "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_CONTACTS, FAILED, legalEntity.getExternalId(), legalEntity.getInternalId(), + "Legal Entity: %s does not have any Users", legalEntity.getExternalId()); return Mono.just(streamTask); } } else { externalUserId = externalUserOptional.get(); } - return contactsSaga.executeTask( - createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), - externalUserId, AccessContextScope.SA, serviceAgreement.getContacts())) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), serviceAgreement.getExternalId(), externalUserId, AccessContextScope.SA, serviceAgreement.getContacts())) + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private String getParticipantUser(ServiceAgreement serviceAgreement) { if (!isEmpty(serviceAgreement.getParticipants())) { Optional participants = serviceAgreement.getParticipants() - .stream() - .filter(LegalEntityParticipant::getSharingUsers) - .findFirst(); + .stream() + .filter(LegalEntityParticipant::getSharingUsers) + .findFirst(); if (participants.isPresent()) { LegalEntityParticipant participant = participants.get(); if (!isEmpty(participant.getAdmins())) { @@ -341,19 +331,15 @@ private String getOptionalUserId(Optional optionalUserId) { return optionalUserId.isPresent() ? optionalUserId.get() : null; } - private ContactsTask createContactsTask(String streamTaskId, String externalLegalEntityId, - String externalServiceAgreementId, String externalUserId, AccessContextScope scope, - List contacts) { + private ContactsTask createContactsTask(String streamTaskId, String externalLegalEntityId, String externalServiceAgreementId, String externalUserId, AccessContextScope scope, List contacts) { var contactData = new ContactsBulkPostRequestBody(); contactData.setIngestMode(IngestMode.UPSERT); - contactData.setAccessContext( - createExternalAccessContext(externalLegalEntityId, externalServiceAgreementId, externalUserId, scope)); + contactData.setAccessContext(createExternalAccessContext(externalLegalEntityId, externalServiceAgreementId, externalUserId, scope)); contactData.setContacts(externalContactMapper.toMapList(contacts)); return new ContactsTask(streamTaskId + "-" + "contacts-task", contactData); } - private ExternalAccessContext createExternalAccessContext(String externalLegalEntityId, - String externalServiceAgreementId, String externalUserId, AccessContextScope scope) { + private ExternalAccessContext createExternalAccessContext(String externalLegalEntityId, String externalServiceAgreementId, String externalUserId, AccessContextScope scope) { ExternalAccessContext accessContext = new ExternalAccessContext(); accessContext.setExternalLegalEntityId(externalLegalEntityId); accessContext.setExternalServiceAgreementId(externalServiceAgreementId); @@ -367,14 +353,13 @@ private Optional getUserExternalId(List users) { return Optional.empty(); } Optional optionalUser = users.stream().findFirst(); - return optionalUser.map(jobProfileUser -> Optional.ofNullable(jobProfileUser.getUser().getExternalId())) - .orElse(Optional.empty()); + return optionalUser.map(jobProfileUser -> Optional.ofNullable(jobProfileUser.getUser().getExternalId())).orElse(Optional.empty()); } private ServiceAgreement getServiceAgreement(LegalEntity legalEntity) { - return legalEntity.getMasterServiceAgreement() != null ? - legalEntity.getMasterServiceAgreement() : - legalEntity.getCustomServiceAgreement(); + return legalEntity.getMasterServiceAgreement() != null? + legalEntity.getMasterServiceAgreement() : + legalEntity.getCustomServiceAgreement(); } @Override @@ -385,8 +370,7 @@ public Mono rollBack(LegalEntityTask streamTask) { /** * Delete Legal Entity by provided Legal Entity external ID. - * This call doesn't cover arrangements and transactions removal. Should be done before caling this - * method. + * This call doesn't cover arrangements and transactions removal. Should be done before caling this method. *
    * Flow is the following: *
      @@ -449,12 +433,10 @@ public Mono deleteLegalEntity(String legalEntityExternalId) { } private Mono upsertLegalEntity(LegalEntityTask task) { - task.info(LEGAL_ENTITY, UPSERT, "", task.getData().getExternalId(), null, - "Upsert Legal Entity with External ID: %s", task.getData().getExternalId()); + task.info(LEGAL_ENTITY, UPSERT, "", task.getData().getExternalId(), null, "Upsert Legal Entity with External ID: %s", task.getData().getExternalId()); LegalEntity legalEntity = task.getData(); // Pipeline for Existing Legal Entity - Mono existingLegalEntity = legalEntityService.getLegalEntityByExternalId( - legalEntity.getExternalId()) + Mono existingLegalEntity = legalEntityService.getLegalEntityByExternalId(legalEntity.getExternalId()) .flatMap(actual -> { task.getData().setInternalId(actual.getInternalId()); return legalEntityService.getLegalEntityByInternalId(actual.getInternalId()) @@ -463,8 +445,7 @@ private Mono upsertLegalEntity(LegalEntityTask task) { return legalEntityService.putLegalEntity(task.getData()).flatMap(leUpdated -> { log.info("Updated LegalEntity: {}", leUpdated.getName()); - task.info(LEGAL_ENTITY, UPSERT_LEGAL_ENTITY, UPDATED, legalEntity.getExternalId(), - actual.getInternalId(), "Legal Entity: %s updated", legalEntity.getName()); + task.info(LEGAL_ENTITY, UPSERT_LEGAL_ENTITY, UPDATED, legalEntity.getExternalId(), actual.getInternalId(), "Legal Entity: %s updated", legalEntity.getName()); return Mono.just(task); }); }); @@ -505,9 +486,7 @@ private Mono upsertLegalEntity(LegalEntityTask task) { private Mono processProducts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (legalEntity.getProductGroups() == null || legalEntity.getProductGroups().isEmpty()) { - streamTask.info(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), "Legal Entity: %s does not have any products defied", - legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any products defied", legalEntity.getExternalId()); return Mono.just(streamTask); } @@ -519,10 +498,8 @@ private Mono processProducts(LegalEntityTask streamTask) { if (throwable.getClass().isAssignableFrom(WebClientResponseException.class)) { message = ((WebClientResponseException) throwable).getResponseBodyAsString(); } - streamTask.error(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), throwable, message, "Unexpected error processing"); - log.error("Unexpected error processing product group {}: {}", - productGroupStreamTask.getData().getName(), message); + streamTask.error(LEGAL_ENTITY, PROCESS_PRODUCTS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), throwable, message, "Unexpected error processing"); + log.error("Unexpected error processing product group {}: {}", productGroupStreamTask.getData().getName(), message); productGroupStreamTask.setState(StreamTask.State.FAILED); return Mono.error(throwable); })) @@ -606,57 +583,41 @@ private Mono processJobProfiles(LegalEntityTask streamTask) { log.info("Processing Job Profiles for: {}", streamTask.getName()); LegalEntity legalEntity = streamTask.getData(); if (legalEntity.getUsers() == null) { - streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), - legalEntity.getInternalId(), - "No Job Profile Users defined in Legal Entity. No Business Function Groups will be assigned between a User and Legal Entity. "); + streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), legalEntity.getInternalId(), "No Job Profile Users defined in Legal Entity. No Business Function Groups will be assigned between a User and Legal Entity. "); return Mono.just(streamTask); } if (legalEntity.getUsers().stream().allMatch(jobProfileUser -> jobProfileUser.getUser() == null)) { - streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), - legalEntity.getInternalId(), "No Users defined in Job Profiles"); + streamTask.warn(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, REJECTED, legalEntity.getExternalId(), legalEntity.getInternalId(), "No Users defined in Job Profiles"); return Mono.just(streamTask); } return Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())) .flatMap(jobProfileUser -> { ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); return getBusinessFunctionGroupTemplates(streamTask, jobProfileUser) - .flatMap( - businessFunctionGroups -> accessGroupService.setupFunctionGroups(streamTask, serviceAgreement, - businessFunctionGroups)) + .flatMap(businessFunctionGroups -> accessGroupService.setupFunctionGroups(streamTask, serviceAgreement, businessFunctionGroups)) .flatMap(list -> { - log.info("Assigning {} Business Function Groups to Job Profile User: {}", list.size(), - jobProfileUser.getUser().getExternalId()); + log.info("Assigning {} Business Function Groups to Job Profile User: {}", list.size(), jobProfileUser.getUser().getExternalId()); jobProfileUser.setBusinessFunctionGroups(list); - list.forEach(bfg -> streamTask.info(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, "assigned", - legalEntity.getExternalId(), legalEntity.getInternalId(), - "Assigned Business Function Group: %s with functions: %s to Service Agreement: %s", - bfg.getName(), - ofNullable(bfg.getFunctions()).orElse( - Collections.singletonList(new BusinessFunction().name(""))).stream() - .map(BusinessFunction::getFunctionCode).collect(Collectors.joining(", ")), - serviceAgreement.getExternalId())); + list.forEach(bfg -> streamTask.info(BUSINESS_FUNCTION_GROUP, PROCESS_JOB_PROFILES, "assigned", legalEntity.getExternalId(), legalEntity.getInternalId(), "Assigned Business Function Group: %s with functions: %s to Service Agreement: %s", bfg.getName(), + ofNullable(bfg.getFunctions()).orElse(Collections.singletonList(new BusinessFunction().name(""))).stream().map(BusinessFunction::getFunctionCode).collect(Collectors.joining(", ")), serviceAgreement.getExternalId())); return setupUserPermissions(streamTask, jobProfileUser); }) .map(actual -> jobProfileUser); }) .collectList() .map(jobProfileUsers -> { - if (!jobProfileUsers.isEmpty()) { + if (!jobProfileUsers.isEmpty()) streamTask.getData().setUsers(jobProfileUsers); - } return streamTask; }); } - private Mono> getBusinessFunctionGroupTemplates(LegalEntityTask streamTask, - JobProfileUser jobProfileUser) { - streamTask.info(LEGAL_ENTITY, BUSINESS_FUNCTION_GROUP, "getBusinessFunctionGroupTemplates", "", "", - "Using Reference Job Roles and Custom Job Roles defined in Job Profile User"); + private Mono> getBusinessFunctionGroupTemplates(LegalEntityTask streamTask, JobProfileUser jobProfileUser) { + streamTask.info(LEGAL_ENTITY, BUSINESS_FUNCTION_GROUP, "getBusinessFunctionGroupTemplates", "", "", "Using Reference Job Roles and Custom Job Roles defined in Job Profile User"); List businessFunctionGroups = jobProfileUser.getBusinessFunctionGroups(); if (!isEmpty(jobProfileUser.getReferenceJobRoleNames())) { - return accessGroupService.getFunctionGroupsForServiceAgreement( - retrieveServiceAgreement(streamTask.getData()).getInternalId()) + return accessGroupService.getFunctionGroupsForServiceAgreement(retrieveServiceAgreement(streamTask.getData()).getInternalId()) .map(functionGroups -> { Map idByFunctionGroupName = functionGroups .stream() @@ -669,9 +630,8 @@ private Mono> getBusinessFunctionGroupTemplates(Lega .collect(Collectors.toList()); }) .map(bf -> { - if (!isEmpty(businessFunctionGroups)) { + if (!isEmpty(businessFunctionGroups)) bf.addAll(businessFunctionGroups); - } return bf; }); } @@ -688,7 +648,7 @@ private Mono setupAdministrators(LegalEntityTask streamTask) { .map(streamTask::data); } - private Mono setupUsers(LegalEntityTask streamTask) { + private Mono setupUsers(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); Flux jobProfileUsers = Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())); @@ -718,26 +678,24 @@ private Mono postUserContacts(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); Flux jobProfileUsers = Flux.fromStream(nullableCollectionToStream(legalEntity.getUsers())); return jobProfileUsers - .flatMap(jobProfileUser -> postUserContacts(streamTask, jobProfileUser.getContacts(), - jobProfileUser.getUser().getExternalId())) - .collectList() - .thenReturn(streamTask); + .flatMap(jobProfileUser -> postUserContacts(streamTask, jobProfileUser.getContacts(), jobProfileUser.getUser().getExternalId())) + .collectList() + .thenReturn(streamTask); } - private Mono postUserContacts(LegalEntityTask streamTask, List externalContacts, - String externalUserId) { + private Mono postUserContacts(LegalEntityTask streamTask, List externalContacts, String externalUserId) { if (isEmpty(externalContacts)) { log.info("Creating Contacts for User {}", externalUserId); streamTask.info(USER, PROCESS_CONTACTS, FAILED, externalUserId, null, - "User: %s does not have any Contacts", externalUserId); + "User: %s does not have any Contacts", externalUserId); return Mono.just(streamTask); } LegalEntity legalEntity = streamTask.getData(); log.info("Creating Contacts for User {}", externalUserId); return contactsSaga.executeTask(createContactsTask(streamTask.getId(), legalEntity.getExternalId(), null, externalUserId, AccessContextScope.USER, externalContacts)) - .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) - .then(Mono.just(streamTask)); + .flatMap(contactsTask -> requireNonNull(Mono.just(streamTask))) + .then(Mono.just(streamTask)); } private Mono upsertUserProfile(User user) { @@ -779,8 +737,7 @@ public Mono setupUserPermissions(LegalEntityTask legalEntityTas public Mono setupAdministratorPermissions(LegalEntityTask legalEntityTask) { // Assign permissions for the user for all business function groups. LegalEntity legalEntity = legalEntityTask.getData(); - Map>> request = nullableCollectionToStream( - legalEntity.getUsers()) + Map>> request = nullableCollectionToStream(legalEntity.getUsers()) .filter(jobProfileUser -> !isEmpty(jobProfileUser.getBusinessFunctionGroups())) .collect(Collectors.toMap( jobProfileUser -> setupAdminInternalId(legalEntity, jobProfileUser), @@ -823,8 +780,7 @@ public Mono upsertUser(LegalEntityTask streamTask, User user) { && !IdentityUserLinkStrategy.IDENTITY_AGNOSTIC.equals(user.getIdentityLinkStrategy())) { return upsertIdentityUser(streamTask, user); } else { - log.debug( - "Fallback to Identity Agnostic identityLinkStrategy. Either identity integration is disabled or User identityLinkStrategy is not set to identity."); + log.debug("Fallback to Identity Agnostic identityLinkStrategy. Either identity integration is disabled or User identityLinkStrategy is not set to identity."); return upsertUser(user, streamTask); } } @@ -834,16 +790,14 @@ private Mono upsertUserBulk(User user, LegalEntityTask streamTask) { streamTask.info(USER, UPSERT, "", user.getExternalId(), user.getInternalId(), "Upsert User with External ID: %s", user.getExternalId()); - Mono getExistingUser = Mono.zip(Mono.just(user), userService.getUserByExternalId(user.getExternalId()), - (u, existingUser) -> { - u.setInternalId(existingUser.getInternalId()); - streamTask.info(USER, UPSERT, EXISTS, u.getExternalId(), u.getInternalId(), "User %s already exists", - existingUser.getExternalId()); - return u; - }); + Mono getExistingUser = Mono.zip(Mono.just(user), userService.getUserByExternalId(user.getExternalId()), (u, existingUser) -> { + u.setInternalId(existingUser.getInternalId()); + streamTask.info(USER, UPSERT, EXISTS, u.getExternalId(), u.getInternalId(), "User %s already exists", + existingUser.getExternalId()); + return u; + }); - Mono createNewUser = Mono.zip(Mono.just(user), - userService.createUser(user, legalEntity.getExternalId(), streamTask), + Mono createNewUser = Mono.zip(Mono.just(user), userService.createUser(user, legalEntity.getExternalId(), streamTask), (u, newUser) -> { u.setInternalId(newUser.getInternalId()); streamTask.info(USER, UPSERT, CREATED, u.getExternalId(), user.getInternalId(), "User %s created", @@ -855,8 +809,7 @@ private Mono upsertUserBulk(User user, LegalEntityTask streamTask) { private Mono upsertUser(User user, LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); - streamTask.info(USER, UPSERT, "", user.getExternalId(), "Upsert User with External ID: %s", - user.getExternalId()); + streamTask.info(USER, UPSERT, "", user.getExternalId(), "Upsert User with External ID: %s", user.getExternalId()); Mono existingUser = userService.getUserByExternalId(user.getExternalId()).flatMap(existUser -> { user.setInternalId(existUser.getInternalId()); @@ -870,8 +823,7 @@ private Mono upsertUser(User user, LegalEntityTask streamTask) { }); }); - Mono createNewUser = Mono.zip(Mono.just(user), - userService.createUser(user, legalEntity.getExternalId(), streamTask), + Mono createNewUser = Mono.zip(Mono.just(user), userService.createUser(user, legalEntity.getExternalId(), streamTask), (u, newUser) -> { u.setInternalId(newUser.getInternalId()); streamTask.info(USER, UPSERT, CREATED, u.getExternalId(), user.getInternalId(), "User %s created", @@ -882,14 +834,13 @@ private Mono upsertUser(User user, LegalEntityTask streamTask) { } private Mono upsertIdentityUser(LegalEntityTask streamTask, User user) { - streamTask.info(IDENTITY_USER, UPSERT, "", user.getExternalId(), user.getInternalId(), - "Upsert User to Identity with External ID: %s", user.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, "", user.getExternalId(), user.getInternalId(), + "Upsert User to Identity with External ID: %s", user.getExternalId()); LegalEntity legalEntity = streamTask.getData(); Mono getExistingIdentityUser = userService.getUserByExternalId(user.getExternalId()) .map(existingUser -> { user.setInternalId(existingUser.getInternalId()); - streamTask.info(IDENTITY_USER, UPSERT, EXISTS, user.getExternalId(), user.getInternalId(), - "User %s already exists", existingUser.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, EXISTS, user.getExternalId(), user.getInternalId(), "User %s already exists", existingUser.getExternalId()); return user; }) .flatMap(userService::updateIdentity); @@ -899,8 +850,7 @@ private Mono upsertIdentityUser(LegalEntityTask streamTask, User user) { .flatMap(currentUser -> userService.updateUserState(currentUser, legalEntity.getRealmName())) .map(existingUser -> { user.setInternalId(existingUser.getInternalId()); - streamTask.info(IDENTITY_USER, UPSERT, CREATED, user.getExternalId(), user.getInternalId(), - "User %s created", existingUser.getExternalId()); + streamTask.info(IDENTITY_USER, UPSERT, CREATED, user.getExternalId(), user.getInternalId(), "User %s created", existingUser.getExternalId()); return user; }); return getExistingIdentityUser.switchIfEmpty(createNewIdentityUser); @@ -912,8 +862,7 @@ private Mono setupServiceAgreement(LegalEntityTask streamTask) if (legalEntity.getCustomServiceAgreement() != null) { return setupCustomServiceAgreement(streamTask, legalEntity); - } else if (legalEntity.getMasterServiceAgreement() == null || StringUtils.isEmpty( - legalEntity.getMasterServiceAgreement().getInternalId())) { + } else if (legalEntity.getMasterServiceAgreement() == null || StringUtils.isEmpty(legalEntity.getMasterServiceAgreement().getInternalId())) { // Fetch existing master service agreement or create a new one return fetchExistingMasterServiceAgreement(legalEntity, streamTask) @@ -1057,17 +1006,16 @@ private Mono setupCustomServiceAgreement(LegalEntityTask stream .getServiceAgreementByExternalId(newSa.getExternalId()) .flatMap(sa -> { newSa.setInternalId(sa.getInternalId()); - streamTask.info(SERVICE_AGREEMENT, SETUP_SERVICE_AGREEMENT, EXISTS, sa.getExternalId(), - sa.getInternalId(), + streamTask.info(SERVICE_AGREEMENT, SETUP_SERVICE_AGREEMENT, EXISTS, sa.getExternalId(), sa.getInternalId(), "Existing Service Agreement: %s found for Legal Entity: %s", sa.getExternalId(), legalEntity.getExternalId()); if (legalEntitySagaConfigurationProperties.isServiceAgreementUpdateEnabled()) { return accessGroupService.updateServiceAgreementItem(streamTask, newSa) - .then(accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions)) - .thenReturn(streamTask); + .then(accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions)) + .thenReturn(streamTask); } else { return accessGroupService.updateServiceAgreementAssociations(streamTask, newSa, userActions) - .thenReturn(streamTask); + .thenReturn(streamTask); } }); // As creatorLegalEntity doesnt accept external ID @@ -1124,7 +1072,7 @@ private ServiceAgreement createMasterServiceAgreement(LegalEntity legalEntity, @ } serviceAgreement.setIsMaster(true); - if (isEmpty(serviceAgreement.getParticipants())) { + if(isEmpty(serviceAgreement.getParticipants())) { serviceAgreement.addParticipantsItem(legalEntityParticipant); } @@ -1221,7 +1169,7 @@ private ServiceAgreement retrieveServiceAgreement(LegalEntity legalEntity) { } private Flux setSubsidiaryParentLegalEntityId(LegalEntity parentLegalEntity, - Flux subsidiaries) { + Flux subsidiaries) { return subsidiaries.map(subsidiary -> { subsidiary.setParentExternalId(parentLegalEntity.getExternalId()); return subsidiary; @@ -1240,15 +1188,12 @@ private Mono setupLimits(LegalEntityTask streamTask) { private Mono setupLegalEntityLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); - if (isNull(legalEntity.getLimit()) || !validateLimit(legalEntity.getLimit())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", - legalEntity.getExternalId()); + if(isNull(legalEntity.getLimit()) || !validateLimit(legalEntity.getLimit())) { + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", legalEntity.getExternalId()); return Mono.just(streamTask); } - return limitsSaga.executeTask( - createLimitsTask(streamTask, null, legalEntity.getInternalId(), legalEntity.getLimit())) + return limitsSaga.executeTask(createLimitsTask(streamTask, null, legalEntity.getInternalId(), legalEntity.getLimit())) .flatMap(limitsTask -> requireNonNull(Mono.just(streamTask))) .then(Mono.just(streamTask)); } @@ -1256,49 +1201,44 @@ private Mono setupLegalEntityLimits(LegalEntityTask streamTask) private boolean validateLimit(Limit limit) { return nonNull(limit) && - (nonNull(limit.getTransactional()) || - nonNull(limit.getDaily()) || - nonNull(limit.getWeekly()) || - nonNull(limit.getMonthly()) || - nonNull(limit.getQuarterly()) || - nonNull(limit.getYearly())); + (nonNull(limit.getTransactional()) || + nonNull(limit.getDaily()) || + nonNull(limit.getWeekly()) || + nonNull(limit.getMonthly()) || + nonNull(limit.getQuarterly()) || + nonNull(limit.getYearly())); } private Mono setupLegalEntityLevelBusinessFunctionLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); if (isNull(legalEntity.getLimit()) || isEmpty(legalEntity.getLimit().getBusinessFunctionLimits())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", - legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Legal Entity limits defined", legalEntity.getExternalId()); return Mono.just(streamTask); } return Flux.fromStream(legalEntity.getLimit().getBusinessFunctionLimits() .stream() .filter(businessFunctionLimit -> nonNull(businessFunctionLimit) - && !CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) - .flatMap(businessFunctionLimit -> createLimitsTask(streamTask, legalEntity.getInternalId(), - businessFunctionLimit))) - .concatMap(limitsSaga::executeTask) - .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) - .collectList() - .map(tasks -> { - boolean failed = tasks.stream().anyMatch(StreamTask::isFailed); - if (failed) { - streamTask.setState(StreamTask.State.FAILED); - } else { - streamTask.setState(StreamTask.State.COMPLETED); - } - return streamTask; - }); + && !CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) + .flatMap(businessFunctionLimit -> createLimitsTask(streamTask, legalEntity.getInternalId(), businessFunctionLimit))) + .concatMap(limitsSaga::executeTask) + .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) + .collectList() + .map(tasks -> { + boolean failed = tasks.stream().anyMatch(StreamTask::isFailed); + if (failed) { + streamTask.setState(StreamTask.State.FAILED); + } else { + streamTask.setState(StreamTask.State.COMPLETED); + } + return streamTask; + }); } private Mono setupServiceAgreementLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); if (isNull(serviceAgreement.getLimit())) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), "Legal Entity: %s does not have any Service Agreement limits defined", - legalEntity.getExternalId()); + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Service Agreement limits defined", legalEntity.getExternalId()); return Mono.just(streamTask); } return limitsSaga.executeTask(createLimitsTask(streamTask, serviceAgreement, null, serviceAgreement.getLimit())) @@ -1306,10 +1246,9 @@ private Mono setupServiceAgreementLimits(LegalEntityTask stream .then(Mono.just(streamTask)); } - private Stream createLimitsTask(LegalEntityTask streamTask, String legalEntityId, - BusinessFunctionLimit businessFunctionLimit) { + private Stream createLimitsTask(LegalEntityTask streamTask, String legalEntityId, BusinessFunctionLimit businessFunctionLimit) { - if (isNull(businessFunctionLimit) || CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())) { + if(isNull(businessFunctionLimit) || CollectionUtils.isEmpty(businessFunctionLimit.getPrivileges())){ return Stream.of(); } return businessFunctionLimit.getPrivileges() @@ -1318,31 +1257,28 @@ private Stream createLimitsTask(LegalEntityTask streamTask, String l .map(privilege -> { var limitData = new CreateLimitRequestBody(); var entities = new ArrayList(); - ofNullable(legalEntityId).ifPresent( - le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); + ofNullable(legalEntityId).ifPresent(le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); ofNullable(businessFunctionLimit.getFunctionId()) - .ifPresent(functionId -> entities.add(new Entity().etype(FUNCTION_E_TYPE).eref(functionId))); + .ifPresent(functionId -> entities.add(new Entity().etype(FUNCTION_E_TYPE).eref(functionId))); ofNullable(privilege.getPrivilege()) - .ifPresent(prv -> entities.add(new Entity().etype(PRIVILEGE_E_TYPE).eref(prv))); + .ifPresent(prv -> entities.add(new Entity().etype(PRIVILEGE_E_TYPE).eref(prv))); limitData.entities(entities); Optional.of(privilege) .map(Privilege::getLimit).ifPresent(limit -> limitData.periodicLimitsBounds(periodicLimits(limit)) - .transactionalLimitsBound(transactionalLimits(limit)) - .shadow(businessFunctionLimit.getShadow()) - .currency(limit.getCurrencyCode())); + .transactionalLimitsBound(transactionalLimits(limit)) + .shadow(businessFunctionLimit.getShadow()) + .currency(limit.getCurrencyCode())); return new LimitsTask(streamTask.getId() + "-" + LEGAL_ENTITY_LIMITS, limitData); }); } - private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement serviceAgreement, - String legalEntityId, Limit limit) { + private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement serviceAgreement, String legalEntityId, Limit limit) { var limitData = new CreateLimitRequestBody(); var entities = new ArrayList(); ofNullable(legalEntityId).ifPresent(le -> entities.add(new Entity().etype(LEGAL_ENTITY_E_TYPE).eref(le))); - ofNullable(serviceAgreement).ifPresent( - sa -> entities.add(new Entity().etype(SERVICE_AGREEMENT_E_TYPE).eref(sa.getInternalId()))); + ofNullable(serviceAgreement).ifPresent(sa -> entities.add(new Entity().etype(SERVICE_AGREEMENT_E_TYPE).eref(sa.getInternalId()))); limitData.entities(entities); limitData.periodicLimitsBounds(periodicLimits(limit)) .transactionalLimitsBound(transactionalLimits(limit)) @@ -1354,21 +1290,14 @@ private LimitsTask createLimitsTask(LegalEntityTask streamTask, ServiceAgreement private Mono setupServiceAgreementParticipantLimits(LegalEntityTask streamTask) { LegalEntity legalEntity = streamTask.getData(); ServiceAgreement serviceAgreement = retrieveServiceAgreement(legalEntity); - if (isNull(serviceAgreement.getParticipants()) - || serviceAgreement.getParticipants().stream() - .noneMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) { - streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), - legalEntity.getExternalId(), - "Legal Entity: %s does not have any Participant with Limits in Service Agreement", - legalEntity.getExternalId()); + if(isNull(serviceAgreement.getParticipants()) + || serviceAgreement.getParticipants().stream().noneMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) { + streamTask.info(LEGAL_ENTITY, PROCESS_LIMITS, FAILED, legalEntity.getInternalId(), legalEntity.getExternalId(), "Legal Entity: %s does not have any Participant with Limits in Service Agreement", legalEntity.getExternalId()); return Mono.just(streamTask); } return accessGroupService.getServiceAgreementParticipants(streamTask, serviceAgreement) - .filter(participant -> serviceAgreement.getParticipants().stream() - .filter(p -> p.getExternalId().equalsIgnoreCase(participant.getExternalId())) - .anyMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) - .flatMapIterable(participant -> List.of(createLimitsTask(streamTask, serviceAgreement, participant.getId(), - getLimits(serviceAgreement, participant)))) + .filter(participant -> serviceAgreement.getParticipants().stream().filter(p -> p.getExternalId().equalsIgnoreCase(participant.getExternalId())).anyMatch(legalEntityParticipant -> legalEntityParticipant.getLimit() != null)) + .flatMapIterable(participant -> List.of(createLimitsTask(streamTask, serviceAgreement, participant.getId(), getLimits(serviceAgreement, participant)))) .flatMap(limitsSaga::executeTask) .map(limitsTask -> streamTask.addHistory(limitsTask.getHistory())) .collectList() @@ -1383,11 +1312,9 @@ private Mono setupServiceAgreementParticipantLimits(LegalEntity }); } - private Limit getLimits(ServiceAgreement serviceAgreement, - ServiceAgreementParticipantsGetResponseBody participant) { + private Limit getLimits(ServiceAgreement serviceAgreement, ServiceAgreementParticipantsGetResponseBody participant) { return serviceAgreement.getParticipants().stream() - .filter(legalEntityParticipant -> legalEntityParticipant.getExternalId() - .equalsIgnoreCase(participant.getExternalId())) + .filter(legalEntityParticipant -> legalEntityParticipant.getExternalId().equalsIgnoreCase(participant.getExternalId())) .map(LegalEntityParticipant::getLimit) .findFirst().orElseGet(Limit::new); } @@ -1413,15 +1340,14 @@ && noLimitsInJobRole(legalEntity.getReferenceJobRoles())) { .filter(jobProfileUser -> nonNull(jobProfileUser.getUser()) && nonNull( jobProfileUser.getUser().getSupportsLimit()) && !isEmpty(jobProfileUser.getReferenceJobRoleNames())) .forEach(jobProfileUser -> jobProfileUser.getReferenceJobRoleNames().forEach(jobRoleName -> { - if (userJobRoleMap.get(jobRoleName) != null) { - var users = userJobRoleMap.get(jobRoleName); - users.add(jobProfileUser.getUser().getInternalId()); - userJobRoleMap.put(jobRoleName, users); - } else { - userJobRoleMap.put(jobRoleName, - new HashSet<>(List.of(jobProfileUser.getUser().getInternalId()))); - } - })); + if(userJobRoleMap.get(jobRoleName) != null) { + var users = userJobRoleMap.get(jobRoleName); + users.add(jobProfileUser.getUser().getInternalId()); + userJobRoleMap.put(jobRoleName, users); + } else { + userJobRoleMap.put(jobRoleName, new HashSet<>(List.of(jobProfileUser.getUser().getInternalId()))); + } + })); } return Flux.fromStream(Stream.of(serviceAgreement.getJobRoles(), legalEntity.getReferenceJobRoles()) @@ -1444,24 +1370,20 @@ && noLimitsInJobRole(legalEntity.getReferenceJobRoles())) { private Mono retrieveUsersInternalIds(LegalEntityTask streamTask) { var le = streamTask.getData(); - if (le.getProductGroups() == null || le.getProductGroups().stream() - .allMatch(productGroup -> Objects.isNull(productGroup.getUsers())) + if(le.getProductGroups() == null || le.getProductGroups().stream().allMatch(productGroup -> Objects.isNull(productGroup.getUsers())) || le.getProductGroups().stream().filter(productGroup -> nonNull(productGroup.getUsers())) .flatMap(productGroup -> productGroup.getUsers().stream()) - .noneMatch(jobProfileUser -> nonNull(jobProfileUser) && nonNull(jobProfileUser.getUser()) && nonNull( - jobProfileUser.getUser().getSupportsLimit()) && jobProfileUser.getUser().getSupportsLimit())) { + .noneMatch(jobProfileUser -> nonNull(jobProfileUser) && nonNull(jobProfileUser.getUser()) && nonNull(jobProfileUser.getUser().getSupportsLimit()) && jobProfileUser.getUser().getSupportsLimit())) { return Mono.just(streamTask); } - var users = le.getProductGroups().stream().flatMap(productGroup -> productGroup.getUsers().stream()) - .collect(Collectors.toSet()); + var users = le.getProductGroups().stream().flatMap(productGroup -> productGroup.getUsers().stream()).collect(Collectors.toSet()); return Flux.fromIterable(users) .flatMap(jpu -> accessGroupService.getUserByExternalId(jpu.getUser().getExternalId(), true)) .collectList() .flatMap(internalUsers -> { Map usersByExternalId = - internalUsers.stream() - .collect(Collectors.toMap(GetUser::getExternalId, Function.identity(), (a1, a2) -> a1)); + internalUsers.stream().collect(Collectors.toMap(GetUser::getExternalId, Function.identity(), (a1, a2) -> a1)); users.forEach(jp -> { String externalId = jp.getUser().getExternalId(); GetUser internalUser = usersByExternalId.get(externalId); @@ -1477,9 +1399,8 @@ private List createLimitsTask(LegalEntityTask streamTask, JobRole ac ServiceAgreement serviceAgreement, Map> userJobRoleMap) { List userJobRoleLimits = new ArrayList<>(); - if (!CollectionUtils.isEmpty(userJobRoleMap) && userJobRoleMap.containsKey(actual.getName())) { - userJobRoleMap.get(actual.getName()) - .forEach(userId -> userJobRoleLimits.addAll(actual.getFunctionGroups().stream() + if(!CollectionUtils.isEmpty(userJobRoleMap) && userJobRoleMap.containsKey(actual.getName())) { + userJobRoleMap.get(actual.getName()).forEach(userId -> userJobRoleLimits.addAll(actual.getFunctionGroups().stream() .filter(this::limitsExist) .flatMap(businessFunctionGroup -> businessFunctionGroup.getFunctions().stream() .flatMap(businessFunction -> businessFunction.getPrivileges().stream() @@ -1490,7 +1411,7 @@ private List createLimitsTask(LegalEntityTask streamTask, JobRole ac businessFunction, privilege, actual.getId(), userId)))) .map(limitData -> new LimitsTask(streamTask.getId() + "-" + USER_JOB_ROLE_LIMITS, limitData)) .collect(Collectors.toList()))); - } + } var jobRoleLimits = actual.getFunctionGroups().stream() .filter(this::limitsExist) diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index aa499deb0..19cfe04fd 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -176,14 +176,12 @@ void customServiceAgreementCreation() { .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); - legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId) - .addAdministratorsItem(adminUser) + legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).addAdministratorsItem(adminUser) .parentExternalId(leParentExternalId).customServiceAgreement(customSa).users(singletonList(regularUser)) .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -194,8 +192,7 @@ void customServiceAgreementCreation() { when(accessGroupService.getServiceAgreementByExternalId(eq(customSaExId))).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( - Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); when(userService.getUserByExternalId(eq(regularUserExId))).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(eq(adminExId))).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -279,19 +276,16 @@ void masterServiceAgreementCreation() { BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).parentExternalId(leExternalId) - .activateSingleServiceAgreement(false).masterServiceAgreement(sa) - .productGroups(singletonList(productGroup)); + .activateSingleServiceAgreement(false).masterServiceAgreement(sa).productGroups(singletonList(productGroup)); LegalEntityTask task = mockLegalEntityTask(legalEntity); when(task.getLegalEntity()).thenReturn(legalEntity); when(legalEntityService.getLegalEntityByExternalId(eq(leExternalId))).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(eq(leInternalId))).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn( - Mono.just(sa)); + when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn(Mono.just(sa)); when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(legalEntity)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))) @@ -331,16 +325,14 @@ void masterServiceAgreementCreation_activateSingleServiceAgreement() { JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).parentExternalId(leExternalId) .productGroups(singletonList(productGroup)); - ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + ServiceAgreement sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); LegalEntityTask task = mockLegalEntityTask(legalEntity); when(task.getLegalEntity()).thenReturn(legalEntity); when(legalEntityService.getLegalEntityByExternalId(eq(leExternalId))).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(eq(leInternalId))).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn( - Mono.empty()); + when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(eq(leInternalId))).thenReturn(Mono.empty()); when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(legalEntity)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); when(accessGroupService.createServiceAgreement(any(), any())).thenReturn(Mono.just(sa)); @@ -507,8 +499,9 @@ private void executeAndVerifyTask(LegalEntityTask task, int createServiceAgreeme } /** - * Intention of this test is to verify that {@link ProductGroupTask} are processed in order at (in short that - * .concatMap is used instead of .flatMap). Otherwise it may happen that during permission assignment at + * Intention of this test is to verify that {@link ProductGroupTask} are processed in order at + * (in short that .concatMap is used instead of .flatMap). + * Otherwise it may happen that during permission assignment at * {@link AccessGroupService#assignPermissionsBatch(BatchProductGroupTask, Map)} there will be stale set of * permissions which will lead to state when not all of desired applied */ @@ -526,8 +519,8 @@ void productGroupsProcessedSequentially() { .referenceJobRoles(Collections.singletonList(new JobRole() .name("Job Role with Limits").functionGroups(Collections.singletonList(new BusinessFunctionGroup() .name("someFunctionGroup") - .addFunctionsItem(new BusinessFunction().functionId("1071").name("US Domestic Wire") - .addPrivilegesItem(new Privilege().privilege("create").limit(limit))))))) + .addFunctionsItem(new BusinessFunction().functionId("1071").name("US Domestic Wire") + .addPrivilegesItem(new Privilege().privilege("create").limit(limit))))))) .productGroups(Arrays.asList( (ProductGroup) new ProductGroup() .productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS) @@ -618,13 +611,13 @@ void productGroupsProcessedSequentially() { when(legalEntitySagaConfigurationProperties.isUseIdentityIntegration()) .thenReturn(true); when(legalEntitySagaConfigurationProperties.isServiceAgreementUpdateEnabled()) - .thenReturn(true); + .thenReturn(true); when(userService.setupRealm(legalEntityTask.getLegalEntity())) .thenReturn(Mono.empty()); when(userService.linkLegalEntityToRealm(legalEntityTask.getLegalEntity())) .thenReturn(Mono.empty()); when(userService.updateIdentity(any())) - .thenReturn(Mono.empty()); + .thenReturn(Mono.empty()); when(userService.getUserByExternalId("john.doe")) .thenReturn(Mono.just(new User().internalId("100").externalId("john.doe"))); when(userService.createOrImportIdentityUser(any(), any(), any())) @@ -632,7 +625,7 @@ void productGroupsProcessedSequentially() { when(accessGroupService.getServiceAgreementByExternalId("Service_Agreement_Id")) .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); lenient().when(accessGroupService.updateServiceAgreementItem(any(), any())) - .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); + .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); when(accessGroupService.updateServiceAgreementAssociations(any(), any(), any())) .thenReturn(Mono.just(new ServiceAgreement().internalId("101").externalId("Service_Agreement_Id"))); when(accessGroupService.createServiceAgreement(any(), (ServiceAgreement) any())) @@ -645,7 +638,7 @@ void productGroupsProcessedSequentially() { when(accessGroupService.getUserByExternalId("john.doe", true)) .thenReturn(Mono.just(new GetUser().externalId("john.doe").id("internalId"))); when(limitsSaga.executeTask(any())).thenReturn(Mono.just(new LimitsTask("1", new CreateLimitRequestBody()))); - // when(contactsSaga.executeTask(any())).thenReturn(Mono.just(new ContactsTask("1", new ContactsBulkPostRequestBody()))); + // when(contactsSaga.executeTask(any())).thenReturn(Mono.just(new ContactsTask("1", new ContactsBulkPostRequestBody()))); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))) .thenAnswer((Answer>) invocationOnMock -> { ProductGroupTask productGroupTask = invocationOnMock.getArgument(0); @@ -757,31 +750,30 @@ void updateLegalEntityName() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntity newLE = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("New Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(newLE); @@ -791,8 +783,7 @@ void updateLegalEntityName() { when(accessGroupService.getServiceAgreementByExternalId(eq(customSaExId))).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( - Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); when(userService.getUserByExternalId(eq(regularUserExId))).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(eq(adminExId))).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -802,7 +793,7 @@ void updateLegalEntityName() { when(userService.updateUser(any())).thenReturn(Mono.empty()); LegalEntityTask result = legalEntitySaga.executeTask(task) - .block(); + .block(); Assertions.assertNotNull(result); Assertions.assertEquals(newLE.getName(), result.getData().getName()); @@ -819,26 +810,25 @@ void updateUserName() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); JobProfileUser newRegularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId).fullName("New Name Regular User")); + .externalId(regularUserExId).fullName("New Name Regular User")); JobProfileUser oldRegularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId).fullName("Old Name Regular User")); + .externalId(regularUserExId).fullName("Old Name Regular User")); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId).fullName("Admin"); legalEntity = new LegalEntity().internalId(leInternalId).externalId(leExternalId).name("Model Bank") - .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) - .customServiceAgreement(customSa).users(singletonList(newRegularUser)) - .productGroups(singletonList(productGroup)).subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .addAdministratorsItem(adminUser).parentExternalId(leParentExternalId) + .customServiceAgreement(customSa).users(singletonList(newRegularUser)) + .productGroups(singletonList(productGroup)).subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -861,13 +851,13 @@ void updateUserName() { when(userService.updateUser(any())).thenReturn(Mono.just(newRegularUser.getUser())); LegalEntityTask result = legalEntitySaga.executeTask(task) - .block(); + .block(); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getData().getUsers()); Assertions.assertNotNull(result.getData().getUsers().get(0)); Assertions.assertEquals(newRegularUser.getUser().getFullName(), - result.getData().getUsers().get(0).getUser().getFullName()); + result.getData().getUsers().get(0).getUser().getFullName()); verify(accessGroupService).createServiceAgreement(eq(task), eq(customSa)); verify(accessGroupService).updateServiceAgreementRegularUsers(eq(task), eq(customSa), any()); @@ -880,30 +870,29 @@ void getMockLegalEntity() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); legalEntity = new LegalEntity() - .internalId(leInternalId) - .externalId(leExternalId) - .addAdministratorsItem(adminUser) - .parentExternalId(leParentExternalId) - .customServiceAgreement(customSa) - .users(singletonList(regularUser)) - .productGroups(singletonList(productGroup)) - .subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .internalId(leInternalId) + .externalId(leExternalId) + .addAdministratorsItem(adminUser) + .parentExternalId(leParentExternalId) + .customServiceAgreement(customSa) + .users(singletonList(regularUser)) + .productGroups(singletonList(productGroup)) + .subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); when(legalEntityService.getLegalEntityByExternalId(leExternalId)).thenReturn(Mono.empty()); when(legalEntityService.getLegalEntityByInternalId(leInternalId)).thenReturn(Mono.just(legalEntity)); @@ -911,8 +900,7 @@ void getMockLegalEntity() { when(accessGroupService.getServiceAgreementByExternalId(customSaExId)).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( - Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); when(userService.getUserByExternalId(regularUserExId)).thenReturn(Mono.just(regularUser.getUser())); when(userService.getUserByExternalId(adminExId)).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); @@ -945,32 +933,31 @@ void test_PostLegalContacts_NoUser() { account.externalId("someAccountExId").productTypeExternalId("Account").currency("GBP"); ProductGroup productGroup = new ProductGroup(); productGroup.productGroupType(BaseProductGroup.ProductGroupTypeEnum.ARRANGEMENTS).name("somePgName") - .description("somePgDescription").savingAccounts(singletonList(account)); + .description("somePgDescription").savingAccounts(singletonList(account)); ProductGroupTask productGroupTask = new ProductGroupTask(productGroup); Mono productGroupTaskMono = Mono.just(productGroupTask); regularUser = new JobProfileUser().user(new User().internalId("someRegularUserInId") - .externalId(regularUserExId)); + .externalId(regularUserExId)); BusinessFunctionGroup functionGroup = new BusinessFunctionGroup().name("someFunctionGroup"); JobRole jobRole = new JobRole().functionGroups(singletonList(functionGroup)).name("someJobRole"); - customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) - .creatorLegalEntity(leExternalId); + customSa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole).creatorLegalEntity(leExternalId); User adminUser = new User().internalId("someAdminInId").externalId(adminExId); ExternalContact contact = getMockExternalContact(); legalEntity = new LegalEntity() - .internalId(leInternalId) - .externalId(leExternalId) - .addAdministratorsItem(adminUser) - .parentExternalId(leParentExternalId) - .customServiceAgreement(customSa) - .productGroups(singletonList(productGroup)) - .contacts(Collections.singletonList(contact)) - .subsidiaries(singletonList( - new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) - )); + .internalId(leInternalId) + .externalId(leExternalId) + .addAdministratorsItem(adminUser) + .parentExternalId(leParentExternalId) + .customServiceAgreement(customSa) + .productGroups(singletonList(productGroup)) + .contacts(Collections.singletonList(contact)) + .subsidiaries(singletonList( + new LegalEntity().externalId(leExternalId).customServiceAgreement(customSa) + )); LegalEntityTask task = mockLegalEntityTask(legalEntity); @@ -980,8 +967,7 @@ void test_PostLegalContacts_NoUser() { when(accessGroupService.getServiceAgreementByExternalId(customSaExId)).thenReturn(Mono.empty()); when(accessGroupService.createServiceAgreement(any(), eq(customSa))).thenReturn(Mono.just(customSa)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); - when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn( - Mono.just(customSa)); + when(accessGroupService.updateServiceAgreementRegularUsers(any(), eq(customSa), any())).thenReturn(Mono.just(customSa)); when(userService.getUserByExternalId(adminExId)).thenReturn(Mono.just(adminUser)); when(userService.createUser(any(), any(), any())).thenReturn(Mono.empty()); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))).thenReturn(productGroupTaskMono); @@ -1008,25 +994,22 @@ void test_PostSAContacts() { customSa.setContacts(Collections.singletonList(contact)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals(leExternalId, - result.getData().getCustomServiceAgreement().getContacts().get(0).getExternalId()); + Assertions.assertEquals(leExternalId, result.getData().getCustomServiceAgreement().getContacts().get(0).getExternalId()); LegalEntityParticipant participant = new LegalEntityParticipant() - .externalId(leExternalId) - .sharingUsers(true) - .users(singletonList("USER1")); + .externalId(leExternalId) + .sharingUsers(true) + .users(singletonList("USER1")); customSa.setParticipants(singletonList(participant)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals("USER1", - result.getData().getCustomServiceAgreement().getParticipants().get(0).getUsers().get(0)); + Assertions.assertEquals("USER1", result.getData().getCustomServiceAgreement().getParticipants().get(0).getUsers().get(0)); participant = participant.users(null).admins(singletonList("ADMIN1")); customSa.setParticipants(singletonList(participant)); result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); - Assertions.assertEquals("ADMIN1", - result.getData().getCustomServiceAgreement().getParticipants().get(0).getAdmins().get(0)); + Assertions.assertEquals("ADMIN1", result.getData().getCustomServiceAgreement().getParticipants().get(0).getAdmins().get(0)); } @@ -1186,7 +1169,7 @@ private LegalEntityTask mockLegalEntityTask(LegalEntity legalEntity) { } private LegalEntitySagaConfigurationProperties getLegalEntitySagaConfigurationProperties() { - LegalEntitySagaConfigurationProperties sagaConfiguration = new LegalEntitySagaConfigurationProperties(); + LegalEntitySagaConfigurationProperties sagaConfiguration = new LegalEntitySagaConfigurationProperties(); sagaConfiguration.setUseIdentityIntegration(true); sagaConfiguration.setUserProfileEnabled(true); return sagaConfiguration; @@ -1195,13 +1178,13 @@ private LegalEntitySagaConfigurationProperties getLegalEntitySagaConfigurationPr private ExternalContact getMockExternalContact() { ExternalAccountInformation externalAccount = new ExternalAccountInformation() - .name("ACC1") - .externalId("ACCEXT1") - .accountNumber("12345"); + .name("ACC1") + .externalId("ACCEXT1") + .accountNumber("12345"); return new ExternalContact() - .name("Sam") - .externalId(leExternalId) - .accounts(Collections.singletonList(externalAccount)); + .name("Sam") + .externalId(leExternalId) + .accounts(Collections.singletonList(externalAccount)); } private ContactsBulkPostRequestBody getMockContactsBulkRequest(AccessContextScope accessContextScope) { From 0bfe2bc06e36406fde5ca65585b26e81a85ee4ac Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 19:10:46 +0200 Subject: [PATCH 13/41] Update LegalEntitySagaTest to mock upsertParty method in CustomerProfileService --- .../java/com/backbase/stream/LegalEntitySagaTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 19cfe04fd..b36bf1bff 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -362,6 +362,9 @@ void masterServiceAgreementCreation_activateSingleServiceAgreement() { void testCustomServiceAgreement_IfFetchedServiceAgreementExists_ThenSettingUp() { var task = setupLegalEntityTask(); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + mockAccessGroupService(userId); mockUserService(userId); @@ -375,6 +378,8 @@ void testCustomServiceAgreement_IfFetchedServiceAgreementExists_ThenSettingUp() void testCustomServiceAgreement_IfNoCustomServiceAgreementExists_ThenCreateMaster() { var task = setupLegalEntityTask(); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); when(accessGroupService.getUserContextsByUserId(userId)).thenReturn(Mono.empty()); mockUserService(userId); @@ -388,6 +393,9 @@ void testCustomServiceAgreement_IfNoCustomServiceAgreementExists_ThenCreateMaste void testCustomServiceAgreement_IfNoMatchingCustomServiceAgreementExists_ThenCreateMaster() { LegalEntityTask task = setupLegalEntityTask(); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + when(accessGroupService.getUserContextsByUserId(userId)) .thenReturn( Mono.just(List.of(new ServiceAgreement().internalId("sa_id").externalId("sa_ext_id").purpose("TEST")))); @@ -457,7 +465,7 @@ private LegalEntityTask setupLegalEntityTask() { var jobRole = new JobRole("someJobRole", "someJobRole"); jobRole.setFunctionGroups(singletonList(functionGroup)); - legalEntity = new LegalEntity("le_name", null, null); + var legalEntity = new LegalEntity("le_name", null, null); legalEntity.setInternalId(leInternalId); legalEntity.setExternalId(leExternalId); legalEntity.setParentExternalId(leExternalId); From b5edf73b000b47ee2c9c2e9ecc0c8e50a12f9230 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 23 Apr 2025 20:20:19 +0200 Subject: [PATCH 14/41] Add tests for CustomerProfileConfiguration and enhance LegalEntitySagaTest with error handling --- .../CustomerProfileConfigurationTest.java | 35 +++++++++++++++++++ .../backbase/stream/LegalEntitySagaTest.java | 34 ++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java new file mode 100644 index 000000000..e655f9985 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java @@ -0,0 +1,35 @@ +package com.backbase.stream.configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import com.backbase.buildingblocks.webclient.InterServiceWebClientConfiguration; +import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; +import com.backbase.stream.clients.config.CustomerProfileClientConfig; +import com.backbase.stream.service.CustomerProfileService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.web.reactive.function.client.WebClient; + +@SpringJUnitConfig +class CustomerProfileConfigurationTest { + + ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + void configurationTest() { + contextRunner + .withBean(WebClientAutoConfiguration.class) + .withBean(InterServiceWebClientConfiguration.class) + .withBean(PartyManagementIntegrationApi.class, () -> mock(PartyManagementIntegrationApi.class)) + .withUserConfiguration(CustomerProfileConfiguration.class) + .run(context -> { + assertThat(context).hasSingleBean(CustomerProfileService.class); + assertThat(context).hasSingleBean(PartyManagementIntegrationApi.class); + assertThat(context).hasSingleBean(WebClient.class); + assertThat(context).hasSingleBean(CustomerProfileClientConfig.class); + }); + } +} \ No newline at end of file diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index b36bf1bff..ccfb1b937 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -4,7 +4,9 @@ import static java.util.Collections.singletonList; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -431,6 +433,38 @@ void testProcessCustomerProfile_IfPartyFound_ThenUpsertParty() { verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class)); } + @Test + void testProcessCustomerProfile_IfUpsertPartyError_ThenTrowException() { + var task = setupLegalEntityTask(); + var mockException = new WebClientResponseException( + "CPS Error", + 400, + "Bad Request", + null, + null, + null + ); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn(Mono.error(mockException)); + + mockAccessGroupService(userId); + mockUserService(userId); + legalEntitySaga.executeTask(task).block(); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class)); + verify(task, times(PARTY_SIZE)).error( + eq(LegalEntitySaga.PARTY), + eq(LegalEntitySaga.PROCESS_CUSTOMER_PROFILE), + eq("failed"), + anyString(), + isNull(), + any(Throwable.class), + anyString(), + eq("Error upserting party: %s for LE: %s"), + anyString(), + anyString() + ); + } + + private void mockUserService(String userId) { when(userService.getUsersByLegalEntity(any(), anyInt(), anyInt())) .thenReturn(Mono.just(new GetUsersList().totalElements(1L) From 19a6b0ec2f19ff87875877a233386c00913b575b Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 00:06:52 +0200 Subject: [PATCH 15/41] Add AddressMapper for mapping between legal entity models and upsert DTOs --- api/stream-legal-entity/openapi.yaml | 4 +- .../customer-profile-core/pom.xml | 8 +- .../CustomerProfileConfiguration.java | 54 ++++- .../backbase/stream/mapper/AddressMapper.java | 41 ++++ .../stream/mapper/DemographicsMapper.java | 27 +++ .../mapper/ElectronicAddressMapper.java | 20 ++ .../stream/mapper/IdentificationMapper.java | 22 ++ .../stream/mapper/OrganisationMapper.java | 25 +++ .../backbase/stream/mapper/PartyMapper.java | 33 +++ .../mapper/PartyRelationshipMapper.java | 22 ++ .../backbase/stream/mapper/PersonMapper.java | 25 +++ .../service/CustomerProfileService.java | 7 +- .../CustomerProfileConfigurationTest.java | 2 + .../backbase/stream/mapper/MapperTest.java | 190 ++++++++++++++++++ .../service/CustomerProfileServiceTest.java | 3 +- 15 files changed, 473 insertions(+), 10 deletions(-) create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java create mode 100644 stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index f265b6dfe..f117656c7 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1306,9 +1306,7 @@ components: items: $ref: '#/components/schemas/PhoneAddress' electronicAddress: - type: array - items: - $ref: '#/components/schemas/ElectronicAddress' + $ref: '#/components/schemas/ElectronicAddress' preferredLanguage: type: string maxLength: 50 diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml index 074b255b8..521f38ed3 100644 --- a/stream-customer-profile/customer-profile-core/pom.xml +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -26,9 +26,8 @@ org.mapstruct - mapstruct-processor + mapstruct - org.springframework.boot spring-boot-configuration-processor @@ -41,6 +40,11 @@ ${project.version} compile + + org.mapstruct + mapstruct-processor + provided + com.backbase.stream diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java index fd781cbfc..d4a45a22c 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java @@ -2,8 +2,17 @@ import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.stream.clients.config.CustomerProfileClientConfig; +import com.backbase.stream.mapper.AddressMapper; +import com.backbase.stream.mapper.DemographicsMapper; +import com.backbase.stream.mapper.ElectronicAddressMapper; +import com.backbase.stream.mapper.IdentificationMapper; +import com.backbase.stream.mapper.OrganisationMapper; +import com.backbase.stream.mapper.PartyMapper; +import com.backbase.stream.mapper.PartyRelationshipMapper; +import com.backbase.stream.mapper.PersonMapper; import com.backbase.stream.service.CustomerProfileService; import lombok.extern.slf4j.Slf4j; +import org.mapstruct.factory.Mappers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,9 +22,50 @@ @EnableConfigurationProperties(CustomerProfileClientConfig.class) public class CustomerProfileConfiguration { + + @Bean + public PartyMapper partyMapper() { + return Mappers.getMapper(PartyMapper.class); + } + + @Bean + public AddressMapper addressMapper() { + return Mappers.getMapper(AddressMapper.class); + } + + @Bean + public IdentificationMapper identificationMapper() { + return Mappers.getMapper(IdentificationMapper.class); + } + + @Bean + public DemographicsMapper demographicsMapper() { + return Mappers.getMapper(DemographicsMapper.class); + } + + @Bean + public PersonMapper personMapper() { + return Mappers.getMapper(PersonMapper.class); + } + + @Bean + public OrganisationMapper organisationMapper() { + return Mappers.getMapper(OrganisationMapper.class); + } + + @Bean + public PartyRelationshipMapper partyRelationshipMapper() { + return Mappers.getMapper(PartyRelationshipMapper.class); + } + + @Bean + public ElectronicAddressMapper electronicAddressMapper() { + return Mappers.getMapper(ElectronicAddressMapper.class); + } + @Bean public CustomerProfileService createCustomerProfileService( - PartyManagementIntegrationApi partyManagementIntegrationApi) { - return new CustomerProfileService(partyManagementIntegrationApi); + PartyManagementIntegrationApi partyManagementIntegrationApi, PartyMapper partyMapper) { + return new CustomerProfileService(partyManagementIntegrationApi, partyMapper); } } diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java new file mode 100644 index 000000000..9e573954b --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java @@ -0,0 +1,41 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.EmailUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.PhoneNumberUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.PostalAddressUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.UrlUpsertDto; +import com.backbase.stream.legalentity.model.EmailAddress; +import com.backbase.stream.legalentity.model.PartyPostalAddress; +import com.backbase.stream.legalentity.model.PhoneAddress; +import com.backbase.stream.legalentity.model.Url; +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE +) +public interface AddressMapper { + + AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class); + + PostalAddressUpsertDto postalAddressToPostalAddressUpsertDto(PartyPostalAddress source); + + List postalAddressListToPostalAddressUpsertDtoList(List source); + + + PhoneNumberUpsertDto phoneAddressToPhoneNumberUpsertDto(PhoneAddress source); + + List phoneAddressListToPhoneNumberUpsertDtoList(List source); + + EmailUpsertDto emailAddressToEmailUpsertDto(EmailAddress source); + + List emailAddressListToEmailUpsertDtoList(List source); + + UrlUpsertDto urlToUrlUpsertDto(Url source); + + List urlListToUrlUpsertDtoList(List source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java new file mode 100644 index 000000000..b0efd3c23 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java @@ -0,0 +1,27 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDtoEducation; +import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDtoOccupation; +import com.backbase.stream.legalentity.model.PersonDemographics; +import com.backbase.stream.legalentity.model.PersonDemographicsEducation; +import com.backbase.stream.legalentity.model.PersonDemographicsOccupation; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE +) +public interface DemographicsMapper { + + DemographicsMapper INSTANCE = Mappers.getMapper(DemographicsMapper.class); + + DemographicsUpsertDto personDemographicsToDemographicsUpsertDto(PersonDemographics source); + + DemographicsUpsertDtoOccupation occupationToDto(PersonDemographicsOccupation source); + + DemographicsUpsertDtoEducation educationToDto(PersonDemographicsEducation source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java new file mode 100644 index 000000000..1dc39c89e --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java @@ -0,0 +1,20 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.ElectronicAddressesUpsertDto; +import com.backbase.stream.legalentity.model.ElectronicAddress; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE, + uses = {AddressMapper.class} +) +public interface ElectronicAddressMapper { + + ElectronicAddressMapper INSTANCE = Mappers.getMapper(ElectronicAddressMapper.class); + + ElectronicAddressesUpsertDto electronicAddressToDto(ElectronicAddress source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java new file mode 100644 index 000000000..a8e7cb584 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java @@ -0,0 +1,22 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.IdentificationUpsertDto; +import com.backbase.stream.legalentity.model.Identification; +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE +) +public interface IdentificationMapper { + + IdentificationMapper INSTANCE = Mappers.getMapper(IdentificationMapper.class); + + IdentificationUpsertDto identificationToIdentificationUpsertDto(Identification source); + + List identificationListToIdentificationUpsertDtoList(List source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java new file mode 100644 index 000000000..b0e527310 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java @@ -0,0 +1,25 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.OrganisationUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.OrganisationUpsertDtoLegalStructure; +import com.backbase.stream.legalentity.model.Organisation; +import com.backbase.stream.legalentity.model.OrganisationLegalStructure; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE, + uses = {IdentificationMapper.class} +) +public interface OrganisationMapper { + + OrganisationMapper INSTANCE = Mappers.getMapper(OrganisationMapper.class); + + OrganisationUpsertDto organisationToOrganisationUpsertDto(Organisation source); + + OrganisationUpsertDtoLegalStructure legalStructureToDto(OrganisationLegalStructure source); + +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java new file mode 100644 index 000000000..f0a459372 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java @@ -0,0 +1,33 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; +import com.backbase.stream.legalentity.model.Party; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE, + uses = { + PersonMapper.class, + OrganisationMapper.class, + PartyRelationshipMapper.class, + AddressMapper.class, + ElectronicAddressMapper.class + } +) +public interface PartyMapper { + + PartyMapper INSTANCE = Mappers.getMapper(PartyMapper.class); + + @Mapping(target = "additions", source = "customFields") + @Mapping(target = "phoneNumbers", source = "phoneAddresses") + @Mapping(target = "electronicAddresses", source = "electronicAddress") + @Mapping(target = "legalEntityId", ignore = true) + @Mapping(target = "subState", ignore = true) + PartyUpsertDto partyToPartyUpsertDto(Party party); + +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java new file mode 100644 index 000000000..3c9699ffe --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java @@ -0,0 +1,22 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.PartyPartyRelationshipUpsertDto; +import com.backbase.stream.legalentity.model.PartyRelationship; +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE +) +public interface PartyRelationshipMapper { + + PartyRelationshipMapper INSTANCE = Mappers.getMapper(PartyRelationshipMapper.class); + + PartyPartyRelationshipUpsertDto relationshipToDto(PartyRelationship source); + + List relationshipListToDtoList(List source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java new file mode 100644 index 000000000..512f891d1 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java @@ -0,0 +1,25 @@ +package com.backbase.stream.mapper; + +import com.backbase.customerprofile.api.integration.v1.model.PersonNameUpsertDto; +import com.backbase.customerprofile.api.integration.v1.model.PersonUpsertDto; +import com.backbase.stream.legalentity.model.Person; +import com.backbase.stream.legalentity.model.PersonName; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + + +@Mapper( + componentModel = MappingConstants.ComponentModel.SPRING, + unmappedTargetPolicy = ReportingPolicy.IGNORE, + uses = {IdentificationMapper.class, DemographicsMapper.class} +) +public interface PersonMapper { + + PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class); + + PersonUpsertDto personToPersonUpsertDto(Person source); + + PersonNameUpsertDto personNameToPersonNameUpsertDto(PersonName source); +} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 0d6f7b688..7272668c3 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -4,6 +4,7 @@ import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; import com.backbase.stream.legalentity.model.Party; +import com.backbase.stream.mapper.PartyMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.reactive.function.client.WebClientResponseException; @@ -15,6 +16,8 @@ public class CustomerProfileService { private final PartyManagementIntegrationApi partyManagementIntegrationApi; + private final PartyMapper partyMapper; + public Mono upsertParty(PartyUpsertDto partyUpsertDto) throws WebClientResponseException { return partyManagementIntegrationApi.upsertParty(partyUpsertDto) @@ -28,8 +31,8 @@ public Mono upsertParty(PartyUpsertDto partyUpsertDto) public Mono upsertParty(Party party) { - // TODO: Implement the conversion from Party to PartyUpsertDto + var partyUpsertDto = partyMapper.partyToPartyUpsertDto(party); - return upsertParty(new PartyUpsertDto()); + return upsertParty(partyUpsertDto); } } diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java index e655f9985..3e5519720 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java @@ -6,6 +6,7 @@ import com.backbase.buildingblocks.webclient.InterServiceWebClientConfiguration; import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.stream.clients.config.CustomerProfileClientConfig; +import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.service.CustomerProfileService; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; @@ -30,6 +31,7 @@ void configurationTest() { assertThat(context).hasSingleBean(PartyManagementIntegrationApi.class); assertThat(context).hasSingleBean(WebClient.class); assertThat(context).hasSingleBean(CustomerProfileClientConfig.class); + assertThat(context).hasSingleBean(PartyMapper.class); }); } } \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java new file mode 100644 index 000000000..003917735 --- /dev/null +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -0,0 +1,190 @@ +package com.backbase.stream.mapper; + + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import com.backbase.stream.legalentity.model.Party; +import com.navercorp.fixturemonkey.FixtureMonkey; +import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; +import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; +import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.arbitraries.StringArbitrary; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = { + PartyMapperImpl.class, + PersonMapperImpl.class, + OrganisationMapperImpl.class, + PartyRelationshipMapperImpl.class, + AddressMapperImpl.class, + ElectronicAddressMapperImpl.class, + IdentificationMapperImpl.class, + DemographicsMapperImpl.class +}) +public class MapperTest { + + @Autowired + private PartyMapper partyMapper; + private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) + .defaultNotNull(true) + .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { + @Override + public StringArbitrary strings() { + return Arbitraries.strings().alpha(); + } + })) + .build(); + + @Test + void testPartyToPartyUpsertDtoMapping() { + + var party = fixtureMonkey.giveMeOne(Party.class); + + assertNotNull(party.getPartyId(), "FixtureMonkey should generate a partyId"); + assertNotNull(party.getIsCustomer(), "FixtureMonkey should generate isCustomer"); + assertNotNull(party.getPartyType(), "FixtureMonkey should generate partyType"); + + var resultDto = partyMapper.partyToPartyUpsertDto(party); + + assertNotNull(resultDto); + + assertEquals(party.getPartyId(), resultDto.getPartyId()); + assertEquals(party.getIsCustomer(), resultDto.getIsCustomer()); + + if (party.getPartyType() != null) { + assertNotNull(resultDto.getPartyType()); + assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); // + } else { + assertNull(resultDto.getPartyType()); + } + // Compara el valor del Enum State + if (party.getState() != null) { + assertNotNull(resultDto.getState()); + assertEquals(party.getState().getValue(), resultDto.getState().getValue()); // + } else { + assertNull(resultDto.getState()); + } + assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); // + assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); // + assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); // + assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); // + assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); // + assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); // + assertEquals(party.getNotes(), resultDto.getNotes()); // + + assertNull(resultDto.getLegalEntityId(), "legalEntityId debe ser ignorado por el mapper"); + assertNull(resultDto.getSubState(), "subState debe ser ignorado por el mapper"); + + if (party.getCustomFields() != null) { + assertNotNull(resultDto.getAdditions()); + assertEquals(party.getCustomFields().size(), resultDto.getAdditions().size()); + assertEquals(party.getCustomFields(), resultDto.getAdditions()); + } + + if (party.getPhoneAddresses() != null) { + assertNotNull(resultDto.getPhoneNumbers()); + assertEquals(party.getPhoneAddresses().size(), resultDto.getPhoneNumbers().size()); + + if (!party.getPhoneAddresses().isEmpty()) { + assertEquals(party.getPhoneAddresses().get(0).getNumber(), + resultDto.getPhoneNumbers().get(0).getNumber()); + } + } else { + assertNull(resultDto.getPhoneNumbers()); + } + + if (party.getElectronicAddress() != null) { + assertNotNull(resultDto.getElectronicAddresses()); + if (party.getElectronicAddress().getEmails() != null) { + assertNotNull(resultDto.getElectronicAddresses().getEmails()); + assertEquals(party.getElectronicAddress().getEmails().size(), + resultDto.getElectronicAddresses().getEmails().size()); + } else { + assertNull(resultDto.getElectronicAddresses().getEmails()); + } + if (party.getElectronicAddress().getUrls() != null) { + assertNotNull(resultDto.getElectronicAddresses().getUrls()); + assertEquals(party.getElectronicAddress().getUrls().size(), + resultDto.getElectronicAddresses().getUrls().size()); + } else { + assertNull(resultDto.getElectronicAddresses().getUrls()); + } + } else { + assertNull(resultDto.getElectronicAddresses()); + } + + if (party.getPerson() != null) { + assertNotNull(resultDto.getPerson()); + + assertEquals(party.getPerson().getPersonName().getFirstName(), + resultDto.getPerson().getPersonName().getFirstName()); + + assertEquals(party.getPerson().getPersonName().getFamilyName(), + resultDto.getPerson().getPersonName().getFamilyName()); + if (party.getPerson().getIdentifications() != null) { + assertNotNull(resultDto.getPerson().getIdentifications()); + assertEquals(party.getPerson().getIdentifications().size(), + resultDto.getPerson().getIdentifications().size()); + } else { + assertNull(resultDto.getPerson().getIdentifications()); + } + if (party.getPerson().getDemographics() != null) { + assertNotNull(resultDto.getPerson().getDemographics()); + } else { + assertNull(resultDto.getPerson().getDemographics()); + } + + } else { + if (party.getPartyType() != Party.PartyTypeEnum.PERSON) { + assertNull(resultDto.getPerson()); + } else { + assertNull(resultDto.getPerson()); + } + } + + if (party.getOrganisation() != null) { + assertNotNull(resultDto.getOrganisation()); // + assertEquals(party.getOrganisation().getName(), resultDto.getOrganisation().getName()); + if (party.getOrganisation().getIdentifications() != null) { + assertNotNull(resultDto.getOrganisation().getIdentifications()); + assertEquals(party.getOrganisation().getIdentifications().size(), + resultDto.getOrganisation().getIdentifications().size()); + } else { + assertNull(resultDto.getOrganisation().getIdentifications()); + } + if (party.getOrganisation().getLegalStructure() != null) { + assertNotNull(resultDto.getOrganisation().getLegalStructure()); + // Añade más aserciones para legal structure aquí + } else { + assertNull(resultDto.getOrganisation().getLegalStructure()); + } + } else { + if (party.getPartyType() != Party.PartyTypeEnum.ORGANISATION) { + assertNull(resultDto.getOrganisation()); + } else { + assertNull(resultDto.getOrganisation()); + } + } + + if (party.getPostalAddresses() != null) { + assertNotNull(resultDto.getPostalAddresses()); // + assertEquals(party.getPostalAddresses().size(), resultDto.getPostalAddresses().size()); // + } else { + assertNull(resultDto.getPostalAddresses()); + } + + if (party.getPartyPartyRelationships() != null) { + assertNotNull(resultDto.getPartyPartyRelationships()); // + assertEquals(party.getPartyPartyRelationships().size(), resultDto.getPartyPartyRelationships().size()); // + } else { + assertNull(resultDto.getPartyPartyRelationships()); + } + + } +} diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index 85d171a8c..7be1cd776 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -7,6 +7,7 @@ import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; +import com.backbase.stream.mapper.PartyMapper; import com.navercorp.fixturemonkey.FixtureMonkey; import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; @@ -46,7 +47,7 @@ public StringArbitrary strings() { @BeforeEach void setup() { - customerProfileService = new CustomerProfileService(partyManagementIntegrationApiMock); + customerProfileService = new CustomerProfileService(partyManagementIntegrationApiMock, PartyMapper.INSTANCE); } @Test From e3d6c7ebb284ea713dd8e4f305ac0da738e88c01 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 09:38:58 +0200 Subject: [PATCH 16/41] Refactor assertions in MapperTest for clarity and consistency --- .../java/com/backbase/stream/mapper/MapperTest.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index 003917735..416a446c7 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -63,7 +63,6 @@ void testPartyToPartyUpsertDtoMapping() { } else { assertNull(resultDto.getPartyType()); } - // Compara el valor del Enum State if (party.getState() != null) { assertNotNull(resultDto.getState()); assertEquals(party.getState().getValue(), resultDto.getState().getValue()); // @@ -149,7 +148,7 @@ void testPartyToPartyUpsertDtoMapping() { } if (party.getOrganisation() != null) { - assertNotNull(resultDto.getOrganisation()); // + assertNotNull(resultDto.getOrganisation()); assertEquals(party.getOrganisation().getName(), resultDto.getOrganisation().getName()); if (party.getOrganisation().getIdentifications() != null) { assertNotNull(resultDto.getOrganisation().getIdentifications()); @@ -160,7 +159,6 @@ void testPartyToPartyUpsertDtoMapping() { } if (party.getOrganisation().getLegalStructure() != null) { assertNotNull(resultDto.getOrganisation().getLegalStructure()); - // Añade más aserciones para legal structure aquí } else { assertNull(resultDto.getOrganisation().getLegalStructure()); } @@ -173,15 +171,15 @@ void testPartyToPartyUpsertDtoMapping() { } if (party.getPostalAddresses() != null) { - assertNotNull(resultDto.getPostalAddresses()); // - assertEquals(party.getPostalAddresses().size(), resultDto.getPostalAddresses().size()); // + assertNotNull(resultDto.getPostalAddresses()); + assertEquals(party.getPostalAddresses().size(), resultDto.getPostalAddresses().size()); } else { assertNull(resultDto.getPostalAddresses()); } if (party.getPartyPartyRelationships() != null) { - assertNotNull(resultDto.getPartyPartyRelationships()); // - assertEquals(party.getPartyPartyRelationships().size(), resultDto.getPartyPartyRelationships().size()); // + assertNotNull(resultDto.getPartyPartyRelationships()); + assertEquals(party.getPartyPartyRelationships().size(), resultDto.getPartyPartyRelationships().size()); } else { assertNull(resultDto.getPartyPartyRelationships()); } From 5160c4894893aefddf627e127010fd768042d189 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 10:25:12 +0200 Subject: [PATCH 17/41] Refactor assertions in MapperTest for clarity and consistency --- .../backbase/stream/mapper/MapperTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index 416a446c7..37bda7aa8 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -59,26 +59,26 @@ void testPartyToPartyUpsertDtoMapping() { if (party.getPartyType() != null) { assertNotNull(resultDto.getPartyType()); - assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); // + assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); } else { assertNull(resultDto.getPartyType()); } if (party.getState() != null) { assertNotNull(resultDto.getState()); - assertEquals(party.getState().getValue(), resultDto.getState().getValue()); // + assertEquals(party.getState().getValue(), resultDto.getState().getValue()); } else { assertNull(resultDto.getState()); } - assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); // - assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); // - assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); // - assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); // - assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); // - assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); // - assertEquals(party.getNotes(), resultDto.getNotes()); // - - assertNull(resultDto.getLegalEntityId(), "legalEntityId debe ser ignorado por el mapper"); - assertNull(resultDto.getSubState(), "subState debe ser ignorado por el mapper"); + assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); + assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); + assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); + assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); + assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); + assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); + assertEquals(party.getNotes(), resultDto.getNotes()); + + assertNull(resultDto.getLegalEntityId(), "legalEntityId ignored by mapper"); + assertNull(resultDto.getSubState(), "subState ignored by mapper"); if (party.getCustomFields() != null) { assertNotNull(resultDto.getAdditions()); From 3175512751d39a3cc9aeab17328add678b934cee Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 10:32:38 +0200 Subject: [PATCH 18/41] Introduce FixtureUtils for centralized FixtureMonkey configuration in tests --- .../backbase/stream/mapper/MapperTest.java | 12 ++-------- .../service/CustomerProfileServiceTest.java | 11 ++------- .../backbase/stream/LegalEntitySagaTest.java | 11 ++------- .../com/backbase/stream/FixtureUtils.java | 23 +++++++++++++++++++ 4 files changed, 29 insertions(+), 28 deletions(-) create mode 100644 stream-sdk/stream-parent/stream-test-support/src/main/java/com/backbase/stream/FixtureUtils.java diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index 37bda7aa8..c430c8c12 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -1,6 +1,7 @@ package com.backbase.stream.mapper; +import static com.backbase.stream.FixtureUtils.reflectiveAlphaFixtureMonkey; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -30,16 +31,7 @@ public class MapperTest { @Autowired private PartyMapper partyMapper; - private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) - .defaultNotNull(true) - .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { - @Override - public StringArbitrary strings() { - return Arbitraries.strings().alpha(); - } - })) - .build(); + private final FixtureMonkey fixtureMonkey = reflectiveAlphaFixtureMonkey; @Test void testPartyToPartyUpsertDtoMapping() { diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index 7be1cd776..51b2fb9c2 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -1,5 +1,6 @@ package com.backbase.stream.service; +import static com.backbase.stream.FixtureUtils.reflectiveAlphaFixtureMonkey; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -32,15 +33,7 @@ class CustomerProfileServiceTest { private CustomerProfileService customerProfileService; - private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) - .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { - @Override - public StringArbitrary strings() { - return Arbitraries.strings().alpha(); - } - })) - .build(); + private final FixtureMonkey fixtureMonkey = reflectiveAlphaFixtureMonkey; @Mock private PartyManagementIntegrationApi partyManagementIntegrationApiMock; diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index ccfb1b937..036e9da0b 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -1,5 +1,6 @@ package com.backbase.stream; +import static com.backbase.stream.FixtureUtils.reflectiveAlphaFixtureMonkey; import static com.backbase.stream.service.UserService.REMOVED_PREFIX; import static java.util.Collections.singletonList; import static org.mockito.ArgumentMatchers.any; @@ -140,15 +141,7 @@ class LegalEntitySagaTest { private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties = getLegalEntitySagaConfigurationProperties(); - private final FixtureMonkey fixtureMonkey = FixtureMonkey.builder() - .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) - .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { - @Override - public StringArbitrary strings() { - return Arbitraries.strings().alpha(); - } - })) - .build(); + private final FixtureMonkey fixtureMonkey = reflectiveAlphaFixtureMonkey; private static final int PARTY_SIZE = 10; diff --git a/stream-sdk/stream-parent/stream-test-support/src/main/java/com/backbase/stream/FixtureUtils.java b/stream-sdk/stream-parent/stream-test-support/src/main/java/com/backbase/stream/FixtureUtils.java new file mode 100644 index 000000000..7f433845e --- /dev/null +++ b/stream-sdk/stream-parent/stream-test-support/src/main/java/com/backbase/stream/FixtureUtils.java @@ -0,0 +1,23 @@ +package com.backbase.stream; + +import com.navercorp.fixturemonkey.FixtureMonkey; +import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; +import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; +import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.arbitraries.StringArbitrary; + +public class FixtureUtils { + + public static final FixtureMonkey reflectiveAlphaFixtureMonkey = FixtureMonkey.builder() + .objectIntrospector(FieldReflectionArbitraryIntrospector.INSTANCE) + .defaultNotNull(true) + .plugin(new JqwikPlugin().javaTypeArbitraryGenerator(new JavaTypeArbitraryGenerator() { + @Override + public StringArbitrary strings() { + return Arbitraries.strings().alpha(); + } + })) + .build(); + +} From ef70371a9a782f9c1c9d4664c6f263d6db1e2155 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 17:52:00 +0200 Subject: [PATCH 19/41] Refactor PartyMapper and CustomerProfileConfiguration for improved mapper instantiation and remove unused mappers --- api/stream-legal-entity/openapi.yaml | 873 +++++++++--------- .../CustomerProfileConfiguration.java | 45 +- .../backbase/stream/mapper/AddressMapper.java | 41 - .../stream/mapper/DemographicsMapper.java | 27 - .../mapper/ElectronicAddressMapper.java | 20 - .../stream/mapper/IdentificationMapper.java | 22 - .../stream/mapper/OrganisationMapper.java | 25 - .../backbase/stream/mapper/PartyMapper.java | 13 +- .../mapper/PartyRelationshipMapper.java | 22 - .../backbase/stream/mapper/PersonMapper.java | 25 - .../backbase/stream/mapper/MapperTest.java | 59 +- 11 files changed, 482 insertions(+), 690 deletions(-) delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java delete mode 100644 stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index f117656c7..9428d9ec0 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1248,289 +1248,6 @@ components: $ref: '#/components/schemas/ExternalContact' required: - user - Party: - type: object - properties: - partyId: - $ref: '#/components/schemas/ExternalIdentifier' - isDigital: - type: boolean - isCustomer: - type: boolean - description: Indicates if it is a customer or not. - partyType: - type: string - enum: - - PERSON - - ORGANISATION - description: Type of party in different business contexts. - person: - $ref: '#/components/schemas/Person' - organisation: - $ref: '#/components/schemas/Organisation' - partyPartyRelationships: - type: array - items: - $ref: '#/components/schemas/PartyRelationship' - closingDateTime: - type: string - format: date-time - description: Date on which the party and related services cease effectively to be operational for the party. - approvedDateTime: - type: string - format: date-time - description: Date on which the party and related basic services are approved. - lastUpdatedDateTime: - type: string - format: date-time - description: Date on which there was any update to the party and related basic services. - openingDateTime: - type: string - format: date-time - description: Date on which the party and related basic services are effectively operational for the party. - liveDateTime: - type: string - format: date-time - description: Date of the first movement on the party. - state: - type: string - enum: - - ENROLLED - - EXITED - postalAddresses: - type: array - items: - $ref: '#/components/schemas/PartyPostalAddress' - phoneAddresses: - type: array - items: - $ref: '#/components/schemas/PhoneAddress' - electronicAddress: - $ref: '#/components/schemas/ElectronicAddress' - preferredLanguage: - type: string - maxLength: 50 - description: Language preferred by party. - notes: - type: string - maxLength: 100 - description: Notes on the party. - customFields: - type: object - additionalProperties: - type: string - required: - - partyId - - isCustomer - - partyType - Person: - type: object - properties: - identifications: - type: array - description: List of specific identification assigned to a party. - minItems: 1 - items: - $ref: '#/components/schemas/Identification' - personName: - $ref: '#/components/schemas/PersonName' - gender: - type: string - enum: - - MALE - - FEMALE - - NON_BINARY - description: Person's gender - birthDate: - type: string - format: date - description: Indicates person birthdate - demographics: - type: object - properties: - occupation: - type: object - properties: - employment: - type: string - description: Type of employment of the party. - maxLength: 100 - employer: - type: string - description: Details of the party's employment. - maxLength: 100 - education: - type: object - properties: - educationLevel: - type: string - description: Party's education level, such as qualifications and certifications. - maxLength: 100 - yearOfPassing: - type: string - maxLength: 20 - description: Year of completing the qualification. - required: - - personName - - identifications - Organisation: - type: object - properties: - name: - type: string - description: Organisation Name - maxLength: 64 - type: - type: string - maxLength: 64 - description: Specifies a type of organisation. - sector: - type: string - maxLength: 255 - description: Sector of business of the organisation, for example, pharmaceutical. (ISO20022) - establishmentDate: - type: string - format: date - description: Date when the organisation was established. - legalStructure: - type: object - properties: - type: - type: string - maxLength: 64 - description: Individual, Partnership and Corporation - required: - - type - identifications: - type: array - description: List of specific identification assigned to a party. - minItems: 1 - items: - $ref: '#/components/schemas/Identification' - required: - - name - - identifications - Identification: - type: object - properties: - identificationType: - type: string - enum: - - TaxIdentificationNumber - - NationalRegistrationNumber - - RegistrationAuthorityIdentification - - LegalEntityIdentifier - - AlienRegistrationNumber - - PassportNumber - - TaxExemptionIdentificationNumber - - CorporateIdentification - - DriverLicenseNumber - - ForeignInvestmentIdentityNumber - - SocialSecurityNumber - - IdentityCardNumber - - Concat - - NationalRegistrationIdentificationNumber - - CustomerIdentificationNumber - - EmployeeIdentificationNumber - - NationalIdentityNumber - - TelephoneNumber - - EmployerIdentificationNumber - - CentralBankIdentificationNumber - - ClearingIdentificationNumber - - BankPartyIdentification - - CertificateOfIncorporationNumber - - CountryIdentificationCode - - CustomerNumber - - DataUniversalNumberingSystem - - GS1GLNIdentifier - - ELF - - SIREN - - SIRET - - MIC - - BICFI - - DUNS - - EANGLN - description: Identification Type of the identity document. - identificationNumber: - type: string - maxLength: 100 - description: Number or code assigned by the government authority to an entity - issuingCountry: - type: string - maxLength: 100 - description: Identifies issuing country of the identity document. - issuingAuthority: - type: string - maxLength: 100 - description: Identifies issuing authority of the identity document. - issueDate: - type: string - format: date - description: Identifies issue date of the identity document. - expiryDate: - type: string - format: date - description: Identifies expiry date of the identity document. - required: - - identificationType - - identificationNumber - PartyRelationship: - type: object - properties: - partyId: - $ref: '#/components/schemas/ExternalIdentifier' - partyType: - type: string - enum: - - PERSON - - ORGANISATION - description: Specifies the type of party in different business contexts. - partyRole: - type: string - description: Identifies role of a party - enum: - - COMPANY_ROLE - - COMPANY_OWNERSHIP - - COMPANY_CONTROL_PERSON - - COMPANY_SIGNATORY - - GUARDIAN - roleStartDate: - type: string - format: date - description: Identifies start date of the party role - roleEndDate: - type: string - format: date - description: Identifies end date of the party role - ownershipPercent: - type: integer - description: Identifies the percentage of stake/ownership for a related person/organisation in this organisation. Total ownership percent must not exceed 100% - minimum: 0 - maximum: 100 - required: - - partyId - - partyRole - PersonName: - type: object - properties: - salutation: - type: string - maxLength: 20 - firstName: - type: string - description: First name of the person. - maxLength: 64 - middleName: - type: string - description: Middle name of the person. - maxLength: 64 - familyName: - type: string - description: Family name of the person. - maxLength: 64 - required: - - firstName - LegalEntityType: type: string title: Legal Entity Type @@ -1600,46 +1317,31 @@ components: - externalId - fullName EmailAddress: - type: object - properties: - type: - type: string - enum: - - WORK - - PERSONAL - - HOME - - OTHERS - description: Identifies the type of email. Possible values - WORK, PERSONAL, HOME, OTHERS. - primary: - type: boolean - description: Flag denoting whether this is the primary email address of the party. - address: - type: string - maxLength: 100 - description: Address for electronic mail (e-mail) (ISO20022). + title: "The email addresses the user can be reached by." required: - - type - address - Url: + - key + - type type: object properties: + key: + maxLength: 70 + minLength: 1 + type: string + description: Unique key identifying the email address. type: + maxLength: 36 + minLength: 1 type: string - enum: - - WORK - - PERSONAL - description: Identifies the type of URL. Possible Values - WORK, PERSONAL. + description: Key identifying the type of electronic address, e.g. work or personal. primary: type: boolean - description: Flag denoting whether this is the primary url address of the party. + description: Flag denoting whether this is the main electronic address. address: - type: string maxLength: 255 - description: Address for the Universal Resource Locator (URL), used over the www (HTTP) service. - required: - - address - - type - + minLength: 1 + type: string + description: Address. PhoneNumber: required: - key @@ -1720,104 +1422,6 @@ components: maxLength: 3 type: string description: Country code - ISO 3166. - PartyPostalAddress: - type: object - properties: - type: - type: string - enum: - - Business - - Correspondence - - DeliveryTo - - MailTo - - POBox - - Postal - - Residential - - Statement - description: Identifies the type of postal address. - primary: - type: boolean - description: Flag denoting whether this is the primary postal address of the party. - department: - type: string - maxLength: 100 - description: Identification of a division of a large organisation or building (ISO20022). - subDepartment: - type: string - maxLength: 100 - description: Identification of a sub-division of a large organisation or building (ISO20022). - addressLine: - type: string - maxLength: 100 - description: Information that locates and identifies a specific address, as defined by postal services, presented in free format text (ISO20022). - buildingNumber: - type: string - maxLength: 50 - description: Number that identifies the position of a building on a street (ISO20022). - streetName: - type: string - maxLength: 100 - description: Name of a street or thoroughfare (ISO20022). - townName: - type: string - maxLength: 100 - description: Name of a built-up area, with defined boundaries, and a local government (ISO20022). - postalCode: - type: string - maxLength: 12 - description: Identifier consisting of a group of letters and/or numbers that is added to a postal address to assist the sorting of mail (ISO20022). - countrySubDivision: - type: string - maxLength: 100 - description: Identifies name of a country subdivision such as state, region, county. For example - Oregon. - country: - type: string - maxLength: 100 - description: Country name. - required: - - type - - PhoneAddress: - type: object - properties: - type: - type: string - enum: - - MOBILE - - HOME - - WORK - - OTHER - description: Identifies the type of the phone address. For example - MOBILE, LANDLINE, HOME, WORK, FAX. - primary: - type: boolean - description: Flag denoting if its the primary phone address of the party. - number: - type: string - maxLength: 50 - description: Collection of information that identifies a phone address, as defined by telecom services (ISO20022). - countryCode: - type: string - maxLength: 3 - description: Phone’s country calling code. Country calling code can be obtained from https://countrycode.org/. - countryIsoCode: - type: string - maxLength: 3 - description: Phone’s ISO country code. Country code can be obtained from the United Nations (ISO 3166, Alpha-2 code)- https://www.iban.com/country-codes. - required: - - type - - number - ElectronicAddress: - type: object - properties: - emails: - type: array - items: - $ref: '#/components/schemas/EmailAddress' - urls: - type: array - items: - $ref: '#/components/schemas/Url' - Limit: title: Limit type: object @@ -2023,7 +1627,7 @@ components: type: boolean ServiceAgreement: - title: Service Agreement + title: Service Agreement description: | The formal vehicle that allows users of one entity to access products of that or other entities A Service agreement is: @@ -2254,7 +1858,7 @@ components: title: External Identifier maxLength: 64 minLength: 1 - # pattern: ^{1,64}$ +# pattern: ^{1,64}$ type: string description: External legal entity identifier. UrgentTransfer: @@ -2786,7 +2390,7 @@ components: maxLength: 255 type: string description: Email-id of the contact - # format: email +# format: email addressLine1: maxLength: 70 type: string @@ -2954,7 +2558,7 @@ components: type: string description: "An email account identifier. At least one of the account identifiers\ \ (accountNumber, IBAN, phoneNumber or email) is mandatory." - # format: email +# format: email Additions: title: Additions type: object @@ -3496,7 +3100,444 @@ components: description: Subscription identifier required: - identifier - + Party: + type: object + properties: + partyId: + type: string + description: Core System Identifier + maxLength: 100 + legalEntityId: + type: string + description: Legal Entity Id from Access Control. + pattern: ^[0-9a-f]{32}$|^[0-9a-f-]{36}$ + isCustomer: + type: boolean + description: Indicates if it is a customer or not. + partyType: + type: string + enum: + - PERSON + - ORGANISATION + description: Type of party in different business contexts. + state: + type: string + enum: + - ENROLLED + - EXITED + subState: + type: string + enum: + - OPENED + - APPROVED + - ACTIVE + - DORMANT + - CLOSED + description: Status of the party. + openingDateTime: + type: string + format: date-time + description: Date on which the party and related basic services are effectively operational for the party. + closingDateTime: + type: string + format: date-time + description: Date on which the party and related services cease effectively to be operational for the party. + liveDateTime: + type: string + format: date-time + description: Date of the first movement on the party. + approvedDateTime: + type: string + format: date-time + description: Date on which the party and related basic services are approved. + lastUpdatedDateTime: + type: string + format: date-time + description: Date on which there was any update to the party and related basic services. + preferredLanguage: + type: string + maxLength: 50 + description: Language preferred by party. + notes: + type: string + maxLength: 100 + description: Notes on the party. + organisation: + $ref: '#/components/schemas/Organization' + person: + $ref: '#/components/schemas/Person' + partyPartyRelationships: + type: array + items: + $ref: '#/components/schemas/PartyPartyRelationship' + electronicAddresses: + $ref: '#/components/schemas/ElectronicAddress' + postalAddresses: + type: array + items: + $ref: '#/components/schemas/PartyPostalAddress' + phoneNumbers: + type: array + items: + $ref: '#/components/schemas/PartyPhoneNumber' + customFields: + type: object + additionalProperties: + type: string + required: + - partyId + - isCustomer + - partyType + Organization: + type: object + properties: + name: + type: string + description: Organisation Name + maxLength: 64 + type: + type: string + maxLength: 64 + description: Specifies a type of organisation. + sector: + type: string + maxLength: 255 + description: Sector of business of the organisation, for example, pharmaceutical. (ISO20022) + establishmentDate: + type: string + format: date + description: Date when the organisation was established. + legalStructure: + type: object + properties: + type: + type: string + maxLength: 64 + description: Individual, Partnership and Corporation + required: + - type + identifications: + type: array + description: List of specific identification assigned to a party. + minItems: 1 + items: + $ref: '#/components/schemas/Identification' + required: + - name + - identifications + Identification: + type: object + properties: + identificationType: + type: string + enum: + - TaxIdentificationNumber + - NationalRegistrationNumber + - RegistrationAuthorityIdentification + - LegalEntityIdentifier + - AlienRegistrationNumber + - PassportNumber + - TaxExemptionIdentificationNumber + - CorporateIdentification + - DriverLicenseNumber + - ForeignInvestmentIdentityNumber + - SocialSecurityNumber + - IdentityCardNumber + - Concat + - NationalRegistrationIdentificationNumber + - CustomerIdentificationNumber + - EmployeeIdentificationNumber + - NationalIdentityNumber + - TelephoneNumber + - EmployerIdentificationNumber + - CentralBankIdentificationNumber + - ClearingIdentificationNumber + - BankPartyIdentification + - CertificateOfIncorporationNumber + - CountryIdentificationCode + - CustomerNumber + - DataUniversalNumberingSystem + - GS1GLNIdentifier + - ELF + - SIREN + - SIRET + - MIC + - BICFI + - DUNS + - EANGLN + description: Identification Type of the identity document. + identificationNumber: + type: string + maxLength: 100 + description: Number or code assigned by the government authority to an entity + issuingCountry: + type: string + maxLength: 100 + description: Identifies issuing country of the identity document. + issuingAuthority: + type: string + maxLength: 100 + description: Identifies issuing authority of the identity document. + issueDate: + type: string + format: date + description: Identifies issue date of the identity document. + expiryDate: + type: string + format: date + description: Identifies expiry date of the identity document. + required: + - identificationType + - identificationNumber + Person: + type: object + properties: + birthDate: + type: string + format: date + description: Indicates person birthdate + gender: + type: string + enum: + - MALE + - FEMALE + - NON_BINARY + description: Person's gender + personName: + $ref: '#/components/schemas/PersonName' + demographics: + $ref: '#/components/schemas/Demographics' + identifications: + type: array + description: List of specific identification assigned to a party. + minItems: 1 + items: + $ref: '#/components/schemas/Identification' + required: + - personName + - identifications + PersonName: + type: object + properties: + salutation: + type: string + maxLength: 20 + firstName: + type: string + description: First name of the person. + maxLength: 64 + middleName: + type: string + description: Middle name of the person. + maxLength: 64 + familyName: + type: string + description: Family name of the person. + maxLength: 64 + required: + - firstName + Demographics: + type: object + properties: + occupation: + type: object + properties: + employment: + type: string + description: Type of employment of the party. + maxLength: 100 + employer: + type: string + description: Details of the party's employment. + maxLength: 100 + education: + type: object + properties: + educationLevel: + type: string + description: Party's education level, such as qualifications and certifications. + maxLength: 100 + yearOfPassing: + type: string + maxLength: 20 + description: Year of completing the qualification. + PartyPartyRelationship: + type: object + properties: + partyId: + type: string + maxLength: 100 + description: Core System Id + partyType: + type: string + enum: + - PERSON + - ORGANISATION + description: Specifies the type of party in different business contexts. + partyRole: + type: string + description: Identifies role of a party + enum: + - COMPANY_ROLE + - COMPANY_OWNERSHIP + - COMPANY_CONTROL_PERSON + - COMPANY_SIGNATORY + - GUARDIAN + roleStartDate: + type: string + format: date + description: Identifies start date of the party role + roleEndDate: + type: string + format: date + description: Identifies end date of the party role + ownershipPercent: + type: integer + description: Identifies the percentage of stake/ownership for a related person/organisation in this organisation. Total ownership percent must not exceed 100% + minimum: 0 + maximum: 100 + required: + - partyId + - partyRole + ElectronicAddress: + type: object + description: Address which is accessed by electronic means. + properties: + emails: + type: array + description: Email(s) of the party. + items: + $ref: '#/components/schemas/Email' + urls: + type: array + description: Address for the Universal Resource Locator (URL), used over the www (HTTP) service. + items: + $ref: '#/components/schemas/Url' + Email: + type: object + properties: + type: + type: string + enum: + - WORK + - PERSONAL + - HOME + - OTHERS + description: Identifies the type of email. Possible values - WORK, PERSONAL, HOME, OTHERS. + primary: + type: boolean + description: Flag denoting whether this is the primary email address of the party. + address: + type: string + maxLength: 100 + description: Address for electronic mail (e-mail) (ISO20022). + required: + - type + - address + Url: + type: object + properties: + type: + type: string + enum: + - WORK + - PERSONAL + description: Identifies the type of URL. Possible Values - WORK, PERSONAL. + primary: + type: boolean + description: Flag denoting whether this is the primary url address of the party. + address: + type: string + maxLength: 255 + description: Address for the Universal Resource Locator (URL), used over the www (HTTP) service. + required: + - address + - type + PartyPostalAddress: + type: object + properties: + type: + type: string + enum: + - Business + - Correspondence + - DeliveryTo + - MailTo + - POBox + - Postal + - Residential + - Statement + description: Identifies the type of postal address. + primary: + type: boolean + description: Flag denoting whether this is the primary postal address of the party. + department: + type: string + maxLength: 100 + description: Identification of a division of a large organisation or building (ISO20022). + subDepartment: + type: string + maxLength: 100 + description: Identification of a sub-division of a large organisation or building (ISO20022). + addressLine: + type: string + maxLength: 100 + description: Information that locates and identifies a specific address, as defined by postal services, presented in free format text (ISO20022). + buildingNumber: + type: string + maxLength: 50 + description: Number that identifies the position of a building on a street (ISO20022). + streetName: + type: string + maxLength: 100 + description: Name of a street or thoroughfare (ISO20022). + townName: + type: string + maxLength: 100 + description: Name of a built-up area, with defined boundaries, and a local government (ISO20022). + postalCode: + type: string + maxLength: 12 + description: Identifier consisting of a group of letters and/or numbers that is added to a postal address to assist the sorting of mail (ISO20022). + countrySubDivision: + type: string + maxLength: 100 + description: Identifies name of a country subdivision such as state, region, county. For example - Oregon. + country: + type: string + maxLength: 100 + description: Country name. + required: + - type + PartyPhoneNumber: + type: object + properties: + type: + type: string + enum: + - MOBILE + - HOME + - WORK + - OTHER + description: Identifies the type of the phone address. For example - MOBILE, LANDLINE, HOME, WORK, FAX. + primary: + type: boolean + description: Flag denoting if its the primary phone address of the party. + number: + type: string + maxLength: 50 + description: Collection of information that identifies a phone address, as defined by telecom services (ISO20022). + countryCode: + type: string + maxLength: 3 + description: Phone’s country calling code. Country calling code can be obtained from https://countrycode.org/. + countryIsoCode: + type: string + maxLength: 3 + description: Phone’s ISO country code. Country code can be obtained from the United Nations (ISO 3166, Alpha-2 code)- https://www.iban.com/country-codes. + required: + - type + - number examples: RootLegalEntityHierarchyExample: description: "Example Request for setting up Root Legal Entity Structure as described on Backbase Community" diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java index d4a45a22c..c350b4b01 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java @@ -2,17 +2,9 @@ import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.stream.clients.config.CustomerProfileClientConfig; -import com.backbase.stream.mapper.AddressMapper; -import com.backbase.stream.mapper.DemographicsMapper; -import com.backbase.stream.mapper.ElectronicAddressMapper; -import com.backbase.stream.mapper.IdentificationMapper; -import com.backbase.stream.mapper.OrganisationMapper; import com.backbase.stream.mapper.PartyMapper; -import com.backbase.stream.mapper.PartyRelationshipMapper; -import com.backbase.stream.mapper.PersonMapper; import com.backbase.stream.service.CustomerProfileService; import lombok.extern.slf4j.Slf4j; -import org.mapstruct.factory.Mappers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -25,42 +17,7 @@ public class CustomerProfileConfiguration { @Bean public PartyMapper partyMapper() { - return Mappers.getMapper(PartyMapper.class); - } - - @Bean - public AddressMapper addressMapper() { - return Mappers.getMapper(AddressMapper.class); - } - - @Bean - public IdentificationMapper identificationMapper() { - return Mappers.getMapper(IdentificationMapper.class); - } - - @Bean - public DemographicsMapper demographicsMapper() { - return Mappers.getMapper(DemographicsMapper.class); - } - - @Bean - public PersonMapper personMapper() { - return Mappers.getMapper(PersonMapper.class); - } - - @Bean - public OrganisationMapper organisationMapper() { - return Mappers.getMapper(OrganisationMapper.class); - } - - @Bean - public PartyRelationshipMapper partyRelationshipMapper() { - return Mappers.getMapper(PartyRelationshipMapper.class); - } - - @Bean - public ElectronicAddressMapper electronicAddressMapper() { - return Mappers.getMapper(ElectronicAddressMapper.class); + return PartyMapper.INSTANCE; } @Bean diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java deleted file mode 100644 index 9e573954b..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/AddressMapper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.EmailUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.PhoneNumberUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.PostalAddressUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.UrlUpsertDto; -import com.backbase.stream.legalentity.model.EmailAddress; -import com.backbase.stream.legalentity.model.PartyPostalAddress; -import com.backbase.stream.legalentity.model.PhoneAddress; -import com.backbase.stream.legalentity.model.Url; -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE -) -public interface AddressMapper { - - AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class); - - PostalAddressUpsertDto postalAddressToPostalAddressUpsertDto(PartyPostalAddress source); - - List postalAddressListToPostalAddressUpsertDtoList(List source); - - - PhoneNumberUpsertDto phoneAddressToPhoneNumberUpsertDto(PhoneAddress source); - - List phoneAddressListToPhoneNumberUpsertDtoList(List source); - - EmailUpsertDto emailAddressToEmailUpsertDto(EmailAddress source); - - List emailAddressListToEmailUpsertDtoList(List source); - - UrlUpsertDto urlToUrlUpsertDto(Url source); - - List urlListToUrlUpsertDtoList(List source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java deleted file mode 100644 index b0efd3c23..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/DemographicsMapper.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDtoEducation; -import com.backbase.customerprofile.api.integration.v1.model.DemographicsUpsertDtoOccupation; -import com.backbase.stream.legalentity.model.PersonDemographics; -import com.backbase.stream.legalentity.model.PersonDemographicsEducation; -import com.backbase.stream.legalentity.model.PersonDemographicsOccupation; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE -) -public interface DemographicsMapper { - - DemographicsMapper INSTANCE = Mappers.getMapper(DemographicsMapper.class); - - DemographicsUpsertDto personDemographicsToDemographicsUpsertDto(PersonDemographics source); - - DemographicsUpsertDtoOccupation occupationToDto(PersonDemographicsOccupation source); - - DemographicsUpsertDtoEducation educationToDto(PersonDemographicsEducation source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java deleted file mode 100644 index 1dc39c89e..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/ElectronicAddressMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.ElectronicAddressesUpsertDto; -import com.backbase.stream.legalentity.model.ElectronicAddress; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = {AddressMapper.class} -) -public interface ElectronicAddressMapper { - - ElectronicAddressMapper INSTANCE = Mappers.getMapper(ElectronicAddressMapper.class); - - ElectronicAddressesUpsertDto electronicAddressToDto(ElectronicAddress source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java deleted file mode 100644 index a8e7cb584..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/IdentificationMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.IdentificationUpsertDto; -import com.backbase.stream.legalentity.model.Identification; -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE -) -public interface IdentificationMapper { - - IdentificationMapper INSTANCE = Mappers.getMapper(IdentificationMapper.class); - - IdentificationUpsertDto identificationToIdentificationUpsertDto(Identification source); - - List identificationListToIdentificationUpsertDtoList(List source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java deleted file mode 100644 index b0e527310..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/OrganisationMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.OrganisationUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.OrganisationUpsertDtoLegalStructure; -import com.backbase.stream.legalentity.model.Organisation; -import com.backbase.stream.legalentity.model.OrganisationLegalStructure; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = {IdentificationMapper.class} -) -public interface OrganisationMapper { - - OrganisationMapper INSTANCE = Mappers.getMapper(OrganisationMapper.class); - - OrganisationUpsertDto organisationToOrganisationUpsertDto(Organisation source); - - OrganisationUpsertDtoLegalStructure legalStructureToDto(OrganisationLegalStructure source); - -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java index f0a459372..e0cbf3eda 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java @@ -10,24 +10,13 @@ @Mapper( componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = { - PersonMapper.class, - OrganisationMapper.class, - PartyRelationshipMapper.class, - AddressMapper.class, - ElectronicAddressMapper.class - } + unmappedTargetPolicy = ReportingPolicy.IGNORE ) public interface PartyMapper { PartyMapper INSTANCE = Mappers.getMapper(PartyMapper.class); @Mapping(target = "additions", source = "customFields") - @Mapping(target = "phoneNumbers", source = "phoneAddresses") - @Mapping(target = "electronicAddresses", source = "electronicAddress") - @Mapping(target = "legalEntityId", ignore = true) - @Mapping(target = "subState", ignore = true) PartyUpsertDto partyToPartyUpsertDto(Party party); } \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java deleted file mode 100644 index 3c9699ffe..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyRelationshipMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.PartyPartyRelationshipUpsertDto; -import com.backbase.stream.legalentity.model.PartyRelationship; -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE -) -public interface PartyRelationshipMapper { - - PartyRelationshipMapper INSTANCE = Mappers.getMapper(PartyRelationshipMapper.class); - - PartyPartyRelationshipUpsertDto relationshipToDto(PartyRelationship source); - - List relationshipListToDtoList(List source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java deleted file mode 100644 index 512f891d1..000000000 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PersonMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.backbase.stream.mapper; - -import com.backbase.customerprofile.api.integration.v1.model.PersonNameUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.PersonUpsertDto; -import com.backbase.stream.legalentity.model.Person; -import com.backbase.stream.legalentity.model.PersonName; -import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; - - -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE, - uses = {IdentificationMapper.class, DemographicsMapper.class} -) -public interface PersonMapper { - - PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class); - - PersonUpsertDto personToPersonUpsertDto(Person source); - - PersonNameUpsertDto personNameToPersonNameUpsertDto(PersonName source); -} \ No newline at end of file diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index c430c8c12..2bc968eb1 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -8,25 +8,11 @@ import com.backbase.stream.legalentity.model.Party; import com.navercorp.fixturemonkey.FixtureMonkey; -import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; -import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; -import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; -import net.jqwik.api.Arbitraries; -import net.jqwik.api.arbitraries.StringArbitrary; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -@SpringBootTest(classes = { - PartyMapperImpl.class, - PersonMapperImpl.class, - OrganisationMapperImpl.class, - PartyRelationshipMapperImpl.class, - AddressMapperImpl.class, - ElectronicAddressMapperImpl.class, - IdentificationMapperImpl.class, - DemographicsMapperImpl.class -}) +@SpringBootTest(classes = PartyMapperImpl.class) public class MapperTest { @Autowired @@ -51,26 +37,27 @@ void testPartyToPartyUpsertDtoMapping() { if (party.getPartyType() != null) { assertNotNull(resultDto.getPartyType()); - assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); + assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); } else { assertNull(resultDto.getPartyType()); } if (party.getState() != null) { assertNotNull(resultDto.getState()); - assertEquals(party.getState().getValue(), resultDto.getState().getValue()); + assertEquals(party.getState().getValue(), resultDto.getState().getValue()); } else { assertNull(resultDto.getState()); } - assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); - assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); - assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); - assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); - assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); - assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); - assertEquals(party.getNotes(), resultDto.getNotes()); - - assertNull(resultDto.getLegalEntityId(), "legalEntityId ignored by mapper"); - assertNull(resultDto.getSubState(), "subState ignored by mapper"); + assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); + assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); + assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); + assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); + assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); + assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); + assertEquals(party.getNotes(), resultDto.getNotes()); + + assertEquals(party.getLegalEntityId(), resultDto.getLegalEntityId()); + assertNotNull(resultDto.getSubState()); + assertEquals(party.getSubState().getValue(), resultDto.getSubState().getValue()); if (party.getCustomFields() != null) { assertNotNull(resultDto.getAdditions()); @@ -78,30 +65,30 @@ void testPartyToPartyUpsertDtoMapping() { assertEquals(party.getCustomFields(), resultDto.getAdditions()); } - if (party.getPhoneAddresses() != null) { + if (party.getPhoneNumbers() != null) { assertNotNull(resultDto.getPhoneNumbers()); - assertEquals(party.getPhoneAddresses().size(), resultDto.getPhoneNumbers().size()); + assertEquals(party.getPhoneNumbers().size(), resultDto.getPhoneNumbers().size()); - if (!party.getPhoneAddresses().isEmpty()) { - assertEquals(party.getPhoneAddresses().get(0).getNumber(), + if (!party.getPhoneNumbers().isEmpty()) { + assertEquals(party.getPhoneNumbers().get(0).getNumber(), resultDto.getPhoneNumbers().get(0).getNumber()); } } else { assertNull(resultDto.getPhoneNumbers()); } - if (party.getElectronicAddress() != null) { + if (party.getElectronicAddresses() != null) { assertNotNull(resultDto.getElectronicAddresses()); - if (party.getElectronicAddress().getEmails() != null) { + if (party.getElectronicAddresses().getEmails() != null) { assertNotNull(resultDto.getElectronicAddresses().getEmails()); - assertEquals(party.getElectronicAddress().getEmails().size(), + assertEquals(party.getElectronicAddresses().getEmails().size(), resultDto.getElectronicAddresses().getEmails().size()); } else { assertNull(resultDto.getElectronicAddresses().getEmails()); } - if (party.getElectronicAddress().getUrls() != null) { + if (party.getElectronicAddresses().getUrls() != null) { assertNotNull(resultDto.getElectronicAddresses().getUrls()); - assertEquals(party.getElectronicAddress().getUrls().size(), + assertEquals(party.getElectronicAddresses().getUrls().size(), resultDto.getElectronicAddresses().getUrls().size()); } else { assertNull(resultDto.getElectronicAddresses().getUrls()); From e3dad8c2ff76f59e87d5450a7b6a1df115ec75ef Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 18:21:21 +0200 Subject: [PATCH 20/41] Refactor LegalEntitySaga and CustomerProfileService for improved party setup and streamline upsertParty method --- .../stream/service/CustomerProfileService.java | 12 ++---------- .../java/com/backbase/stream/LegalEntitySaga.java | 6 +++--- .../com/backbase/stream/LegalEntitySagaTest.java | 4 +++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 7272668c3..d578abb54 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -7,7 +7,6 @@ import com.backbase.stream.mapper.PartyMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; @Slf4j @@ -18,15 +17,8 @@ public class CustomerProfileService { private final PartyMapper partyMapper; - public Mono upsertParty(PartyUpsertDto partyUpsertDto) - throws WebClientResponseException { - return partyManagementIntegrationApi.upsertParty(partyUpsertDto) - .doOnError(WebClientResponseException.class, e -> { - log.error("Error creating customer profile: {}", e.getMessage()); - throw e; - }) - .doOnSuccess(customerResponseDto -> - log.info("Customer profile created successfully: {}", customerResponseDto)); + public Mono upsertParty(PartyUpsertDto partyUpsertDto) { + return partyManagementIntegrationApi.upsertParty(partyUpsertDto); } public Mono upsertParty(Party party) { diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index 60cbb4938..3f7d6debc 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -182,6 +182,7 @@ public LegalEntitySaga( public Mono executeTask(@SpanTag(value = "streamTask") LegalEntityTask streamTask) { return upsertLegalEntity(streamTask) .flatMap(this::linkLegalEntityToRealm) + .flatMap(this::setupParties) .flatMap(this::setupAdministrators) .flatMap(this::setupUsers) .flatMap(this::processAudiencesSegmentation) @@ -192,8 +193,7 @@ public Mono executeTask(@SpanTag(value = "streamTask") LegalEnt .flatMap(this::setupLimits) .flatMap(this::processProducts) .flatMap(this::postContacts) - .flatMap(this::processSubsidiaries) - .flatMap(this::processCustomerProfile); + .flatMap(this::processSubsidiaries); } private Mono processAudiencesSegmentation(LegalEntityTask streamTask) { @@ -1099,7 +1099,7 @@ private Mono processSubsidiaries(LegalEntityTask streamTask) { }); } - private Mono processCustomerProfile(LegalEntityTask legalEntityTask) { + private Mono setupParties(LegalEntityTask legalEntityTask) { log.info("Processing Customer Profile Parties for: {}", legalEntityTask.getName()); var legalEntity = legalEntityTask.getData(); diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 036e9da0b..612b56357 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -407,6 +407,8 @@ void testCustomServiceAgreement_IfNoUserDataFoundWhileServiceAgreementFetch_thro LegalEntityTask task = setupLegalEntityTask(); when(userService.getUsersByLegalEntity(any(), anyInt(), anyInt())) .thenReturn(Mono.just(new GetUsersList().totalElements(0L).users(null))); + when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); Assertions.assertThrows( StreamTaskException.class, () -> executeLegalEntityTaskAndBlock(task), @@ -416,7 +418,7 @@ void testCustomServiceAgreement_IfNoUserDataFoundWhileServiceAgreementFetch_thro } @Test - void testProcessCustomerProfile_IfPartyFound_ThenUpsertParty() { + void testSetupParties_IfPartyFound_ThenUpsertParty() { var task = setupLegalEntityTask(); when(customerProfileService.upsertParty(any(Party.class))).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); From be7a61628f9b5a88f25dfac98d91dd73835d8e0e Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 18:42:03 +0200 Subject: [PATCH 21/41] Refactor upsertParty method in CustomerProfileService to include legalEntityExternalId and update LegalEntitySaga accordingly --- .../stream/service/CustomerProfileService.java | 11 +++++------ .../service/CustomerProfileServiceTest.java | 18 +++++++----------- .../com/backbase/stream/LegalEntitySaga.java | 2 +- .../backbase/stream/LegalEntitySagaTest.java | 16 ++++++++-------- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index d578abb54..5e8fe3e59 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -17,14 +17,13 @@ public class CustomerProfileService { private final PartyMapper partyMapper; - public Mono upsertParty(PartyUpsertDto partyUpsertDto) { - return partyManagementIntegrationApi.upsertParty(partyUpsertDto); - } - - public Mono upsertParty(Party party) { + public Mono upsertParty(Party party, String legalEntityExternalId) { + if (legalEntityExternalId != null && !legalEntityExternalId.trim().isEmpty() && party.getIsCustomer()) { + party.partyId(legalEntityExternalId); + } var partyUpsertDto = partyMapper.partyToPartyUpsertDto(party); - return upsertParty(partyUpsertDto); + return partyManagementIntegrationApi.upsertParty(partyUpsertDto); } } diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index 51b2fb9c2..be66366c7 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -8,15 +8,11 @@ import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; +import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.mapper.PartyMapper; import com.navercorp.fixturemonkey.FixtureMonkey; -import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; -import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; -import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; import java.nio.charset.StandardCharsets; import java.util.UUID; -import net.jqwik.api.Arbitraries; -import net.jqwik.api.arbitraries.StringArbitrary; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -47,7 +43,7 @@ void setup() { @DisplayName("Upsert party should return PartyResponseUpsertDto when API call is successful") void createCustomer_success() { var legalEntityId = UUID.randomUUID().toString(); - var requestDto = fixtureMonkey.giveMeBuilder(PartyUpsertDto.class) + var requestDto = fixtureMonkey.giveMeBuilder(Party.class) .set("legalEntityId", legalEntityId) .sample(); var expectedResponseDto = fixtureMonkey.giveMeBuilder(PartyResponseUpsertDto.class) @@ -56,7 +52,7 @@ void createCustomer_success() { when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.just(expectedResponseDto)); - var result = customerProfileService.upsertParty(requestDto); + var result = customerProfileService.upsertParty(requestDto, legalEntityId); StepVerifier.create(result) .assertNext(response -> { @@ -70,7 +66,7 @@ void createCustomer_success() { @Test @DisplayName("Upsert party should propagate WebClientResponseException when API call fails") void upsertParty_apiError() { - var requestDto = fixtureMonkey.giveMeOne(PartyUpsertDto.class); + var requestDto = fixtureMonkey.giveMeOne(Party.class); var expectedException = new WebClientResponseException( HttpStatus.BAD_REQUEST.value(), "Bad Request from API", @@ -79,7 +75,7 @@ void upsertParty_apiError() { StandardCharsets.UTF_8); when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.error(expectedException)); - var result = customerProfileService.upsertParty(requestDto); + var result = customerProfileService.upsertParty(requestDto, null); StepVerifier.create(result) .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException && @@ -92,11 +88,11 @@ void upsertParty_apiError() { @Test @DisplayName("Upsert party should propagate other RuntimeExceptions when API call fails unexpectedly") void upsertParty_otherError() { - var requestDto = fixtureMonkey.giveMeOne(PartyUpsertDto.class); + var requestDto = fixtureMonkey.giveMeOne(Party.class); var expectedException = new RuntimeException("Unexpected error"); when(partyManagementIntegrationApiMock.upsertParty(any(PartyUpsertDto.class))) .thenReturn(Mono.error(expectedException)); - var result = customerProfileService.upsertParty(requestDto); + var result = customerProfileService.upsertParty(requestDto, null); StepVerifier.create(result) .expectErrorMatches(throwable -> throwable == expectedException) .verify(); diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index 3f7d6debc..f5641141f 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -1115,7 +1115,7 @@ private Mono setupParties(LegalEntityTask legalEntityTask) { .filter(Objects::nonNull) .concatMap(party -> { log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party) + return customerProfileService.upsertParty(party, legalEntity.getExternalId()) .doOnSuccess(result -> { legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, "Successfully upserted party: %s for LE: %s", party.getPartyId(), diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 612b56357..12fbf3655 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -357,7 +357,7 @@ void masterServiceAgreementCreation_activateSingleServiceAgreement() { void testCustomServiceAgreement_IfFetchedServiceAgreementExists_ThenSettingUp() { var task = setupLegalEntityTask(); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); mockAccessGroupService(userId); @@ -373,7 +373,7 @@ void testCustomServiceAgreement_IfFetchedServiceAgreementExists_ThenSettingUp() void testCustomServiceAgreement_IfNoCustomServiceAgreementExists_ThenCreateMaster() { var task = setupLegalEntityTask(); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); when(accessGroupService.getUserContextsByUserId(userId)).thenReturn(Mono.empty()); mockUserService(userId); @@ -388,7 +388,7 @@ void testCustomServiceAgreement_IfNoCustomServiceAgreementExists_ThenCreateMaste void testCustomServiceAgreement_IfNoMatchingCustomServiceAgreementExists_ThenCreateMaster() { LegalEntityTask task = setupLegalEntityTask(); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); when(accessGroupService.getUserContextsByUserId(userId)) @@ -407,7 +407,7 @@ void testCustomServiceAgreement_IfNoUserDataFoundWhileServiceAgreementFetch_thro LegalEntityTask task = setupLegalEntityTask(); when(userService.getUsersByLegalEntity(any(), anyInt(), anyInt())) .thenReturn(Mono.just(new GetUsersList().totalElements(0L).users(null))); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); Assertions.assertThrows( StreamTaskException.class, @@ -420,12 +420,12 @@ void testCustomServiceAgreement_IfNoUserDataFoundWhileServiceAgreementFetch_thro @Test void testSetupParties_IfPartyFound_ThenUpsertParty() { var task = setupLegalEntityTask(); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn( + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); mockAccessGroupService(userId); mockUserService(userId); legalEntitySaga.executeTask(task).block(); - verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class)); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class), anyString()); } @Test @@ -439,12 +439,12 @@ void testProcessCustomerProfile_IfUpsertPartyError_ThenTrowException() { null, null ); - when(customerProfileService.upsertParty(any(Party.class))).thenReturn(Mono.error(mockException)); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn(Mono.error(mockException)); mockAccessGroupService(userId); mockUserService(userId); legalEntitySaga.executeTask(task).block(); - verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class)); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class), anyString()); verify(task, times(PARTY_SIZE)).error( eq(LegalEntitySaga.PARTY), eq(LegalEntitySaga.PROCESS_CUSTOMER_PROFILE), From d23b6c68d6d4576946230e003d74b57062b2c8bd Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 19:05:15 +0200 Subject: [PATCH 22/41] Add parties array to LegalEntityV2 and integrate CustomerProfileService in LegalEntitySagaV2 for party processing --- api/stream-legal-entity/openapi.yaml | 4 ++ .../backbase/stream/LegalEntitySagaV2.java | 66 ++++++++++++++++++- .../LegalEntitySagaConfiguration.java | 6 +- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index 9428d9ec0..e457ebd43 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -1203,6 +1203,10 @@ components: type: array items: $ref: '#/components/schemas/User' + parties: + type: array + items: + $ref: '#/components/schemas/Party' masterServiceAgreement: $ref: '#/components/schemas/ServiceAgreementV2' contacts: diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java index 3e77dd1fc..05149768b 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java @@ -47,6 +47,7 @@ import com.backbase.stream.mapper.UserProfileMapper; import com.backbase.stream.product.utils.StreamUtils; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.stream.service.LegalEntityService; import com.backbase.stream.service.UserProfileService; import com.backbase.stream.service.UserService; @@ -56,7 +57,9 @@ import io.micrometer.tracing.annotation.SpanTag; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; @@ -88,12 +91,14 @@ public class LegalEntitySagaV2 implements StreamTaskExecutor public static final String PROCESS_LIMITS = "process-limits"; public static final String PROCESS_CONTACTS = "process-contacts"; public static final String UPSERT = "upsert"; + public static final String PARTY = "party"; private static final String LEGAL_ENTITY_E_TYPE = "LE"; private static final String SERVICE_AGREEMENT_E_TYPE = "SA"; private static final String FUNCTION_E_TYPE = "FUN"; private static final String PRIVILEGE_E_TYPE = "PRV"; private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; + public static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class); private final LegalEntityV2toV1Mapper leV2Mapper = Mappers.getMapper(LegalEntityV2toV1Mapper.class); @@ -107,17 +112,20 @@ public class LegalEntitySagaV2 implements StreamTaskExecutor private final ContactsSaga contactsSaga; private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties; private final UserKindSegmentationSaga userKindSegmentationSaga; + private final CustomerProfileService customerProfileService; private static final ExternalContactMapper externalContactMapper = ExternalContactMapper.INSTANCE; - public LegalEntitySagaV2(LegalEntityService legalEntityService, + public LegalEntitySagaV2( + LegalEntityService legalEntityService, UserService userService, UserProfileService userProfileService, AccessGroupService accessGroupService, LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga) { + UserKindSegmentationSaga userKindSegmentationSaga, + CustomerProfileService customerProfileService) { this.legalEntityService = legalEntityService; this.userService = userService; this.userProfileService = userProfileService; @@ -126,12 +134,14 @@ public LegalEntitySagaV2(LegalEntityService legalEntityService, this.contactsSaga = contactsSaga; this.legalEntitySagaConfigurationProperties = legalEntitySagaConfigurationProperties; this.userKindSegmentationSaga = userKindSegmentationSaga; + this.customerProfileService = customerProfileService; } @Override public Mono executeTask(@SpanTag(value = "streamTask") LegalEntityTaskV2 streamTask) { return upsertLegalEntity(streamTask) .flatMap(this::linkLegalEntityToRealm) + .flatMap(this::setupParties) .flatMap(this::setupAdministrators) .flatMap(this::setupUsers) .flatMap(this::processAudiencesSegmentation) @@ -580,6 +590,58 @@ private Mono setupLegalEntityLevelBusinessFunctionLimits(Lega }); } + private Mono setupParties(LegalEntityTaskV2 legalEntityTask) { + + log.info("Processing Customer Profile Parties for: {}", legalEntityTask.getName()); + var legalEntity = legalEntityTask.getData(); + + if (isEmpty(legalEntity.getParties())) { + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntity.getExternalId(), + legalEntity.getInternalId(), "No parties found in Legal Entity to process."); + return Mono.just(legalEntityTask); + } + var processingErrors = new CopyOnWriteArrayList<>(); + + return Flux.fromStream(nullableCollectionToStream(legalEntity.getParties())) + .filter(Objects::nonNull) + .concatMap(party -> { + log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); + return customerProfileService.upsertParty(party, legalEntity.getExternalId()) + .doOnSuccess(result -> { + legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, + "Successfully upserted party: %s for LE: %s", party.getPartyId(), + legalEntity.getExternalId()); + }) + .onErrorResume(throwable -> { + log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), + throwable); + processingErrors.add(throwable); + legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, + throwable, + throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), + legalEntity.getExternalId()); + return Mono.empty(); + }) + .then(Mono.just(true)); + }) + .then(Mono.fromRunnable(() -> { + if (!processingErrors.isEmpty()) { + log.warn("Completed processing parties for LE {} with {} errors.", legalEntity.getExternalId(), + processingErrors.size()); + legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", + legalEntity.getExternalId(), + legalEntity.getInternalId(), "Party processing completed with %d errors.", + processingErrors.size()); + } else { + log.info("Successfully processed all parties for LE {}.", legalEntity.getExternalId()); + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", + legalEntity.getExternalId(), + legalEntity.getInternalId(), "Party processing completed successfully."); + } + })) + .thenReturn(legalEntityTask); + } + private Stream createLimitsTask(LegalEntityTaskV2 streamTask, String legalEntityId, BusinessFunctionLimit businessFunctionLimit) { diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java index 6e2b0841c..97129abc4 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/configuration/LegalEntitySagaConfiguration.java @@ -77,7 +77,8 @@ public LegalEntitySagaV2 reactiveLegalEntitySagaV2(LegalEntityService legalEntit LimitsSaga limitsSaga, ContactsSaga contactsSaga, LegalEntitySagaConfigurationProperties sinkConfigurationProperties, - UserKindSegmentationSaga userKindSegmentationSaga + UserKindSegmentationSaga userKindSegmentationSaga, + CustomerProfileService customerProfileService ) { return new LegalEntitySagaV2( legalEntityService, @@ -87,7 +88,8 @@ public LegalEntitySagaV2 reactiveLegalEntitySagaV2(LegalEntityService legalEntit limitsSaga, contactsSaga, sinkConfigurationProperties, - userKindSegmentationSaga + userKindSegmentationSaga, + customerProfileService ); } From 95503114e9cc7b745b7cbb95712fda51c46f5f98 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 20:02:36 +0200 Subject: [PATCH 23/41] Refactor setupParties method in LegalEntitySagaV2 to use LegalEntityV2 and improve party processing logging --- .../backbase/stream/LegalEntitySagaV2.java | 56 ++++++++--------- .../stream/LegalEntitySagaV2Test.java | 62 +++++++++++++++++++ 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java index 05149768b..6921ff312 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java @@ -590,56 +590,56 @@ private Mono setupLegalEntityLevelBusinessFunctionLimits(Lega }); } - private Mono setupParties(LegalEntityTaskV2 legalEntityTask) { + private Mono setupParties(LegalEntityTaskV2 legalEntityTaskV2) { - log.info("Processing Customer Profile Parties for: {}", legalEntityTask.getName()); - var legalEntity = legalEntityTask.getData(); + log.info("Processing Parties for: {}", legalEntityTaskV2.getName()); - if (isEmpty(legalEntity.getParties())) { - legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntity.getExternalId(), - legalEntity.getInternalId(), "No parties found in Legal Entity to process."); - return Mono.just(legalEntityTask); + LegalEntityV2 legalEntityV2 = legalEntityTaskV2.getData(); + + if (isEmpty(legalEntityV2.getParties())) { + legalEntityTaskV2.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntityV2.getExternalId(), + legalEntityV2.getInternalId(), "No parties found in Legal Entity to process."); + return Mono.just(legalEntityTaskV2); } - var processingErrors = new CopyOnWriteArrayList<>(); + var processingErrors = new CopyOnWriteArrayList(); - return Flux.fromStream(nullableCollectionToStream(legalEntity.getParties())) + return Flux.fromStream(nullableCollectionToStream(legalEntityV2.getParties())) .filter(Objects::nonNull) .concatMap(party -> { - log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntity.getExternalId()) - .doOnSuccess(result -> { - legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, - "Successfully upserted party: %s for LE: %s", party.getPartyId(), - legalEntity.getExternalId()); - }) + log.debug("Processing party with partyId: {}", party.getPartyId()); + return customerProfileService.upsertParty(party, legalEntityV2.getExternalId()) + .doOnSuccess(result -> legalEntityTaskV2 + .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, + "Successfully processed party: %s for LE: %s", party.getPartyId(), + legalEntityV2.getExternalId())) .onErrorResume(throwable -> { log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), throwable); processingErrors.add(throwable); - legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, + legalEntityTaskV2.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, throwable, - throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), - legalEntity.getExternalId()); + throwable.getMessage(), "Error processing party: %s for LE: %s", party.getPartyId(), + legalEntityV2.getExternalId()); return Mono.empty(); }) .then(Mono.just(true)); }) .then(Mono.fromRunnable(() -> { if (!processingErrors.isEmpty()) { - log.warn("Completed processing parties for LE {} with {} errors.", legalEntity.getExternalId(), + log.warn("Processed parties for LE {} with {} errors.", legalEntityV2.getExternalId(), processingErrors.size()); - legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", - legalEntity.getExternalId(), - legalEntity.getInternalId(), "Party processing completed with %d errors.", + legalEntityTaskV2.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", + legalEntityV2.getExternalId(), + legalEntityV2.getInternalId(), "Party processing completed with %d errors.", processingErrors.size()); } else { - log.info("Successfully processed all parties for LE {}.", legalEntity.getExternalId()); - legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", - legalEntity.getExternalId(), - legalEntity.getInternalId(), "Party processing completed successfully."); + log.info("Successfully processed all parties for LE {}.", legalEntityV2.getExternalId()); + legalEntityTaskV2.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", + legalEntityV2.getExternalId(), + legalEntityV2.getInternalId(), "Party processing completed successfully."); } })) - .thenReturn(legalEntityTask); + .thenReturn(legalEntityTaskV2); } private Stream createLimitsTask(LegalEntityTaskV2 streamTask, String legalEntityId, diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java index 9380ab548..431a9680f 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaV2Test.java @@ -1,15 +1,18 @@ package com.backbase.stream; +import static com.backbase.stream.FixtureUtils.reflectiveAlphaFixtureMonkey; import static com.backbase.stream.service.UserService.REMOVED_PREFIX; import static java.util.Collections.singletonList; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; import com.backbase.dbs.contact.api.service.v2.model.AccessContextScope; import com.backbase.dbs.contact.api.service.v2.model.ContactsBulkPostRequestBody; import com.backbase.dbs.contact.api.service.v2.model.ContactsBulkPostResponseBody; @@ -29,6 +32,7 @@ import com.backbase.stream.legalentity.model.LegalEntity; import com.backbase.stream.legalentity.model.LegalEntityType; import com.backbase.stream.legalentity.model.LegalEntityV2; +import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.legalentity.model.SavingsAccount; import com.backbase.stream.legalentity.model.ServiceAgreement; import com.backbase.stream.legalentity.model.ServiceAgreementV2; @@ -36,9 +40,11 @@ import com.backbase.stream.mapper.LegalEntityV2toV1Mapper; import com.backbase.stream.mapper.ServiceAgreementV2ToV1Mapper; import com.backbase.stream.service.AccessGroupService; +import com.backbase.stream.service.CustomerProfileService; import com.backbase.stream.service.LegalEntityService; import com.backbase.stream.service.UserService; import com.backbase.stream.worker.exception.StreamTaskException; +import com.navercorp.fixturemonkey.FixtureMonkey; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; @@ -84,10 +90,17 @@ class LegalEntitySagaV2Test { @Mock private UserKindSegmentationSaga userKindSegmentationSaga; + @Mock + private CustomerProfileService customerProfileService; + @Spy private final LegalEntitySagaConfigurationProperties legalEntitySagaConfigurationProperties = getLegalEntitySagaConfigurationProperties(); + private final FixtureMonkey fixtureMonkey = reflectiveAlphaFixtureMonkey; + + private static final int PARTY_SIZE = 20; + String leExternalId = "someLeExternalId"; String leParentExternalId = "someParentLeExternalId"; String leInternalId = "someLeInternalId"; @@ -352,6 +365,7 @@ void getMockLegalEntity() { legalEntityV2 = new LegalEntityV2() .internalId(leInternalId) .externalId(leExternalId) + .parties(fixtureMonkey.giveMe(Party.class, PARTY_SIZE)) .addAdministratorsItem(adminUser) .parentExternalId(leParentExternalId) .users(singletonList(regularUser)) @@ -383,6 +397,9 @@ void test_PostLegalContacts() { LegalEntityTaskV2 task = mockLegalEntityTask(legalEntityV2); when(contactsSaga.executeTask(any(ContactsTask.class))).thenReturn(getContactsTask(AccessContextScope.LE)); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + LegalEntityTaskV2 result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); @@ -442,6 +459,9 @@ void test_PostUserContacts() { when(contactsSaga.executeTask(any(ContactsTask.class))).thenReturn(getContactsTask(AccessContextScope.USER)); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + LegalEntityTaskV2 result = legalEntitySaga.executeTask(task).block(); Assertions.assertNotNull(result); @@ -456,6 +476,9 @@ void userKindSegmentationIsDisabled() { when(userKindSegmentationSaga.isEnabled()).thenReturn(false); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + legalEntitySaga.executeTask(mockLegalEntityTask(legalEntityV2)).block(); verify(userKindSegmentationSaga, never()).executeTask(Mockito.any()); @@ -468,6 +491,9 @@ void userKindSegmentationUsesLegalEntityCustomerCategory() { when(userKindSegmentationSaga.isEnabled()).thenReturn(true); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + legalEntitySaga.executeTask(mockLegalEntityTask(legalEntityV2)).block(); verify(userKindSegmentationSaga, times(0)).getDefaultCustomerCategory(); @@ -482,6 +508,8 @@ void userKindSegmentationUsesDefaultCustomerCategory() { when(userKindSegmentationSaga.getDefaultCustomerCategory()).thenReturn(CustomerCategory.RETAIL.getValue()); when(userKindSegmentationSaga.executeTask(any())).thenReturn( Mono.just(Mockito.mock(UserKindSegmentationTask.class))); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); legalEntitySaga.executeTask(mockLegalEntityTask(legalEntityV2)).block(); @@ -496,6 +524,9 @@ void whenUserKindSegmentationIsEnabledAndNoCustomerCategoryCanBeDeterminedReturn when(userKindSegmentationSaga.isEnabled()).thenReturn(true); when(userKindSegmentationSaga.getDefaultCustomerCategory()).thenReturn(null); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + var task = mockLegalEntityTask(legalEntityV2); Assertions.assertThrows( @@ -505,6 +536,37 @@ void whenUserKindSegmentationIsEnabledAndNoCustomerCategoryCanBeDeterminedReturn ); } + @Test + void testSetupParties_IfPartyFound_ThenUpsertParty() { + getMockLegalEntity(); + var task = mockLegalEntityTask(legalEntityV2); + when(contactsSaga.executeTask(any(ContactsTask.class))).thenReturn(getContactsTask(AccessContextScope.LE)); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn( + Mono.just(fixtureMonkey.giveMeOne(PartyResponseUpsertDto.class))); + var result = legalEntitySaga.executeTask(task).block(); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class), anyString()); + Assertions.assertNotNull(result); + } + + @Test + void testProcessCustomerProfile_IfUpsertPartyError_ThenTrowException() { + getMockLegalEntity(); + var task = mockLegalEntityTask(legalEntityV2); + when(contactsSaga.executeTask(any(ContactsTask.class))).thenReturn(getContactsTask(AccessContextScope.LE)); + var mockException = new WebClientResponseException( + "CPS Error", + 400, + "Bad Request", + null, + null, + null + ); + when(customerProfileService.upsertParty(any(Party.class), anyString())).thenReturn(Mono.error(mockException)); + var result = legalEntitySaga.executeTask(task).block(); + verify(customerProfileService, times(PARTY_SIZE)).upsertParty(any(Party.class), anyString()); + Assertions.assertNotNull(result); + } + @ParameterizedTest @MethodSource("parameters_upster_error") void upster_error(Exception ex, String error) { From f9b15faefed0cca00706c52f5dcaaaef0d38aac2 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Thu, 24 Apr 2025 20:28:24 +0200 Subject: [PATCH 24/41] Refactor error handling in LegalEntitySaga and clean up unused imports in CustomerProfileService and MapperTest --- .../com/backbase/stream/service/CustomerProfileService.java | 1 - .../src/test/java/com/backbase/stream/mapper/MapperTest.java | 2 +- .../src/main/java/com/backbase/stream/LegalEntitySaga.java | 2 +- .../test/java/com/backbase/stream/LegalEntitySagaTest.java | 5 ----- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 5e8fe3e59..c43e85892 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -2,7 +2,6 @@ import com.backbase.customerprofile.api.integration.v1.PartyManagementIntegrationApi; import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; -import com.backbase.customerprofile.api.integration.v1.model.PartyUpsertDto; import com.backbase.stream.legalentity.model.Party; import com.backbase.stream.mapper.PartyMapper; import lombok.RequiredArgsConstructor; diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index 2bc968eb1..af46e844e 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -13,7 +13,7 @@ import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest(classes = PartyMapperImpl.class) -public class MapperTest { +class MapperTest { @Autowired private PartyMapper partyMapper; diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index f5641141f..70b20352e 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -1125,7 +1125,7 @@ private Mono setupParties(LegalEntityTask legalEntityTask) { log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), throwable); processingErrors.add(throwable); - legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, + legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, throwable, throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), legalEntity.getExternalId()); diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 12fbf3655..4fe198800 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -69,9 +69,6 @@ import com.backbase.stream.service.UserService; import com.backbase.stream.worker.exception.StreamTaskException; import com.navercorp.fixturemonkey.FixtureMonkey; -import com.navercorp.fixturemonkey.api.introspector.FieldReflectionArbitraryIntrospector; -import com.navercorp.fixturemonkey.api.jqwik.JavaTypeArbitraryGenerator; -import com.navercorp.fixturemonkey.api.jqwik.JqwikPlugin; import java.math.BigDecimal; import java.nio.charset.Charset; import java.time.Duration; @@ -83,8 +80,6 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; -import net.jqwik.api.Arbitraries; -import net.jqwik.api.arbitraries.StringArbitrary; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; From bb5cb5b534643aabfb7e3373f8927a5d3e2363d9 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 11:27:20 +0200 Subject: [PATCH 25/41] Refactor LegalEntitySaga and CustomerProfileService to use internalId for party upsert and remove legalEntityId from OpenAPI specification --- api/stream-legal-entity/openapi.yaml | 4 --- .../service/CustomerProfileService.java | 10 +++---- .../com/backbase/stream/LegalEntitySaga.java | 11 ++++---- .../backbase/stream/LegalEntitySagaV2.java | 4 +-- .../backbase/stream/LegalEntitySagaTest.java | 26 +++++++++---------- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/api/stream-legal-entity/openapi.yaml b/api/stream-legal-entity/openapi.yaml index e457ebd43..cfae64384 100644 --- a/api/stream-legal-entity/openapi.yaml +++ b/api/stream-legal-entity/openapi.yaml @@ -3111,10 +3111,6 @@ components: type: string description: Core System Identifier maxLength: 100 - legalEntityId: - type: string - description: Legal Entity Id from Access Control. - pattern: ^[0-9a-f]{32}$|^[0-9a-f-]{36}$ isCustomer: type: boolean description: Indicates if it is a customer or not. diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index c43e85892..526573242 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -16,13 +16,11 @@ public class CustomerProfileService { private final PartyMapper partyMapper; - public Mono upsertParty(Party party, String legalEntityExternalId) { - - if (legalEntityExternalId != null && !legalEntityExternalId.trim().isEmpty() && party.getIsCustomer()) { - party.partyId(legalEntityExternalId); - } + public Mono upsertParty(Party party, String legalEntityInternalId) { var partyUpsertDto = partyMapper.partyToPartyUpsertDto(party); - + if (legalEntityInternalId != null && !legalEntityInternalId.trim().isEmpty() && party.getIsCustomer()) { + partyUpsertDto.setLegalEntityId(legalEntityInternalId); + } return partyManagementIntegrationApi.upsertParty(partyUpsertDto); } } diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index 70b20352e..b1cef7915 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -1115,12 +1115,11 @@ private Mono setupParties(LegalEntityTask legalEntityTask) { .filter(Objects::nonNull) .concatMap(party -> { log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntity.getExternalId()) - .doOnSuccess(result -> { - legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, - "Successfully upserted party: %s for LE: %s", party.getPartyId(), - legalEntity.getExternalId()); - }) + return customerProfileService.upsertParty(party, legalEntity.getInternalId()) + .doOnSuccess(result -> legalEntityTask + .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, + "Successfully upserted party: %s for LE: %s", party.getPartyId(), + legalEntity.getExternalId())) .onErrorResume(throwable -> { log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), throwable); diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java index 6921ff312..bf8608d05 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java @@ -607,7 +607,7 @@ private Mono setupParties(LegalEntityTaskV2 legalEntityTaskV2 .filter(Objects::nonNull) .concatMap(party -> { log.debug("Processing party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntityV2.getExternalId()) + return customerProfileService.upsertParty(party, legalEntityV2.getInternalId()) .doOnSuccess(result -> legalEntityTaskV2 .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, "Successfully processed party: %s for LE: %s", party.getPartyId(), @@ -616,7 +616,7 @@ private Mono setupParties(LegalEntityTaskV2 legalEntityTaskV2 log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), throwable); processingErrors.add(throwable); - legalEntityTaskV2.error(PARTY, PROCESS_CUSTOMER_PROFILE, "failed", party.getPartyId(), null, + legalEntityTaskV2.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, throwable, throwable.getMessage(), "Error processing party: %s for LE: %s", party.getPartyId(), legalEntityV2.getExternalId()); diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java index 4fe198800..242fea463 100644 --- a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/LegalEntitySagaTest.java @@ -489,32 +489,32 @@ private LegalEntityTask setupLegalEntityTask() { var jobRole = new JobRole("someJobRole", "someJobRole"); jobRole.setFunctionGroups(singletonList(functionGroup)); - var legalEntity = new LegalEntity("le_name", null, null); - legalEntity.setInternalId(leInternalId); - legalEntity.setExternalId(leExternalId); - legalEntity.setParentExternalId(leExternalId); - legalEntity.setProductGroups(singletonList(productGroup)); - legalEntity.setParties(fixtureMonkey.giveMe(Party.class, PARTY_SIZE)); + var setuplegalEntity = new LegalEntity("le_name", null, null); + setuplegalEntity.setInternalId(leInternalId); + setuplegalEntity.setExternalId(leExternalId); + setuplegalEntity.setParentExternalId(leExternalId); + setuplegalEntity.setProductGroups(singletonList(productGroup)); + setuplegalEntity.setParties(fixtureMonkey.giveMe(Party.class, PARTY_SIZE)); var sa = new ServiceAgreement().externalId(customSaExId).addJobRolesItem(jobRole) .creatorLegalEntity(leExternalId); - var task = mockLegalEntityTask(legalEntity); + var task = mockLegalEntityTask(setuplegalEntity); - when(task.getLegalEntity()).thenReturn(legalEntity); + when(task.getLegalEntity()).thenReturn(setuplegalEntity); when(legalEntityService.getLegalEntityByExternalId(leExternalId)).thenReturn(Mono.empty()); - when(legalEntityService.getLegalEntityByInternalId(leInternalId)).thenReturn(Mono.just(legalEntity)); + when(legalEntityService.getLegalEntityByInternalId(leInternalId)).thenReturn(Mono.just(setuplegalEntity)); when(legalEntityService.getMasterServiceAgreementForInternalLegalEntityId(leInternalId)).thenReturn( Mono.empty()); - when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(legalEntity)); + when(legalEntityService.createLegalEntity(any())).thenReturn(Mono.just(setuplegalEntity)); when(accessGroupService.setupJobRole(any(), any(), any())).thenReturn(Mono.just(jobRole)); when(accessGroupService.createServiceAgreement(any(), any())).thenReturn(Mono.just(sa)); when(batchProductIngestionSaga.process(any(ProductGroupTask.class))).thenReturn(productGroupTaskMono); when(legalEntitySagaConfigurationProperties.getServiceAgreementPurposes()).thenReturn( Set.of("FAMILY_BANKING")); when(userService.setupRealm(task.getLegalEntity())).thenReturn(Mono.just(new Realm())); - when(userService.linkLegalEntityToRealm(task.getLegalEntity())).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.getLegalEntityByExternalId(leExternalId)).thenReturn(Mono.just(legalEntity)); - when(legalEntityService.putLegalEntity(any())).thenReturn(Mono.just(legalEntity)); + when(userService.linkLegalEntityToRealm(task.getLegalEntity())).thenReturn(Mono.just(setuplegalEntity)); + when(legalEntityService.getLegalEntityByExternalId(leExternalId)).thenReturn(Mono.just(setuplegalEntity)); + when(legalEntityService.putLegalEntity(any())).thenReturn(Mono.just(setuplegalEntity)); return task; } From b228ec58360066a7782df4e36a444e16a81de2d6 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 11:33:21 +0200 Subject: [PATCH 26/41] Remove unused CustomerManagementIntegrationApi, CustomerProfileManagementIntegrationApi, and CustomerLifeCycleManagementIntegrationApi beans from CustomerProfileClientConfig --- .../config/CustomerProfileClientConfig.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java index 625d7e587..d4057680a 100644 --- a/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java +++ b/stream-dbs-clients/src/main/java/com/backbase/stream/clients/config/CustomerProfileClientConfig.java @@ -38,26 +38,4 @@ public PartyManagementIntegrationApi partyManagementIntegrationApi( ApiClient customerProfileApiIntegrationClient) { return new PartyManagementIntegrationApi(customerProfileApiIntegrationClient); } - - @Bean - @ConditionalOnMissingBean - public CustomerManagementIntegrationApi createCustomerManagementIntegrationApi( - ApiClient customerProfileClientConfig) { - return new CustomerManagementIntegrationApi(customerProfileClientConfig); - } - - @Bean - @ConditionalOnMissingBean - public CustomerProfileManagementIntegrationApi createCustomerProfileManagementIntegrationApi( - ApiClient customerProfileClientConfig) { - return new CustomerProfileManagementIntegrationApi(customerProfileClientConfig); - } - - @Bean - @ConditionalOnMissingBean - public CustomerLifeCycleManagementIntegrationApi createCustomerLifeCycleManagementIntegrationApi( - ApiClient customerProfileClientConfig) { - return new CustomerLifeCycleManagementIntegrationApi(customerProfileClientConfig); - } - } From bae16c5be32088065781cc683858b862765ea42e Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 11:39:38 +0200 Subject: [PATCH 27/41] Remove legalEntityId assertion from MapperTest --- .../src/test/java/com/backbase/stream/mapper/MapperTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index af46e844e..46c4b4728 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -55,7 +55,6 @@ void testPartyToPartyUpsertDtoMapping() { assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); assertEquals(party.getNotes(), resultDto.getNotes()); - assertEquals(party.getLegalEntityId(), resultDto.getLegalEntityId()); assertNotNull(resultDto.getSubState()); assertEquals(party.getSubState().getValue(), resultDto.getSubState().getValue()); From fa89a83d639d29f2f87b744b7559f7c48b14aa60 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 11:56:26 +0200 Subject: [PATCH 28/41] Update CHANGELOG for version 6.18.0: Integrate Customer Profile Service into Legal Entity Saga and Legal Entity Saga V2 ingestion --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c8fc9b0..906005c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog All notable changes to this project will be documented in this file. +## [6.18.0] (https://github.com/Backbase/stream-services/compare/6.16.0...6.18.0) +- Integrate Customer Profile Service into Legal Entity Saga and Legal Entity Saga V2 ingestion ## [6.17.0](https://github.com/Backbase/stream-services/compare/6.16.0...6.17.0) ### Added From ceea39836ffb88011fa18d0d8e0953f6c86daece Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 11:58:24 +0200 Subject: [PATCH 29/41] Update CHANGELOG for version 6.18.0: Correct comparison range for Legal Entity Saga integration --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 906005c52..ee2e06476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog All notable changes to this project will be documented in this file. -## [6.18.0] (https://github.com/Backbase/stream-services/compare/6.16.0...6.18.0) +## [6.18.0] (https://github.com/Backbase/stream-services/compare/6.17.0...6.18.0) - Integrate Customer Profile Service into Legal Entity Saga and Legal Entity Saga V2 ingestion ## [6.17.0](https://github.com/Backbase/stream-services/compare/6.16.0...6.17.0) From 5349d824b938c2c48e7b9f08378c93556fab6604 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Fri, 25 Apr 2025 12:17:11 +0200 Subject: [PATCH 30/41] Update README to reflect version 6.18.0 to latest compatibility --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 560dc5656..8fceba835 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ You can find listed here the API specification containing the opinionated model | Stream [version](https://github.com/Backbase/stream-services/releases) | Banking Services | Java | Spring Boot | |------------------------------------------------------------------------|--------------------|------|-------------| +| 6.18.0 to latest | 2025.04 | 21 | 3.3 | | 6.2.0 to latest | 2024.10 | 21 | 3.3 | | 6.0.0 to 6.1.0 | 2024.10 | 21 | 3.2 | | 5.10.0 to 5.16.0 | 2024.09-LTS | 21 | 3.2 | From aa0c77c995f9e0670f4187feace62ed456f53dd3 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Mon, 28 Apr 2025 11:11:29 +0200 Subject: [PATCH 31/41] Update README to correct version range from 6.19.0 to 6.18.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00a11c9a6..8625b1685 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ You can find listed here the API specification containing the opinionated model | Stream [version](https://github.com/Backbase/stream-services/releases) | Banking Services | Java | Spring Boot | |------------------------------------------------------------------------|--------------------|------|-------------| -| 6.19.0 to latest | 2025.04 | 21 | 3.3 | +| 6.18.0 to latest | 2025.04 | 21 | 3.3 | | 6.2.0 to 6.17.0 | 2024.10 | 21 | 3.3 | | 6.0.0 to 6.1.0 | 2024.10 | 21 | 3.2 | | 5.10.0 to 5.16.0 | 2024.09-LTS | 21 | 3.2 | From 85558cd1e0b233671f0d278267ed8701f5f4e67f Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Mon, 28 Apr 2025 11:22:53 +0200 Subject: [PATCH 32/41] Update parent version in pom.xml from 6.17.0 to 6.18.0 for stream-services and stream-customer-profile --- stream-customer-profile/customer-profile-core/pom.xml | 2 +- stream-customer-profile/pom.xml | 2 +- stream-dbs-clients/pom.xml | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/pom.xml b/stream-customer-profile/customer-profile-core/pom.xml index 521f38ed3..0de7b95b4 100644 --- a/stream-customer-profile/customer-profile-core/pom.xml +++ b/stream-customer-profile/customer-profile-core/pom.xml @@ -5,7 +5,7 @@ com.backbase.stream stream-customer-profile - 6.17.0 + 6.18.0 customer-profile-core diff --git a/stream-customer-profile/pom.xml b/stream-customer-profile/pom.xml index f21c9070e..a83364cce 100644 --- a/stream-customer-profile/pom.xml +++ b/stream-customer-profile/pom.xml @@ -5,7 +5,7 @@ com.backbase.stream stream-services - 6.17.0 + 6.18.0 stream-customer-profile diff --git a/stream-dbs-clients/pom.xml b/stream-dbs-clients/pom.xml index 114719a07..0c7a9eee8 100644 --- a/stream-dbs-clients/pom.xml +++ b/stream-dbs-clients/pom.xml @@ -222,7 +222,6 @@ com.backbase.flow.customer-profile.api customer-profile 1.17.1 - api zip ${project.build.directory}/yaml From d7f811ac8d26a0a0db7ffffa2bf37473f0d2eb81 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Mon, 28 Apr 2025 18:18:23 +0200 Subject: [PATCH 33/41] Trigger Build From 84b3a9d3a22351efc1b67a9360bd430c2df99c5f Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 29 Apr 2025 13:10:37 +0200 Subject: [PATCH 34/41] Fix comments --- .../CustomerProfileConfiguration.java | 3 +- .../backbase/stream/mapper/PartyMapper.java | 9 +- .../service/CustomerProfileService.java | 3 +- .../backbase/stream/mapper/MapperTest.java | 270 ++++++++++-------- .../service/CustomerProfileServiceTest.java | 3 +- 5 files changed, 160 insertions(+), 128 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java index c350b4b01..4b6e2fc99 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java @@ -5,6 +5,7 @@ import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.service.CustomerProfileService; import lombok.extern.slf4j.Slf4j; +import org.mapstruct.factory.Mappers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,7 +18,7 @@ public class CustomerProfileConfiguration { @Bean public PartyMapper partyMapper() { - return PartyMapper.INSTANCE; + return Mappers.getMapper(PartyMapper.class); } @Bean diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java index e0cbf3eda..ed43eaea8 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/mapper/PartyMapper.java @@ -5,17 +5,10 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingConstants; -import org.mapstruct.ReportingPolicy; -import org.mapstruct.factory.Mappers; -@Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, - unmappedTargetPolicy = ReportingPolicy.IGNORE -) +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) public interface PartyMapper { - PartyMapper INSTANCE = Mappers.getMapper(PartyMapper.class); - @Mapping(target = "additions", source = "customFields") PartyUpsertDto partyToPartyUpsertDto(Party party); diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java index 526573242..dfc0ccdba 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/service/CustomerProfileService.java @@ -6,6 +6,7 @@ import com.backbase.stream.mapper.PartyMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; @Slf4j @@ -18,7 +19,7 @@ public class CustomerProfileService { public Mono upsertParty(Party party, String legalEntityInternalId) { var partyUpsertDto = partyMapper.partyToPartyUpsertDto(party); - if (legalEntityInternalId != null && !legalEntityInternalId.trim().isEmpty() && party.getIsCustomer()) { + if (StringUtils.hasText(legalEntityInternalId) && party.getIsCustomer()) { partyUpsertDto.setLegalEntityId(legalEntityInternalId); } return partyManagementIntegrationApi.upsertParty(partyUpsertDto); diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java index 46c4b4728..bd0845d80 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/mapper/MapperTest.java @@ -5,9 +5,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.backbase.stream.legalentity.model.Party; import com.navercorp.fixturemonkey.FixtureMonkey; +import java.util.ArrayList; +import java.util.HashMap; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -20,147 +24,179 @@ class MapperTest { private final FixtureMonkey fixtureMonkey = reflectiveAlphaFixtureMonkey; @Test - void testPartyToPartyUpsertDtoMapping() { - + @DisplayName("Should map basic fields correctly when not null") + void shouldMapBasicFields() { var party = fixtureMonkey.giveMeOne(Party.class); - assertNotNull(party.getPartyId(), "FixtureMonkey should generate a partyId"); - assertNotNull(party.getIsCustomer(), "FixtureMonkey should generate isCustomer"); - assertNotNull(party.getPartyType(), "FixtureMonkey should generate partyType"); - var resultDto = partyMapper.partyToPartyUpsertDto(party); assertNotNull(resultDto); - assertEquals(party.getPartyId(), resultDto.getPartyId()); assertEquals(party.getIsCustomer(), resultDto.getIsCustomer()); - - if (party.getPartyType() != null) { - assertNotNull(resultDto.getPartyType()); - assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); - } else { - assertNull(resultDto.getPartyType()); - } - if (party.getState() != null) { - assertNotNull(resultDto.getState()); - assertEquals(party.getState().getValue(), resultDto.getState().getValue()); - } else { - assertNull(resultDto.getState()); - } + assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); + assertEquals(party.getNotes(), resultDto.getNotes()); assertEquals(party.getClosingDateTime(), resultDto.getClosingDateTime()); assertEquals(party.getApprovedDateTime(), resultDto.getApprovedDateTime()); assertEquals(party.getLastUpdatedDateTime(), resultDto.getLastUpdatedDateTime()); assertEquals(party.getOpeningDateTime(), resultDto.getOpeningDateTime()); assertEquals(party.getLiveDateTime(), resultDto.getLiveDateTime()); - assertEquals(party.getPreferredLanguage(), resultDto.getPreferredLanguage()); - assertEquals(party.getNotes(), resultDto.getNotes()); + assertNotNull(resultDto.getPartyType()); + assertEquals(party.getPartyType().getValue(), resultDto.getPartyType().getValue()); + assertNotNull(resultDto.getState()); + assertEquals(party.getState().getValue(), resultDto.getState().getValue()); assertNotNull(resultDto.getSubState()); assertEquals(party.getSubState().getValue(), resultDto.getSubState().getValue()); + } - if (party.getCustomFields() != null) { - assertNotNull(resultDto.getAdditions()); - assertEquals(party.getCustomFields().size(), resultDto.getAdditions().size()); - assertEquals(party.getCustomFields(), resultDto.getAdditions()); - } + @Test + @DisplayName("Should map Person when PartyType is PERSON and Person is not null") + void shouldMapPersonWhenPartyTypeIsPerson() { + var party = fixtureMonkey.giveMeBuilder(Party.class) + .set("partyType", Party.PartyTypeEnum.PERSON) + .setNotNull("person") + .setNotNull("person.personName") + .set("person.personName.firstName", "John") + .set("person.personName.familyName", "Doe") + .setNull("organisation") + .sample(); - if (party.getPhoneNumbers() != null) { - assertNotNull(resultDto.getPhoneNumbers()); - assertEquals(party.getPhoneNumbers().size(), resultDto.getPhoneNumbers().size()); + var resultDto = partyMapper.partyToPartyUpsertDto(party); - if (!party.getPhoneNumbers().isEmpty()) { - assertEquals(party.getPhoneNumbers().get(0).getNumber(), - resultDto.getPhoneNumbers().get(0).getNumber()); - } - } else { - assertNull(resultDto.getPhoneNumbers()); + assertNotNull(resultDto.getPerson()); + assertEquals("John", resultDto.getPerson().getPersonName().getFirstName()); + assertEquals("Doe", resultDto.getPerson().getPersonName().getFamilyName()); + if (party.getPerson().getIdentifications() != null) { + assertNotNull(resultDto.getPerson().getIdentifications()); + assertEquals(party.getPerson().getIdentifications().size(), + resultDto.getPerson().getIdentifications().size()); } + assertNull(resultDto.getOrganisation(), "Organisation should be null if PartyType is PERSON"); + } - if (party.getElectronicAddresses() != null) { - assertNotNull(resultDto.getElectronicAddresses()); - if (party.getElectronicAddresses().getEmails() != null) { - assertNotNull(resultDto.getElectronicAddresses().getEmails()); - assertEquals(party.getElectronicAddresses().getEmails().size(), - resultDto.getElectronicAddresses().getEmails().size()); - } else { - assertNull(resultDto.getElectronicAddresses().getEmails()); - } - if (party.getElectronicAddresses().getUrls() != null) { - assertNotNull(resultDto.getElectronicAddresses().getUrls()); - assertEquals(party.getElectronicAddresses().getUrls().size(), - resultDto.getElectronicAddresses().getUrls().size()); - } else { - assertNull(resultDto.getElectronicAddresses().getUrls()); - } - } else { - assertNull(resultDto.getElectronicAddresses()); - } + @Test + @DisplayName("Should handle null Person from source") + void shouldHandleNullPerson() { + var party = fixtureMonkey.giveMeBuilder(Party.class) + .setNull("person") + .sample(); - if (party.getPerson() != null) { - assertNotNull(resultDto.getPerson()); - - assertEquals(party.getPerson().getPersonName().getFirstName(), - resultDto.getPerson().getPersonName().getFirstName()); - - assertEquals(party.getPerson().getPersonName().getFamilyName(), - resultDto.getPerson().getPersonName().getFamilyName()); - if (party.getPerson().getIdentifications() != null) { - assertNotNull(resultDto.getPerson().getIdentifications()); - assertEquals(party.getPerson().getIdentifications().size(), - resultDto.getPerson().getIdentifications().size()); - } else { - assertNull(resultDto.getPerson().getIdentifications()); - } - if (party.getPerson().getDemographics() != null) { - assertNotNull(resultDto.getPerson().getDemographics()); - } else { - assertNull(resultDto.getPerson().getDemographics()); - } - - } else { - if (party.getPartyType() != Party.PartyTypeEnum.PERSON) { - assertNull(resultDto.getPerson()); - } else { - assertNull(resultDto.getPerson()); - } - } + var resultDto = partyMapper.partyToPartyUpsertDto(party); - if (party.getOrganisation() != null) { - assertNotNull(resultDto.getOrganisation()); - assertEquals(party.getOrganisation().getName(), resultDto.getOrganisation().getName()); - if (party.getOrganisation().getIdentifications() != null) { - assertNotNull(resultDto.getOrganisation().getIdentifications()); - assertEquals(party.getOrganisation().getIdentifications().size(), - resultDto.getOrganisation().getIdentifications().size()); - } else { - assertNull(resultDto.getOrganisation().getIdentifications()); - } - if (party.getOrganisation().getLegalStructure() != null) { - assertNotNull(resultDto.getOrganisation().getLegalStructure()); - } else { - assertNull(resultDto.getOrganisation().getLegalStructure()); - } - } else { - if (party.getPartyType() != Party.PartyTypeEnum.ORGANISATION) { - assertNull(resultDto.getOrganisation()); - } else { - assertNull(resultDto.getOrganisation()); - } - } + assertNull(resultDto.getPerson()); + } - if (party.getPostalAddresses() != null) { - assertNotNull(resultDto.getPostalAddresses()); - assertEquals(party.getPostalAddresses().size(), resultDto.getPostalAddresses().size()); - } else { - assertNull(resultDto.getPostalAddresses()); - } + @Test + @DisplayName("Should map Organisation when PartyType is ORGANISATION and Organisation is not null") + void shouldMapOrganisationWhenPartyTypeIsOrganisation() { + var party = fixtureMonkey.giveMeBuilder(Party.class) + .set("partyType", Party.PartyTypeEnum.ORGANISATION) + .setNotNull("organisation") + .set("organisation.name", "My Company") + .setNull("person") + .sample(); + var resultDto = partyMapper.partyToPartyUpsertDto(party); + assertNotNull(resultDto.getOrganisation()); + assertEquals("My Company", resultDto.getOrganisation().getName()); + assertNull(resultDto.getPerson()); + } - if (party.getPartyPartyRelationships() != null) { - assertNotNull(resultDto.getPartyPartyRelationships()); - assertEquals(party.getPartyPartyRelationships().size(), resultDto.getPartyPartyRelationships().size()); - } else { - assertNull(resultDto.getPartyPartyRelationships()); - } + @Test + @DisplayName("Should handle null Organisation from source") + void shouldHandleNullOrganisation() { + Party party = fixtureMonkey.giveMeBuilder(Party.class) + .setNull("organisation") + .sample(); + var resultDto = partyMapper.partyToPartyUpsertDto(party); + assertNull(resultDto.getOrganisation()); + } + @Test + @DisplayName("Should map populated collections correctly") + void shouldMapPopulatedCollections() { + + var party = fixtureMonkey.giveMeBuilder(Party.class) + .size("phoneNumbers", 2) + .size("postalAddresses", 1) + .size("customFields", 3) + .size("partyPartyRelationships", 1) + .sample(); + + var resultDto = partyMapper.partyToPartyUpsertDto(party); + + assertNotNull(resultDto.getPhoneNumbers()); + assertEquals(2, resultDto.getPhoneNumbers().size()); + + assertNotNull(resultDto.getPostalAddresses()); + assertEquals(1, resultDto.getPostalAddresses().size()); + + assertNotNull(resultDto.getAdditions()); + assertEquals(3, resultDto.getAdditions().size()); + + assertNotNull(resultDto.getPartyPartyRelationships()); + assertEquals(1, resultDto.getPartyPartyRelationships().size()); } + + @Test + @DisplayName("Should map empty collections correctly") + void shouldMapEmptyCollections() { + var party = fixtureMonkey.giveMeBuilder(Party.class) + .set("phoneNumbers", new ArrayList<>()) + .set("postalAddresses", new ArrayList<>()) + .set("customFields", new HashMap<>()) + .set("partyPartyRelationships", new ArrayList<>()) + .sample(); + + var resultDto = partyMapper.partyToPartyUpsertDto(party); + + assertNotNull(resultDto.getPhoneNumbers()); + assertTrue(resultDto.getPhoneNumbers().isEmpty()); + + assertNotNull(resultDto.getPostalAddresses()); + assertTrue(resultDto.getPostalAddresses().isEmpty()); + + assertNotNull(resultDto.getAdditions()); + assertTrue(resultDto.getAdditions().isEmpty()); + + assertNotNull(resultDto.getPartyPartyRelationships()); + assertTrue(resultDto.getPartyPartyRelationships().isEmpty()); + } + + @Test + @DisplayName("Should map empty collections correctly") + void shouldMapNullCollections() { + + var party = fixtureMonkey.giveMeBuilder(Party.class) + .setNull("phoneNumbers") + .setNull("postalAddresses") + .setNull("customFields") + .setNull("partyPartyRelationships") + .setNull("electronicAddresses.emails") + .setNull("electronicAddresses.urls") + .setNull("person.identifications") + .setNull("organisation.identifications") + .sample(); + + var resultDto = partyMapper.partyToPartyUpsertDto(party); + + assertNotNull(resultDto.getPhoneNumbers()); + assertTrue(resultDto.getPhoneNumbers().isEmpty()); + + assertNotNull(resultDto.getPostalAddresses()); + assertTrue(resultDto.getPostalAddresses().isEmpty()); + + assertNotNull(resultDto.getAdditions()); + assertTrue(resultDto.getAdditions().isEmpty()); + + assertNotNull(resultDto.getPartyPartyRelationships()); + assertTrue(resultDto.getPartyPartyRelationships().isEmpty()); + + assertNotNull(resultDto.getElectronicAddresses()); + assertNotNull(resultDto.getElectronicAddresses().getEmails()); + assertTrue(resultDto.getElectronicAddresses().getEmails().isEmpty()); + + assertNotNull(resultDto.getElectronicAddresses().getUrls()); + assertTrue(resultDto.getElectronicAddresses().getUrls().isEmpty()); + } + } diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java index be66366c7..ea657d0f0 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/service/CustomerProfileServiceTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mapstruct.factory.Mappers; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -36,7 +37,7 @@ class CustomerProfileServiceTest { @BeforeEach void setup() { - customerProfileService = new CustomerProfileService(partyManagementIntegrationApiMock, PartyMapper.INSTANCE); + customerProfileService = new CustomerProfileService(partyManagementIntegrationApiMock, Mappers.getMapper(PartyMapper.class)); } @Test From be55727e94eb0b4d7ebadb497f01101fcb10a29a Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Tue, 29 Apr 2025 13:25:14 +0200 Subject: [PATCH 35/41] Trigger Build From 8a189ddf5ddf249d9c569573d427a64e78d93d38 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 12:37:01 +0200 Subject: [PATCH 36/41] Remove unused PartyMapper bean from CustomerProfileConfiguration and update test to mock PartyMapper --- .../stream/configuration/CustomerProfileConfiguration.java | 7 ------- .../configuration/CustomerProfileConfigurationTest.java | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java index 4b6e2fc99..5c457fd8b 100644 --- a/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java +++ b/stream-customer-profile/customer-profile-core/src/main/java/com/backbase/stream/configuration/CustomerProfileConfiguration.java @@ -5,7 +5,6 @@ import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.service.CustomerProfileService; import lombok.extern.slf4j.Slf4j; -import org.mapstruct.factory.Mappers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,12 +14,6 @@ @EnableConfigurationProperties(CustomerProfileClientConfig.class) public class CustomerProfileConfiguration { - - @Bean - public PartyMapper partyMapper() { - return Mappers.getMapper(PartyMapper.class); - } - @Bean public CustomerProfileService createCustomerProfileService( PartyManagementIntegrationApi partyManagementIntegrationApi, PartyMapper partyMapper) { diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java index 3e5519720..b55abac35 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java @@ -9,6 +9,7 @@ import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.service.CustomerProfileService; import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @@ -25,13 +26,13 @@ void configurationTest() { .withBean(WebClientAutoConfiguration.class) .withBean(InterServiceWebClientConfiguration.class) .withBean(PartyManagementIntegrationApi.class, () -> mock(PartyManagementIntegrationApi.class)) + .withBean(PartyMapper.class, () -> mock(PartyMapper.class)) .withUserConfiguration(CustomerProfileConfiguration.class) .run(context -> { assertThat(context).hasSingleBean(CustomerProfileService.class); assertThat(context).hasSingleBean(PartyManagementIntegrationApi.class); assertThat(context).hasSingleBean(WebClient.class); assertThat(context).hasSingleBean(CustomerProfileClientConfig.class); - assertThat(context).hasSingleBean(PartyMapper.class); }); } } \ No newline at end of file From 2a502761f1a5dad45e9c2cc86411eb3a7f05419e Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 12:39:28 +0200 Subject: [PATCH 37/41] Remove unused PartyMapper bean from CustomerProfileConfiguration and update test to mock PartyMapper --- .../stream/configuration/CustomerProfileConfigurationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java index b55abac35..e768c9b6a 100644 --- a/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java +++ b/stream-customer-profile/customer-profile-core/src/test/java/com/backbase/stream/configuration/CustomerProfileConfigurationTest.java @@ -9,7 +9,6 @@ import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.service.CustomerProfileService; import org.junit.jupiter.api.Test; -import org.mapstruct.factory.Mappers; import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @@ -33,6 +32,7 @@ void configurationTest() { assertThat(context).hasSingleBean(PartyManagementIntegrationApi.class); assertThat(context).hasSingleBean(WebClient.class); assertThat(context).hasSingleBean(CustomerProfileClientConfig.class); + assertThat(context).hasSingleBean(PartyMapper.class); }); } } \ No newline at end of file From b6d0232448ebb5883150eaa2ba63c994b63a6d73 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 12:51:43 +0200 Subject: [PATCH 38/41] Add PartyMapper mock to ServiceAgreementControllerTest --- .../stream/controller/ServiceAgreementControllerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java index a4907522a..f8d0e2ced 100644 --- a/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java +++ b/stream-legal-entity/legal-entity-http/src/test/java/com/backbase/stream/controller/ServiceAgreementControllerTest.java @@ -34,6 +34,7 @@ import com.backbase.stream.legalentity.model.UpdatedServiceAgreement; import com.backbase.stream.legalentity.model.UpdatedServiceAgreementResponse; import com.backbase.stream.legalentity.model.User; +import com.backbase.stream.mapper.PartyMapper; import com.backbase.stream.product.task.BatchProductGroupTask; import com.backbase.stream.product.task.ProductGroupTask; import com.backbase.stream.service.AccessGroupService; @@ -129,6 +130,9 @@ class ServiceAgreementControllerTest { @MockBean private PlansService plansService; + @MockBean + private PartyMapper partyMapper; + @MockBean private CustomerProfileClientConfig customerProfileClientConfig; From af73c134fb3f74aceccff76561a9800f058a2919 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 14:12:38 +0200 Subject: [PATCH 39/41] Add HelperProcessor class to handle party processing logic in LegalEntitySaga --- .../com/backbase/stream/HelperProcessor.java | 119 ++++++++++++++++++ .../com/backbase/stream/LegalEntitySaga.java | 86 +------------ .../backbase/stream/LegalEntitySagaV2.java | 74 +---------- 3 files changed, 130 insertions(+), 149 deletions(-) create mode 100644 stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java new file mode 100644 index 000000000..94220a399 --- /dev/null +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java @@ -0,0 +1,119 @@ +package com.backbase.stream; + +import static com.backbase.stream.product.utils.StreamUtils.nullableCollectionToStream; +import static org.springframework.util.CollectionUtils.isEmpty; + +import com.backbase.stream.legalentity.model.Party; +import com.backbase.stream.service.CustomerProfileService; +import com.backbase.stream.worker.model.StreamTask; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +class HelperProcessor { + + protected static final String LEGAL_ENTITY = "LEGAL_ENTITY"; + protected static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; + protected static final String PARTY = "party"; + protected static final String FAILED = "failed"; + + protected static final String SERVICE_AGREEMENT = "SERVICE_AGREEMENT"; + protected static final String BUSINESS_FUNCTION_GROUP = "BUSINESS_FUNCTION_GROUP"; + protected static final String USER = "USER"; + protected static final String DEFAULT_DATA_GROUP = "Default data group"; + protected static final String DEFAULT_DATA_DESCRIPTION = "Default data group description"; + protected static final String UPSERT_LEGAL_ENTITY = "upsert-legal-entity"; + protected static final String EXISTS = "exists"; + protected static final String CREATED = "created"; + + protected static final String UPDATED = "updated"; + protected static final String PROCESS_PRODUCTS = "process-products"; + protected static final String PROCESS_JOB_PROFILES = "process-job-profiles"; + protected static final String PROCESS_LIMITS = "process-limits"; + protected static final String PROCESS_CONTACTS = "process-contacts"; + protected static final String REJECTED = "rejected"; + protected static final String UPSERT = "upsert"; + protected static final String SETUP_SERVICE_AGREEMENT = "setup-service-agreement"; + protected static final String BATCH_PRODUCT_GROUP_ID = "batch_product_group_task-"; + + protected static final String LEGAL_ENTITY_E_TYPE = "LE"; + protected static final String SERVICE_AGREEMENT_E_TYPE = "SA"; + protected static final String FUNCTION_GROUP_E_TYPE = "FAG"; + protected static final String FUNCTION_E_TYPE = "FUN"; + protected static final String PRIVILEGE_E_TYPE = "PRV"; + protected static final String JOB_ROLE_LIMITS = "job-role-limits"; + protected static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; + protected static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; + protected static final String IDENTITY_USER = "IDENTITY_USER"; + + private boolean isValidParty( + T legalEntityTask, + List parties, + String legalEntityInternalId, + String legalEntityExternalId) { + if (isEmpty(parties)) { + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntityExternalId, + legalEntityInternalId, "No parties found in Legal Entity to process."); + return false; + } + return true; + } + + public Mono processParties( + T legalEntityTask, + List parties, + String legalEntityInternalId, + String legalEntityExternalId, + CustomerProfileService customerProfileService) { + + log.info("Processing Customer Profile Parties for: {}", legalEntityExternalId); + + if (!isValidParty(legalEntityTask, parties, legalEntityInternalId, legalEntityExternalId)) { + return Mono.just(legalEntityTask); + } + + var processingErrors = new CopyOnWriteArrayList<>(); + + return Flux.fromStream(nullableCollectionToStream(parties)) + .filter(Objects::nonNull) + .concatMap(party -> { + log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); + return customerProfileService.upsertParty(party, legalEntityInternalId) + .doOnSuccess(result -> legalEntityTask + .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, + "Successfully upserted party: %s for LE: %s", party.getPartyId(), + legalEntityExternalId)) + .onErrorResume(throwable -> { + log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), + throwable); + processingErrors.add(throwable); + legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, + throwable, + throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), + legalEntityExternalId); + return Mono.empty(); + }) + .then(Mono.just(true)); + }) + .then(Mono.fromRunnable(() -> { + if (!processingErrors.isEmpty()) { + log.warn("Completed processing parties for LE {} with {} errors.", legalEntityExternalId, + processingErrors.size()); + legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", + legalEntityExternalId, + legalEntityInternalId, "Party processing completed with %d errors.", + processingErrors.size()); + } else { + log.info("Successfully processed all parties for LE {}.", legalEntityInternalId); + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", + legalEntityExternalId, + legalEntityInternalId, "Party processing completed successfully."); + } + })) + .thenReturn(legalEntityTask); + } +} diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java index b1cef7915..4e9e4bd10 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySaga.java @@ -83,7 +83,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -105,40 +104,8 @@ * After the users are created / retrieved and enriched with their internal Ids we can setup the Master Service */ @Slf4j -public class LegalEntitySaga implements StreamTaskExecutor { - - public static final String LEGAL_ENTITY = "LEGAL_ENTITY"; - public static final String IDENTITY_USER = "IDENTITY_USER"; - public static final String SERVICE_AGREEMENT = "SERVICE_AGREEMENT"; - public static final String BUSINESS_FUNCTION_GROUP = "BUSINESS_FUNCTION_GROUP"; - public static final String USER = "USER"; - private static final String DEFAULT_DATA_GROUP = "Default data group"; - private static final String DEFAULT_DATA_DESCRIPTION = "Default data group description"; - public static final String UPSERT_LEGAL_ENTITY = "upsert-legal-entity"; - public static final String FAILED = "failed"; - public static final String EXISTS = "exists"; - public static final String CREATED = "created"; - - public static final String UPDATED = "updated"; - public static final String PROCESS_PRODUCTS = "process-products"; - public static final String PROCESS_JOB_PROFILES = "process-job-profiles"; - public static final String PROCESS_LIMITS = "process-limits"; - public static final String PROCESS_CONTACTS = "process-contacts"; - public static final String REJECTED = "rejected"; - public static final String UPSERT = "upsert"; - public static final String SETUP_SERVICE_AGREEMENT = "setup-service-agreement"; - private static final String BATCH_PRODUCT_GROUP_ID = "batch_product_group_task-"; - public static final String PARTY = "party"; - public static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; - - private static final String LEGAL_ENTITY_E_TYPE = "LE"; - private static final String SERVICE_AGREEMENT_E_TYPE = "SA"; - private static final String FUNCTION_GROUP_E_TYPE = "FAG"; - private static final String FUNCTION_E_TYPE = "FUN"; - private static final String PRIVILEGE_E_TYPE = "PRV"; - private static final String JOB_ROLE_LIMITS = "job-role-limits"; - private static final String USER_JOB_ROLE_LIMITS = "user-job-role-limits"; - private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; +public class LegalEntitySaga extends HelperProcessor implements StreamTaskExecutor { + private final BusinessFunctionGroupMapper businessFunctionGroupMapper = Mappers.getMapper(BusinessFunctionGroupMapper.class); private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class); @@ -1101,53 +1068,12 @@ private Mono processSubsidiaries(LegalEntityTask streamTask) { private Mono setupParties(LegalEntityTask legalEntityTask) { - log.info("Processing Customer Profile Parties for: {}", legalEntityTask.getName()); var legalEntity = legalEntityTask.getData(); - if (isEmpty(legalEntity.getParties())) { - legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntity.getExternalId(), - legalEntity.getInternalId(), "No parties found in Legal Entity to process."); - return Mono.just(legalEntityTask); - } - var processingErrors = new CopyOnWriteArrayList<>(); - - return Flux.fromStream(nullableCollectionToStream(legalEntity.getParties())) - .filter(Objects::nonNull) - .concatMap(party -> { - log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntity.getInternalId()) - .doOnSuccess(result -> legalEntityTask - .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, - "Successfully upserted party: %s for LE: %s", party.getPartyId(), - legalEntity.getExternalId())) - .onErrorResume(throwable -> { - log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), - throwable); - processingErrors.add(throwable); - legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, - throwable, - throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), - legalEntity.getExternalId()); - return Mono.empty(); - }) - .then(Mono.just(true)); - }) - .then(Mono.fromRunnable(() -> { - if (!processingErrors.isEmpty()) { - log.warn("Completed processing parties for LE {} with {} errors.", legalEntity.getExternalId(), - processingErrors.size()); - legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", - legalEntity.getExternalId(), - legalEntity.getInternalId(), "Party processing completed with %d errors.", - processingErrors.size()); - } else { - log.info("Successfully processed all parties for LE {}.", legalEntity.getExternalId()); - legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", - legalEntity.getExternalId(), - legalEntity.getInternalId(), "Party processing completed successfully."); - } - })) - .thenReturn(legalEntityTask); + return processParties(legalEntityTask, legalEntity.getParties(), + legalEntity.getInternalId(), + legalEntity.getExternalId(), customerProfileService); + } private Mono linkLegalEntityToRealm(LegalEntityTask streamTask) { diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java index bf8608d05..eed85a83e 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/LegalEntitySagaV2.java @@ -77,28 +77,7 @@ * After the users are created / retrieved and enriched with their internal Ids we can setup the Master Service */ @Slf4j -public class LegalEntitySagaV2 implements StreamTaskExecutor { - - public static final String LEGAL_ENTITY = "LEGAL_ENTITY"; - public static final String IDENTITY_USER = "IDENTITY_USER"; - public static final String USER = "USER"; - public static final String UPSERT_LEGAL_ENTITY = "upsert-legal-entity"; - public static final String FAILED = "failed"; - public static final String EXISTS = "exists"; - public static final String CREATED = "created"; - - public static final String UPDATED = "updated"; - public static final String PROCESS_LIMITS = "process-limits"; - public static final String PROCESS_CONTACTS = "process-contacts"; - public static final String UPSERT = "upsert"; - public static final String PARTY = "party"; - - private static final String LEGAL_ENTITY_E_TYPE = "LE"; - private static final String SERVICE_AGREEMENT_E_TYPE = "SA"; - private static final String FUNCTION_E_TYPE = "FUN"; - private static final String PRIVILEGE_E_TYPE = "PRV"; - private static final String LEGAL_ENTITY_LIMITS = "legal-entity-limits"; - public static final String PROCESS_CUSTOMER_PROFILE = "process-customer-profile"; +public class LegalEntitySagaV2 extends HelperProcessor implements StreamTaskExecutor { private final UserProfileMapper userProfileMapper = Mappers.getMapper(UserProfileMapper.class); private final LegalEntityV2toV1Mapper leV2Mapper = Mappers.getMapper(LegalEntityV2toV1Mapper.class); @@ -592,54 +571,11 @@ private Mono setupLegalEntityLevelBusinessFunctionLimits(Lega private Mono setupParties(LegalEntityTaskV2 legalEntityTaskV2) { - log.info("Processing Parties for: {}", legalEntityTaskV2.getName()); + var legalEntity = legalEntityTaskV2.getData(); - LegalEntityV2 legalEntityV2 = legalEntityTaskV2.getData(); - - if (isEmpty(legalEntityV2.getParties())) { - legalEntityTaskV2.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "skipped", legalEntityV2.getExternalId(), - legalEntityV2.getInternalId(), "No parties found in Legal Entity to process."); - return Mono.just(legalEntityTaskV2); - } - var processingErrors = new CopyOnWriteArrayList(); - - return Flux.fromStream(nullableCollectionToStream(legalEntityV2.getParties())) - .filter(Objects::nonNull) - .concatMap(party -> { - log.debug("Processing party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntityV2.getInternalId()) - .doOnSuccess(result -> legalEntityTaskV2 - .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, - "Successfully processed party: %s for LE: %s", party.getPartyId(), - legalEntityV2.getExternalId())) - .onErrorResume(throwable -> { - log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), - throwable); - processingErrors.add(throwable); - legalEntityTaskV2.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, - throwable, - throwable.getMessage(), "Error processing party: %s for LE: %s", party.getPartyId(), - legalEntityV2.getExternalId()); - return Mono.empty(); - }) - .then(Mono.just(true)); - }) - .then(Mono.fromRunnable(() -> { - if (!processingErrors.isEmpty()) { - log.warn("Processed parties for LE {} with {} errors.", legalEntityV2.getExternalId(), - processingErrors.size()); - legalEntityTaskV2.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", - legalEntityV2.getExternalId(), - legalEntityV2.getInternalId(), "Party processing completed with %d errors.", - processingErrors.size()); - } else { - log.info("Successfully processed all parties for LE {}.", legalEntityV2.getExternalId()); - legalEntityTaskV2.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", - legalEntityV2.getExternalId(), - legalEntityV2.getInternalId(), "Party processing completed successfully."); - } - })) - .thenReturn(legalEntityTaskV2); + return processParties(legalEntityTaskV2, legalEntity.getParties(), + legalEntity.getInternalId(), + legalEntity.getExternalId(), customerProfileService); } private Stream createLimitsTask(LegalEntityTaskV2 streamTask, String legalEntityId, From afad5f3552ae44e822acd42eb485a94b271cdef9 Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 14:16:47 +0200 Subject: [PATCH 40/41] Add HelperProcessor class to handle party processing logic in LegalEntitySaga --- .../com/backbase/stream/HelperProcessor.java | 105 +++++++++++------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java index 94220a399..c4661bc76 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java @@ -63,57 +63,84 @@ private boolean isValidParty( return true; } + public Mono processParties( T legalEntityTask, List parties, String legalEntityInternalId, String legalEntityExternalId, - CustomerProfileService customerProfileService) { - - log.info("Processing Customer Profile Parties for: {}", legalEntityExternalId); + CustomerProfileService customerProfileService + ) { + log.info("Processing Customer Profile Parties for LE: {}", legalEntityExternalId); if (!isValidParty(legalEntityTask, parties, legalEntityInternalId, legalEntityExternalId)) { - return Mono.just(legalEntityTask); + return Mono.just(legalEntityTask); // Salida temprana si no hay parties } - var processingErrors = new CopyOnWriteArrayList<>(); + var processingErrors = new CopyOnWriteArrayList(); return Flux.fromStream(nullableCollectionToStream(parties)) .filter(Objects::nonNull) - .concatMap(party -> { - log.debug("Attempting to upsert party with partyId: {}", party.getPartyId()); - return customerProfileService.upsertParty(party, legalEntityInternalId) - .doOnSuccess(result -> legalEntityTask - .info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", party.getPartyId(), null, - "Successfully upserted party: %s for LE: %s", party.getPartyId(), - legalEntityExternalId)) - .onErrorResume(throwable -> { - log.error("Failed to upsert party {}: {}", party.getPartyId(), throwable.getMessage(), - throwable); - processingErrors.add(throwable); - legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, party.getPartyId(), null, - throwable, - throwable.getMessage(), "Error upserting party: %s for LE: %s", party.getPartyId(), - legalEntityExternalId); - return Mono.empty(); - }) - .then(Mono.just(true)); - }) - .then(Mono.fromRunnable(() -> { - if (!processingErrors.isEmpty()) { - log.warn("Completed processing parties for LE {} with {} errors.", legalEntityExternalId, - processingErrors.size()); - legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", - legalEntityExternalId, - legalEntityInternalId, "Party processing completed with %d errors.", - processingErrors.size()); - } else { - log.info("Successfully processed all parties for LE {}.", legalEntityInternalId); - legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", - legalEntityExternalId, - legalEntityInternalId, "Party processing completed successfully."); - } - })) + .concatMap(party -> handlePartyUpsert( + party, + legalEntityInternalId, + legalEntityExternalId, + customerProfileService, + processingErrors, + legalEntityTask + )) + .then(Mono.fromRunnable(() -> logFinalProcessingStatus( + processingErrors, + legalEntityInternalId, + legalEntityExternalId, + legalEntityTask + ))) .thenReturn(legalEntityTask); } + + private void logFinalProcessingStatus( + List processingErrors, + String legalEntityInternalId, + String legalEntityExternalId, + T legalEntityTask + ) { + if (!processingErrors.isEmpty()) { + int errorCount = processingErrors.size(); + log.warn("Completed processing parties for LE {} with {} error(s).", legalEntityExternalId, errorCount); + legalEntityTask.warn(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_with_errors", + legalEntityExternalId, legalEntityInternalId, + "Party processing completed with %d error(s).", errorCount); + } else { + log.info("Successfully processed all parties for LE {}.", legalEntityExternalId); + legalEntityTask.info(LEGAL_ENTITY, PROCESS_CUSTOMER_PROFILE, "completed_successfully", + legalEntityExternalId, legalEntityInternalId, + "Party processing completed successfully."); + } + } + + private Mono handlePartyUpsert( + Party party, + String legalEntityInternalId, + String legalEntityExternalId, + CustomerProfileService customerProfileService, + List processingErrors, + T legalEntityTask + ) { + String partyId = party.getPartyId(); + log.debug("Attempting to upsert party with partyId: {}", partyId); + + return customerProfileService.upsertParty(party, legalEntityInternalId) + .doOnSuccess(result -> + legalEntityTask.info(PARTY, PROCESS_CUSTOMER_PROFILE, "upserted", partyId, null, + "Successfully upserted party: %s for LE: %s", partyId, legalEntityExternalId) + ) + .doOnError(throwable -> { + log.error("Failed to upsert party {}: {}", partyId, throwable.getMessage(), throwable); + processingErrors.add(throwable); + legalEntityTask.error(PARTY, PROCESS_CUSTOMER_PROFILE, FAILED, partyId, null, throwable, + throwable.getMessage(), "Error upserting party: %s for LE: %s", partyId, legalEntityExternalId); + }) + .onErrorResume(throwable -> Mono.empty()) + .then(); + } } From 748260ff33d9cc6194d915e96dff7cb8d8c93b5b Mon Sep 17 00:00:00 2001 From: Jose Manzano Date: Wed, 30 Apr 2025 14:37:13 +0200 Subject: [PATCH 41/41] Add unit tests for HelperProcessor to validate party processing logic --- .../com/backbase/stream/HelperProcessor.java | 2 +- .../backbase/stream/HelperProcessorTest.java | 188 ++++++++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/HelperProcessorTest.java diff --git a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java index c4661bc76..539598f34 100644 --- a/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java +++ b/stream-legal-entity/legal-entity-core/src/main/java/com/backbase/stream/HelperProcessor.java @@ -74,7 +74,7 @@ public Mono processParties( log.info("Processing Customer Profile Parties for LE: {}", legalEntityExternalId); if (!isValidParty(legalEntityTask, parties, legalEntityInternalId, legalEntityExternalId)) { - return Mono.just(legalEntityTask); // Salida temprana si no hay parties + return Mono.just(legalEntityTask); } var processingErrors = new CopyOnWriteArrayList(); diff --git a/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/HelperProcessorTest.java b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/HelperProcessorTest.java new file mode 100644 index 000000000..990458429 --- /dev/null +++ b/stream-legal-entity/legal-entity-core/src/test/java/com/backbase/stream/HelperProcessorTest.java @@ -0,0 +1,188 @@ +package com.backbase.stream; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.backbase.customerprofile.api.integration.v1.model.PartyResponseUpsertDto; +import com.backbase.stream.legalentity.model.Party; +import com.backbase.stream.legalentity.model.Party.PartyTypeEnum; +import com.backbase.stream.service.CustomerProfileService; +import com.backbase.stream.worker.model.StreamTask; +import java.util.Collections; +import java.util.List; +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.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@ExtendWith(MockitoExtension.class) +class HelperProcessorTest { + + @Mock + private CustomerProfileService customerProfileService; + + @Mock + private StreamTask streamTask; + + @InjectMocks + private HelperProcessor helperProcessor; + + private Party party1; + private Party party2; + private final String internalId = "int-123"; + private final String externalId = "ext-abc"; + + @BeforeEach + void setUp() { + party1 = new Party("party-001", true, PartyTypeEnum.PERSON); + party2 = new Party("party-002", true, PartyTypeEnum.PERSON); + + } + + @Nested + @DisplayName("When parties list is empty or null") + class EmptyOrNullParties { + + @Test + @DisplayName("should log skipped and return immediately for empty list") + void processParties_emptyList_shouldSkip() { + List emptyList = Collections.emptyList(); + + Mono result = helperProcessor.processParties( + streamTask, emptyList, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, never()).upsertParty(any(), anyString()); + } + + @Test + @DisplayName("should log skipped and return immediately for null list") + void processParties_nullList_shouldSkip() { + Mono result = helperProcessor.processParties( + streamTask, null, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, never()).upsertParty(any(), anyString()); + } + } + + @Nested + @DisplayName("When processing valid parties") + class ValidParties { + + @Test + @DisplayName("should process all parties successfully") + void processParties_allSuccess() { + List parties = List.of(party1, party2); + when(customerProfileService.upsertParty(any(Party.class), eq(internalId))) + .thenReturn(Mono.just(new PartyResponseUpsertDto())); + + Mono result = helperProcessor.processParties( + streamTask, parties, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, times(2)).upsertParty(any(Party.class), eq(internalId)); + + verify(streamTask, never()).warn(anyString(), anyString(), anyString(), anyString(), anyString(), + anyString(), any()); + verify(streamTask, never()).error(anyString(), anyString(), anyString(), anyString(), any(), + any(Throwable.class), anyString(), any()); + } + + @Test + @DisplayName("should handle one error and complete with warning") + void processParties_oneError() { + List parties = List.of(party1, party2); + RuntimeException dbError = new RuntimeException("DB connection failed"); + + when(customerProfileService.upsertParty(eq(party1), eq(internalId))) + .thenReturn(Mono.just(new PartyResponseUpsertDto())); + when(customerProfileService.upsertParty(eq(party2), eq(internalId))) + .thenReturn(Mono.error(dbError)); + + Mono result = helperProcessor.processParties( + streamTask, parties, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, times(2)).upsertParty(any(Party.class), eq(internalId)); + + verify(streamTask, never()).info(anyString(), anyString(), eq("completed_successfully"), anyString(), + anyString(), anyString(), any()); + } + + @Test + @DisplayName("should handle all errors and complete with warning") + void processParties_allErrors() { + List parties = List.of(party1, party2); + RuntimeException error1 = new RuntimeException("Error 1"); + RuntimeException error2 = new RuntimeException("Error 2"); + + when(customerProfileService.upsertParty(eq(party1), eq(internalId))) + .thenReturn(Mono.error(error1)); + when(customerProfileService.upsertParty(eq(party2), eq(internalId))) + .thenReturn(Mono.error(error2)); + + Mono result = helperProcessor.processParties( + streamTask, parties, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, times(2)).upsertParty(any(Party.class), eq(internalId)); + + verify(streamTask, never()).info(anyString(), anyString(), eq("upserted"), anyString(), any(), anyString(), + any()); + verify(streamTask, never()).info(anyString(), anyString(), eq("completed_successfully"), anyString(), + anyString(), anyString(), any()); + } + + @Test + @DisplayName("should filter out null parties from the list") + void processParties_withNullInList() { + List parties = List.of(party1, party2); + when(customerProfileService.upsertParty(any(Party.class), eq(internalId))) + .thenReturn(Mono.just(new PartyResponseUpsertDto())); + + Mono result = helperProcessor.processParties( + streamTask, parties, internalId, externalId, customerProfileService + ); + + StepVerifier.create(result) + .expectNext(streamTask) + .verifyComplete(); + + verify(customerProfileService, times(2)).upsertParty(any(Party.class), eq(internalId)); + verify(customerProfileService).upsertParty(eq(party1), eq(internalId)); + verify(customerProfileService).upsertParty(eq(party2), eq(internalId)); + } + } +}