diff --git a/connector-api/pom.xml b/connector-api/pom.xml index 9e56523e..3b2983f1 100644 --- a/connector-api/pom.xml +++ b/connector-api/pom.xml @@ -21,7 +21,7 @@ it.pagopa.selfcare onboarding-sdk-product - 0.1.10 + 0.1.14 diff --git a/connector-api/src/main/java/it/pagopa/selfcare/external_api/api/MsCoreConnector.java b/connector-api/src/main/java/it/pagopa/selfcare/external_api/api/MsCoreConnector.java index cc427f8d..e8779b8f 100644 --- a/connector-api/src/main/java/it/pagopa/selfcare/external_api/api/MsCoreConnector.java +++ b/connector-api/src/main/java/it/pagopa/selfcare/external_api/api/MsCoreConnector.java @@ -24,6 +24,8 @@ public interface MsCoreConnector { List getInstitutionUserProductsV2(String institutionId, String id); + Institution getInstitution(String institutionId); + String createPgInstitution(String description, String taxId); } diff --git a/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/OnboardedInstitutionResource.java b/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/OnboardedInstitutionResource.java new file mode 100644 index 00000000..40e728e5 --- /dev/null +++ b/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/OnboardedInstitutionResource.java @@ -0,0 +1,42 @@ +package it.pagopa.selfcare.external_api.model.onboarding; + +import it.pagopa.selfcare.commons.base.utils.InstitutionType; +import it.pagopa.selfcare.external_api.model.institutions.RootParent; +import lombok.Data; + +import java.util.Collection; +import java.util.UUID; + +@Data +public class OnboardedInstitutionResource { + + private UUID id; + private String description; + private String externalId; + private String originId; + private InstitutionType institutionType; + private String digitalAddress; + private String status; + private String address; + private String zipCode; + private String taxCode; + private String taxCodeInvoicing; + private String origin; + private Collection userProductRoles; + private String recipientCode; + private String rea; + private String shareCapital; + private String businessRegisterPlace; + private String supportEmail; + private String supportPhone; + private PaymentServiceProvider paymentServiceProvider; + private DataProtectionOfficer dataProtectionOfficer; + private String subunitCode; + private String subunitType; + private RootParent rootParent; + private String aooParentCode; + private String country; + private String county; + private String city; + +} diff --git a/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/mapper/OnboardingInstitutionMapper.java b/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/mapper/OnboardingInstitutionMapper.java index df5658ec..9cfa7a69 100644 --- a/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/mapper/OnboardingInstitutionMapper.java +++ b/connector-api/src/main/java/it/pagopa/selfcare/external_api/model/onboarding/mapper/OnboardingInstitutionMapper.java @@ -1,11 +1,51 @@ package it.pagopa.selfcare.external_api.model.onboarding.mapper; +import it.pagopa.selfcare.external_api.model.institutions.Institution; +import it.pagopa.selfcare.external_api.model.institutions.Onboarding; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; +import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResource; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResponse; +import it.pagopa.selfcare.external_api.model.user.OnboardedProductResponse; +import it.pagopa.selfcare.external_api.model.user.RelationshipState; +import it.pagopa.selfcare.external_api.model.user.UserInstitution; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; @Mapper(componentModel = "spring") public interface OnboardingInstitutionMapper { OnboardedInstitutionResponse toOnboardedInstitutionResponse(OnboardedInstitutionInfo onboardedInstitutionInfo); + + @Mapping(target = "userProductRoles", expression = "java(retrieveUserProductRole(userInstitution, productId))") + @Mapping(target = "status", expression = "java(retrieveStatus(institution, productId))") + @Mapping(target = "id", source = "institution.id") + OnboardedInstitutionResource toOnboardedInstitutionResource(Institution institution, UserInstitution userInstitution, String productId); + + + @Named("retrieveStatus") + default String retrieveStatus(Institution institution, String productId) { + List statusList = institution.getOnboarding().stream() + .filter(onboarding -> productId.equalsIgnoreCase(onboarding.getProductId())) + .map(Onboarding::getStatus) + .toList(); + + if(CollectionUtils.isEmpty(statusList)) + return null; + + return Collections.min(statusList).name(); + } + + @Named("retrieveUserProductRole") + default Collection retrieveUserProductRole(UserInstitution userInstitution, String productId) { + return userInstitution.getProducts().stream() + .collect(Collectors.groupingBy(OnboardedProductResponse::getProductId, Collectors.mapping(OnboardedProductResponse::getProductRole, Collectors.toList()))) + .get(productId); + } } diff --git a/connector/rest/pom.xml b/connector/rest/pom.xml index 40a91036..db17c207 100644 --- a/connector/rest/pom.xml +++ b/connector/rest/pom.xml @@ -30,6 +30,12 @@ io.github.openfeign feign-okhttp + + it.pagopa.selfcare + onboarding-sdk-product + 0.1.8 + compile + diff --git a/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImpl.java b/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImpl.java index d33fac6d..93c7795f 100644 --- a/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImpl.java +++ b/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImpl.java @@ -1,6 +1,5 @@ package it.pagopa.selfcare.external_api.connector.rest; -import it.pagopa.selfcare.commons.base.logging.LogUtils; import it.pagopa.selfcare.core.generated.openapi.v1.dto.CreatePgInstitutionRequest; import it.pagopa.selfcare.core.generated.openapi.v1.dto.InstitutionResponse; import it.pagopa.selfcare.core.generated.openapi.v1.dto.OnboardingResponse; @@ -9,15 +8,12 @@ import it.pagopa.selfcare.external_api.connector.rest.client.MsCoreRestClient; import it.pagopa.selfcare.external_api.connector.rest.client.MsUserApiRestClient; import it.pagopa.selfcare.external_api.connector.rest.mapper.InstitutionMapper; -import it.pagopa.selfcare.external_api.connector.rest.model.pnpg.CreatePnPgInstitutionRequest; -import it.pagopa.selfcare.external_api.connector.rest.model.pnpg.InstitutionPnPgResponse; import it.pagopa.selfcare.external_api.exceptions.ResourceNotFoundException; import it.pagopa.selfcare.external_api.model.institutions.GeographicTaxonomy; import it.pagopa.selfcare.external_api.model.institutions.Institution; import it.pagopa.selfcare.external_api.model.institutions.SearchMode; import it.pagopa.selfcare.external_api.model.onboarding.InstitutionOnboarding; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; -import it.pagopa.selfcare.external_api.model.pnpg.CreatePnPgInstitution; import it.pagopa.selfcare.user.generated.openapi.v1.dto.OnboardedProductResponse; import it.pagopa.selfcare.user.generated.openapi.v1.dto.UserDataResponse; import lombok.RequiredArgsConstructor; @@ -141,6 +137,13 @@ public List getInstitutionDetails(String institutionId return Collections.emptyList(); } + @Override + public Institution getInstitution(String institutionId) { + return institutionMapper.toInstitution(Objects.requireNonNull(institutionApiClient._retrieveInstitutionByIdUsingGET(institutionId)) + .getBody()); + } + + @Override public String createPgInstitution(String description, String taxId) { log.trace("createPgInstitution start"); diff --git a/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/mapper/InstitutionMapper.java b/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/mapper/InstitutionMapper.java index 531975bb..a56911a9 100644 --- a/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/mapper/InstitutionMapper.java +++ b/connector/rest/src/main/java/it/pagopa/selfcare/external_api/connector/rest/mapper/InstitutionMapper.java @@ -8,6 +8,7 @@ import it.pagopa.selfcare.external_api.model.institutions.AssistanceContacts; import it.pagopa.selfcare.external_api.model.institutions.CompanyInformations; import it.pagopa.selfcare.external_api.model.institutions.Institution; +import it.pagopa.selfcare.external_api.model.institutions.Onboarding; import it.pagopa.selfcare.external_api.model.onboarding.Billing; import it.pagopa.selfcare.external_api.model.onboarding.InstitutionOnboarding; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; @@ -89,4 +90,26 @@ default OffsetDateTime map(LocalDateTime localDateTime) { .map(time -> time.atZone(ZoneId.systemDefault()).toOffsetDateTime()) .orElse(null); } + + @Mapping(target = "onboarding", source = "onboarding", qualifiedByName = "toOnboardingWithDate") + Institution toInstitution(it.pagopa.selfcare.core.generated.openapi.v1.dto.InstitutionResponse body); + + @Named("toOnboardingWithDate") + default Onboarding toOnboardingWithDate(OnboardedProductResponse onboardedProductResponse) { + Onboarding onboarding = toOnboardingWithoutDate(onboardedProductResponse); + onboarding.setCreatedAt(convertDate(onboardedProductResponse.getCreatedAt())); + onboarding.setUpdatedAt(convertDate(onboardedProductResponse.getUpdatedAt())); + return onboarding; + } + + @Mapping(target = "createdAt", ignore = true) + @Mapping(target = "updatedAt", ignore = true) + @Mapping(target = "closedAt", ignore = true) + Onboarding toOnboardingWithoutDate(OnboardedProductResponse onboardedProductResponse); + + default OffsetDateTime convertDate(LocalDateTime localDateTime) { + return Optional.ofNullable(localDateTime) + .map(time -> time.atZone(ZoneId.systemDefault()).toOffsetDateTime()) + .orElse(null); + } } \ No newline at end of file diff --git a/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/InstitutionMapperTest.java b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/InstitutionMapperTest.java new file mode 100644 index 00000000..b422ea4a --- /dev/null +++ b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/InstitutionMapperTest.java @@ -0,0 +1,36 @@ +package it.pagopa.selfcare.external_api.connector.rest; + +import it.pagopa.selfcare.core.generated.openapi.v1.dto.InstitutionResponse; +import it.pagopa.selfcare.core.generated.openapi.v1.dto.OnboardedProductResponse; +import it.pagopa.selfcare.external_api.connector.rest.mapper.InstitutionMapperImpl; +import it.pagopa.selfcare.external_api.model.institutions.Institution; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDateTime; +import java.util.List; + +@ExtendWith(MockitoExtension.class) +public class InstitutionMapperTest { + + @InjectMocks + InstitutionMapperImpl institutionMapperImpl; + + @Test + void toOnboardingWithDate(){ + InstitutionResponse institutionResponse = new InstitutionResponse(); + OnboardedProductResponse onboardedProductResponse = new OnboardedProductResponse(); + onboardedProductResponse.setProductId("productId"); + onboardedProductResponse.setStatus(OnboardedProductResponse.StatusEnum.ACTIVE); + onboardedProductResponse.setCreatedAt(LocalDateTime.now()); + institutionResponse.setOnboarding(List.of(onboardedProductResponse)); + Institution institution = institutionMapperImpl.toInstitution(institutionResponse); + Assertions.assertNotNull(institution); + Assertions.assertNotNull(institution.getOnboarding()); + + } + +} diff --git a/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImplTest.java b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImplTest.java index 6010d3e8..1b35126c 100644 --- a/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImplTest.java +++ b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/MsCoreConnectorImplTest.java @@ -151,7 +151,7 @@ void getGeographicTaxonomyList() throws IOException { } @Test - void getInstitutionsByGeoTaxonomiesWithInstitutionNull() { + void getInstitutionsByGeoTaxonomiesWithInstitutionNull() { String geoTaxIds = "geoTaxIds"; SearchMode searchMode = SearchMode.any; @@ -219,11 +219,11 @@ void getInstitutionUserProductsV2() throws IOException { List response = msCoreConnector.getInstitutionUserProductsV2(institutionId, userId); Assertions.assertEquals(1, response.size()); - Assertions.assertEquals("productId",String.join(",", response)); + Assertions.assertEquals("productId", String.join(",", response)); } @Test - void getInstitutionUserProductsV2EmptyList1() { + void getInstitutionUserProductsV2EmptyList1() { String institutionId = "institutionId"; String userId = "userId"; @@ -308,7 +308,7 @@ void createPgInstitution() { response.setId(institutionId); when(institutionApiClient._createPgInstitutionUsingPOST(any())).thenReturn(ResponseEntity.of(Optional.of(response))); //when - String institutionPnPgResponse = msCoreConnector.createPgInstitution("description", "taxId"); + String institutionPnPgResponse = msCoreConnector.createPgInstitution("description", "taxId"); //then assertEquals(institutionId, institutionPnPgResponse); @@ -339,4 +339,19 @@ void getInstitutionsDetailsBillingNull() throws IOException { verify(institutionApiClient, times(1))._retrieveInstitutionByIdUsingGET(institutionId); } + + @Test + void getInstitution_happyPath() { + String institutionId = "institutionId"; + InstitutionResponse institutionResponse = new InstitutionResponse(); + institutionResponse.setId(institutionId); + when(institutionApiClient._retrieveInstitutionByIdUsingGET(institutionId)).thenReturn(ResponseEntity.ok(institutionResponse)); + when(institutionMapper.toInstitution(any(InstitutionResponse.class))).thenReturn(new Institution()); + + Institution result = msCoreConnector.getInstitution(institutionId); + + assertNotNull(result); + verify(institutionApiClient, times(1))._retrieveInstitutionByIdUsingGET(institutionId); + verify(institutionMapper, times(1)).toInstitution(any(InstitutionResponse.class)); + } } diff --git a/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/UserMsConnectorImplTest.java b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/UserMsConnectorImplTest.java index 21b23549..2c884dbf 100644 --- a/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/UserMsConnectorImplTest.java +++ b/connector/rest/src/test/java/it/pagopa/selfcare/external_api/connector/rest/UserMsConnectorImplTest.java @@ -1,11 +1,11 @@ package it.pagopa.selfcare.external_api.connector.rest; +import it.pagopa.selfcare.external_api.connector.rest.mapper.UserMapperImpl; +import it.pagopa.selfcare.external_api.connector.rest.mapper.UserResourceMapperImpl; import it.pagopa.selfcare.onboarding.common.PartyRole; import com.fasterxml.jackson.core.type.TypeReference; import it.pagopa.selfcare.external_api.connector.rest.client.MsUserApiRestClient; import it.pagopa.selfcare.external_api.connector.rest.config.BaseConnectorTest; -import it.pagopa.selfcare.external_api.connector.rest.mapper.UserMapperImpl; -import it.pagopa.selfcare.external_api.connector.rest.mapper.UserResourceMapperImpl; import it.pagopa.selfcare.external_api.model.institutions.Institution; import it.pagopa.selfcare.external_api.model.user.UserInstitution; import it.pagopa.selfcare.external_api.model.user.UserToOnboard; @@ -85,7 +85,7 @@ void getUserInstitution() throws IOException { } @Test - public void searchUserByExternalId_returnsUser() { + void searchUserByExternalId_returnsUser() { String fiscalCode = "fiscalCode"; SearchUserDto searchUserDto = new SearchUserDto(fiscalCode); @@ -103,7 +103,7 @@ public void searchUserByExternalId_returnsUser() { } @Test - public void searchUserByExternalId_returnsNull_whenUserDoesNotExist() { + void searchUserByExternalId_returnsNull_whenUserDoesNotExist() { String fiscalCode = "fiscalCode"; SearchUserDto searchUserDto = new SearchUserDto(fiscalCode); diff --git a/core/src/main/java/it/pagopa/selfcare/external_api/core/UserService.java b/core/src/main/java/it/pagopa/selfcare/external_api/core/UserService.java index b68d0f44..c1f4e6a2 100644 --- a/core/src/main/java/it/pagopa/selfcare/external_api/core/UserService.java +++ b/core/src/main/java/it/pagopa/selfcare/external_api/core/UserService.java @@ -1,6 +1,7 @@ package it.pagopa.selfcare.external_api.core; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; +import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResource; import it.pagopa.selfcare.external_api.model.user.RelationshipState; import it.pagopa.selfcare.external_api.model.user.UserDetailsWrapper; import it.pagopa.selfcare.external_api.model.user.UserInfoWrapper; @@ -18,7 +19,7 @@ public interface UserService { UserDetailsWrapper getUserOnboardedProductsDetailsV2(String userId, String institutionId, String productId); - List getOnboardedInstitutionsDetailsActive(String userId, String productId); + List getOnboardedInstitutionsDetailsActive(String userId, String productId); List getUsersInstitutions(String userId, String institutionId, Integer page, Integer size, List productRoles, List products, List roles, List states); } diff --git a/core/src/main/java/it/pagopa/selfcare/external_api/core/UserServiceImpl.java b/core/src/main/java/it/pagopa/selfcare/external_api/core/UserServiceImpl.java index 6ced0939..3d22e47a 100644 --- a/core/src/main/java/it/pagopa/selfcare/external_api/core/UserServiceImpl.java +++ b/core/src/main/java/it/pagopa/selfcare/external_api/core/UserServiceImpl.java @@ -2,7 +2,10 @@ import it.pagopa.selfcare.external_api.api.MsCoreConnector; import it.pagopa.selfcare.external_api.api.UserMsConnector; +import it.pagopa.selfcare.external_api.model.institutions.Institution; +import it.pagopa.selfcare.external_api.model.onboarding.Billing; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; +import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResource; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResponse; import it.pagopa.selfcare.external_api.model.onboarding.mapper.OnboardingInstitutionMapper; import it.pagopa.selfcare.external_api.model.user.*; @@ -10,11 +13,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.time.ZoneId; import java.util.*; import java.util.stream.Stream; +import static it.pagopa.selfcare.external_api.model.product.ProductOnboardingStatus.ACTIVE; + @Service @Slf4j public class UserServiceImpl implements UserService { @@ -136,39 +142,51 @@ public List getOnboardedInstitutionsDetails(String use } @Override - public List getOnboardedInstitutionsDetailsActive(String userId, String productId) { - List institutionsWithProductActive = userMsConnector.getUsersInstitutions(userId, null, null, null, null, Objects.isNull(productId) ? null : List.of(productId), null, null) + public List getOnboardedInstitutionsDetailsActive(String userId, String productId) { + List institutionsWithProductActive = userMsConnector.getUsersInstitutions(userId, null, null, null, null, Objects.isNull(productId) ? null : List.of(productId), null, List.of(ACTIVE.name())) .stream() .filter(item -> Objects.nonNull(item.getProducts())) - .filter(item -> item.getProducts().stream() - .filter(product -> Objects.nonNull(product.getProductId())) - .anyMatch(product -> product.getProductId().equals(productId) && RelationshipState.ACTIVE.name().equals(product.getStatus()))) - .peek(item -> item.setProducts(item.getProducts().stream() - .filter(product -> product.getProductId().equals(productId) && RelationshipState.ACTIVE.name().equals(product.getStatus())) - .toList())) .toList(); - List onboardedInstitutionsInfo = new ArrayList<>(); + return institutionsWithProductActive.stream() + .map(userInstitution -> { + Institution institution = msCoreConnector.getInstitution(userInstitution.getInstitutionId()); + OnboardedInstitutionResource onboardedInstitutionResource = null; + if(Objects.nonNull(institution) && checkInstitutionOnboardingStatus(institution, productId)) { + onboardedInstitutionResource = onboardingInstitutionMapper.toOnboardedInstitutionResource(institution, userInstitution, productId); + retrieveBilling(institution, productId, onboardedInstitutionResource); + } + return onboardedInstitutionResource; + }) + .filter(Objects::nonNull) + .toList(); + } - institutionsWithProductActive - .forEach(institution -> { - List institutionOnboardings = msCoreConnector.getInstitutionDetails(institution.getInstitutionId()); - onboardedInstitutionsInfo.addAll(institutionOnboardings.stream() - .filter(onboardedInstitution -> RelationshipState.ACTIVE.name().equals(onboardedInstitution.getState())) - .filter(onboardedInstitutionInfo -> institution.getProducts().stream() - .anyMatch(product -> product.getProductId().equals(onboardedInstitutionInfo.getProductInfo().getId())) - ) - .peek(onboardedInstitution -> { - onboardedInstitution.getProductInfo().setRole(institution.getProducts().stream() - .filter(product -> product.getProductId().equals(onboardedInstitution.getProductInfo().getId()) && - product.getStatus().equals(onboardedInstitution.getProductInfo().getStatus())) - .map(OnboardedProductResponse::getProductRole).findFirst().orElse(null)); - onboardedInstitution.setUserMailUuid(institution.getUserMailUuid()); - }) - .toList()); - }); + private boolean checkInstitutionOnboardingStatus(Institution institution, String productId) { + return institution.getOnboarding().stream() + .anyMatch(onboarding -> productId.equalsIgnoreCase(onboarding.getProductId()) + && RelationshipState.ACTIVE.equals(onboarding.getStatus())); + } - return onboardedInstitutionsInfo; + private void retrieveBilling(Institution institution, String productId, OnboardedInstitutionResource onboardedInstitutionResource){ + List billingList = new ArrayList<>(); + + institution.getOnboarding().forEach(onboarding -> { + if (productId.equalsIgnoreCase(onboarding.getProductId())) { + if (Objects.nonNull(onboarding.getBilling())) { + billingList.add(onboarding.getBilling()); + } else if (Objects.nonNull(institution.getBilling())) { + billingList.add(institution.getBilling()); + } + } + }); + + Billing billing = billingList.stream().findFirst().orElse(null); + + if (Objects.nonNull(billing)) { + onboardedInstitutionResource.setTaxCodeInvoicing(billing.getTaxCodeInvoicing()); + onboardedInstitutionResource.setRecipientCode(billing.getRecipientCode()); + } } @Override diff --git a/core/src/test/java/it/pagopa/selfcare/external_api/core/UserServiceImplTest.java b/core/src/test/java/it/pagopa/selfcare/external_api/core/UserServiceImplTest.java index 2db76e40..059afa6a 100644 --- a/core/src/test/java/it/pagopa/selfcare/external_api/core/UserServiceImplTest.java +++ b/core/src/test/java/it/pagopa/selfcare/external_api/core/UserServiceImplTest.java @@ -3,8 +3,11 @@ import com.fasterxml.jackson.core.type.TypeReference; import it.pagopa.selfcare.external_api.api.MsCoreConnector; import it.pagopa.selfcare.external_api.api.UserMsConnector; +import it.pagopa.selfcare.external_api.model.institutions.Institution; +import it.pagopa.selfcare.external_api.model.institutions.Onboarding; +import it.pagopa.selfcare.external_api.model.onboarding.Billing; import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; -import it.pagopa.selfcare.external_api.model.onboarding.ProductInfo; +import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResource; import it.pagopa.selfcare.external_api.model.onboarding.mapper.OnboardingInstitutionMapperImpl; import it.pagopa.selfcare.external_api.model.user.*; import org.junit.jupiter.api.Assertions; @@ -21,6 +24,8 @@ import java.nio.file.Files; import java.util.List; +import static it.pagopa.selfcare.external_api.model.user.RelationshipState.ACTIVE; +import static it.pagopa.selfcare.external_api.model.user.RelationshipState.SUSPENDED; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -37,7 +42,7 @@ class UserServiceImplTest extends BaseServiceTestUtils { private OnboardingInstitutionMapperImpl onboardingInstitutionMapper; @BeforeEach - public void setUp() { + public void init() { super.setUp(); } @@ -103,26 +108,57 @@ void getOnboardedInstitutionDetailsActiveEmptyList() throws Exception { ClassPathResource resource = new ClassPathResource("expectations/UserInstitution.json"); byte[] resourceStream = Files.readAllBytes(resource.getFile().toPath()); List userInstitutions = objectMapper.readValue(resourceStream, new TypeReference<>() {}); - Mockito.when(userMsConnectorMock.getUsersInstitutions(userId, null, null, null, null, List.of(productId), null, null)).thenReturn(userInstitutions); - - OnboardedInstitutionInfo onboardedInstitutionActive = new OnboardedInstitutionInfo(); - onboardedInstitutionActive.setState(RelationshipState.SUSPENDED.name()); - ProductInfo productInfoActive = new ProductInfo(); - productInfoActive.setId(productId); - productInfoActive.setStatus(RelationshipState.SUSPENDED.name()); - onboardedInstitutionActive.setProductInfo(productInfoActive); - OnboardedInstitutionInfo onboardedInstitutionDeleted = new OnboardedInstitutionInfo(); - ProductInfo productInfoDeleted = new ProductInfo(); - productInfoDeleted.setId(productIdDeleted); - productInfoDeleted.setStatus(RelationshipState.SUSPENDED.name()); - onboardedInstitutionDeleted.setProductInfo(productInfoDeleted); - Mockito.when(msCoreConnectorMock.getInstitutionDetails(institutionId)).thenReturn(List.of(onboardedInstitutionActive, onboardedInstitutionDeleted)); - - List result = userService.getOnboardedInstitutionsDetailsActive(userId, productId); + Mockito.when(userMsConnectorMock.getUsersInstitutions(userId, null, null, null, null, List.of(productId), null, List.of(ACTIVE.name()))) + .thenReturn(userInstitutions); + + Onboarding onboardedInstitutionActive = new Onboarding(); + onboardedInstitutionActive.setStatus(SUSPENDED); + onboardedInstitutionActive.setProductId(productId); + Onboarding onboardedInstitutionDeleted = new Onboarding(); + onboardedInstitutionDeleted.setProductId(productIdDeleted); + onboardedInstitutionDeleted.setStatus(RelationshipState.SUSPENDED); + Institution institution = new Institution(); + institution.setId(institutionId); + institution.setOnboarding(List.of(onboardedInstitutionActive, onboardedInstitutionDeleted)); + Mockito.when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution); + + List result = userService.getOnboardedInstitutionsDetailsActive(userId, productId); Assertions.assertNotNull(result); Assertions.assertTrue(result.isEmpty()); } + @Test + void getOnboardedInstitutionDetailsActive2() throws Exception { + String userId = "123e4567-e89b-12d3-a456-426614174000"; + String institutionId = "123e4567-e89b-12d3-a456-426614174000"; + String productId = "product1"; + String productIdDeleted = "prod-deleted"; + ClassPathResource resource = new ClassPathResource("expectations/UserInstitution.json"); + byte[] resourceStream = Files.readAllBytes(resource.getFile().toPath()); + List userInstitutions = objectMapper.readValue(resourceStream, new TypeReference<>() {}); + Onboarding onboardedInstitutionActive = new Onboarding(); + onboardedInstitutionActive.setStatus(ACTIVE); + onboardedInstitutionActive.setProductId(productId); + Onboarding onboardedInstitutionDeleted = new Onboarding(); + onboardedInstitutionDeleted.setProductId(productIdDeleted); + onboardedInstitutionDeleted.setStatus(RelationshipState.SUSPENDED); + Institution institution = new Institution(); + institution.setId(institutionId); + Billing billing = new Billing(); + billing.setRecipientCode("recipientCode"); + billing.setTaxCodeInvoicing("taxCodeInvoicing"); + onboardedInstitutionActive.setBilling(billing); + institution.setOnboarding(List.of(onboardedInstitutionActive, onboardedInstitutionDeleted)); + Mockito.when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution); + + Mockito.when(userMsConnectorMock.getUsersInstitutions(userId, null, null, null, null, List.of(productId), null, List.of(ACTIVE.name()))).thenReturn(userInstitutions); + Mockito.when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution); + List result = userService.getOnboardedInstitutionsDetailsActive(userId, productId); + Assertions.assertNotNull(result); + Assertions.assertFalse(result.isEmpty()); + Assertions.assertEquals(1, result.size()); + } + @Test void getOnboardedInstitutionDetailsActive() throws Exception { String userId = "123e4567-e89b-12d3-a456-426614174000"; @@ -132,25 +168,31 @@ void getOnboardedInstitutionDetailsActive() throws Exception { ClassPathResource resource = new ClassPathResource("expectations/UserInstitution.json"); byte[] resourceStream = Files.readAllBytes(resource.getFile().toPath()); List userInstitutions = objectMapper.readValue(resourceStream, new TypeReference<>() {}); - OnboardedInstitutionInfo onboardedInstitutionActive = new OnboardedInstitutionInfo(); - onboardedInstitutionActive.setState(RelationshipState.ACTIVE.name()); - ProductInfo productInfoActive = new ProductInfo(); - productInfoActive.setId(productId); - productInfoActive.setStatus(RelationshipState.ACTIVE.name()); - onboardedInstitutionActive.setProductInfo(productInfoActive); - OnboardedInstitutionInfo onboardedInstitutionDeleted = new OnboardedInstitutionInfo(); - ProductInfo productInfoDeleted = new ProductInfo(); - productInfoDeleted.setId(productIdDeleted); - productInfoDeleted.setStatus(RelationshipState.ACTIVE.name()); - onboardedInstitutionDeleted.setProductInfo(productInfoDeleted); - Mockito.when(userMsConnectorMock.getUsersInstitutions(userId, null, null, null, null, List.of(productId), null, null)).thenReturn(userInstitutions); - Mockito.when(msCoreConnectorMock.getInstitutionDetails(institutionId)).thenReturn(List.of(onboardedInstitutionActive, onboardedInstitutionDeleted)); - List result = userService.getOnboardedInstitutionsDetailsActive(userId, productId); + Onboarding onboardedInstitutionActive = new Onboarding(); + onboardedInstitutionActive.setStatus(ACTIVE); + onboardedInstitutionActive.setProductId(productId); + Onboarding onboardedInstitutionDeleted = new Onboarding(); + onboardedInstitutionDeleted.setProductId(productIdDeleted); + onboardedInstitutionDeleted.setStatus(RelationshipState.SUSPENDED); + Institution institution = new Institution(); + institution.setId(institutionId); + Billing billing = new Billing(); + billing.setRecipientCode("recipientCode"); + billing.setTaxCodeInvoicing("taxCodeInvoicing"); + institution.setBilling(billing); + institution.setOnboarding(List.of(onboardedInstitutionActive, onboardedInstitutionDeleted)); + Mockito.when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution); + + Mockito.when(userMsConnectorMock.getUsersInstitutions(userId, null, null, null, null, List.of(productId), null, List.of(ACTIVE.name()))).thenReturn(userInstitutions); + Mockito.when(msCoreConnectorMock.getInstitution(institutionId)).thenReturn(institution); + List result = userService.getOnboardedInstitutionsDetailsActive(userId, productId); Assertions.assertNotNull(result); Assertions.assertFalse(result.isEmpty()); Assertions.assertEquals(1, result.size()); } + + @Test void getUserInfoV2WithEmptyOnboardedInstitutions() throws Exception { String taxCode = "MNCCSD01R13A757G"; @@ -171,7 +213,7 @@ void getUserInfoV2WithEmptyOnboardedInstitutions() throws Exception { Mockito.when(userMsConnectorMock.getUsersInstitutions(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(userInstitution); Mockito.when(msCoreConnectorMock.getInstitutionDetails(any())).thenReturn(List.of(onboardedInstitutionInfo)); - UserInfoWrapper userInfoWrapper = userService.getUserInfoV2(taxCode, List.of(RelationshipState.ACTIVE)); + UserInfoWrapper userInfoWrapper = userService.getUserInfoV2(taxCode, List.of(ACTIVE)); Assertions.assertNotNull(userInfoWrapper); Assertions.assertNotNull(userInfoWrapper.getUser()); @@ -200,7 +242,7 @@ void getUserInfoV2WithValidOnboardedInstitutions() throws Exception { Mockito.when(userMsConnectorMock.getUsersInstitutions(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(userInstitution); Mockito.when(msCoreConnectorMock.getInstitutionDetails(any())).thenReturn(List.of(onboardedInstitutionInfo)); - UserInfoWrapper userInfoWrapper = userService.getUserInfoV2(taxCode, List.of(RelationshipState.ACTIVE)); + UserInfoWrapper userInfoWrapper = userService.getUserInfoV2(taxCode, List.of(ACTIVE)); ClassPathResource userInfoWrapperResource = new ClassPathResource("expectations/UserInfoWrapperV2.json"); byte[] userInfoWrapperStream = Files.readAllBytes(userInfoWrapperResource.getFile().toPath()); diff --git a/web/src/main/java/it/pagopa/selfcare/external_api/web/controller/InstitutionV2Controller.java b/web/src/main/java/it/pagopa/selfcare/external_api/web/controller/InstitutionV2Controller.java index fba2b600..53325fff 100644 --- a/web/src/main/java/it/pagopa/selfcare/external_api/web/controller/InstitutionV2Controller.java +++ b/web/src/main/java/it/pagopa/selfcare/external_api/web/controller/InstitutionV2Controller.java @@ -4,13 +4,11 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.tags.Tags; import it.pagopa.selfcare.commons.base.security.SelfCareUser; import it.pagopa.selfcare.external_api.core.ContractService; import it.pagopa.selfcare.external_api.core.InstitutionService; import it.pagopa.selfcare.external_api.core.UserService; import it.pagopa.selfcare.external_api.model.documents.ResourceResponse; -import it.pagopa.selfcare.external_api.model.user.RelationshipState; import it.pagopa.selfcare.external_api.model.user.UserInfo; import it.pagopa.selfcare.external_api.web.model.institutions.InstitutionResource; import it.pagopa.selfcare.external_api.web.model.mapper.InstitutionResourceMapper; @@ -23,15 +21,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; -import java.util.*; -import java.util.stream.Collectors; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; -import static java.util.Comparator.comparing; -import static java.util.stream.Collectors.toCollection; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; @@ -71,9 +67,7 @@ public List getInstitutions(@ApiParam("${swagger.external_a List institutionResources = userService.getOnboardedInstitutionsDetailsActive(user.getId(), productId) .stream() .map(institutionResourceMapper::toResource) - .filter(item -> RelationshipState.ACTIVE.name().equals(item.getStatus())) - .collect(Collectors.collectingAndThen(toCollection(() -> new TreeSet<>(comparing(InstitutionResource::getId))), - ArrayList::new)); + .toList(); log.debug("getInstitutions result = {}", institutionResources); log.trace("getInstitutions end"); return institutionResources; diff --git a/web/src/main/java/it/pagopa/selfcare/external_api/web/model/mapper/InstitutionResourceMapper.java b/web/src/main/java/it/pagopa/selfcare/external_api/web/model/mapper/InstitutionResourceMapper.java index e49cf297..ad399058 100644 --- a/web/src/main/java/it/pagopa/selfcare/external_api/web/model/mapper/InstitutionResourceMapper.java +++ b/web/src/main/java/it/pagopa/selfcare/external_api/web/model/mapper/InstitutionResourceMapper.java @@ -1,10 +1,7 @@ package it.pagopa.selfcare.external_api.web.model.mapper; import it.pagopa.selfcare.external_api.model.institutions.*; -import it.pagopa.selfcare.external_api.model.onboarding.DataProtectionOfficer; -import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; -import it.pagopa.selfcare.external_api.model.onboarding.PaymentServiceProvider; -import it.pagopa.selfcare.external_api.model.onboarding.ProductInfo; +import it.pagopa.selfcare.external_api.model.onboarding.*; import it.pagopa.selfcare.external_api.web.model.institutions.InstitutionResource; import it.pagopa.selfcare.external_api.web.model.institutions.*; import org.mapstruct.Mapper; @@ -19,6 +16,7 @@ public interface InstitutionResourceMapper { @Mapping(target = "recipientCode", source = "model.billing.recipientCode") + @Mapping(target = "taxCodeInvoicing", source = "model.billing.taxCodeInvoicing") @Mapping(target = "pspData", source = "model.paymentServiceProvider", qualifiedByName = "toPspDataResource") @Mapping(target = "companyInformations", source = "model.businessData", qualifiedByName = "toCompanyInformationResource") @Mapping(target = "assistanceContacts", source = "model.supportContact", qualifiedByName = "toAssistanceContactsResource") @@ -44,6 +42,16 @@ public interface InstitutionResourceMapper { @Mapping(target = "userProductRoles", source = "productInfo", qualifiedByName = "toUserProductRoles") InstitutionResource toResource(OnboardedInstitutionInfo model); + @Mapping(target = "pspData", source = "paymentServiceProvider", qualifiedByName = "toPspDataResource") + @Mapping(target = "companyInformations.rea", source = "rea") + @Mapping(target = "companyInformations.shareCapital", source = "shareCapital") + @Mapping(target = "companyInformations.businessRegisterPlace", source = "businessRegisterPlace") + @Mapping(target = "assistanceContacts.supportPhone", source = "supportPhone") + @Mapping(target = "assistanceContacts.supportEmail", source = "supportEmail") + @Mapping(target = "dpoData", source = "dataProtectionOfficer", qualifiedByName = "toDpoDataResource") + @Mapping(target = "rootParent", source = "rootParent", qualifiedByName = "toRootParentResource") + InstitutionResource toResource(OnboardedInstitutionResource model); + @Named("toUserProductRoles") static Collection toUserProductRoles(ProductInfo productInfo) { Set productRole = new HashSet<>(); diff --git a/web/src/test/java/it/pagopa/selfcare/external_api/web/controller/InstitutionControllerV2Test.java b/web/src/test/java/it/pagopa/selfcare/external_api/web/controller/InstitutionControllerV2Test.java index 8b393834..ef22de54 100644 --- a/web/src/test/java/it/pagopa/selfcare/external_api/web/controller/InstitutionControllerV2Test.java +++ b/web/src/test/java/it/pagopa/selfcare/external_api/web/controller/InstitutionControllerV2Test.java @@ -6,7 +6,7 @@ import it.pagopa.selfcare.external_api.core.InstitutionService; import it.pagopa.selfcare.external_api.core.UserService; import it.pagopa.selfcare.external_api.model.documents.ResourceResponse; -import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionInfo; +import it.pagopa.selfcare.external_api.model.onboarding.OnboardedInstitutionResource; import it.pagopa.selfcare.external_api.model.user.UserInfo; import it.pagopa.selfcare.external_api.web.model.mapper.InstitutionResourceMapperImpl; import it.pagopa.selfcare.external_api.web.model.mapper.ProductsMapper; @@ -68,8 +68,8 @@ void getInstitutionsWith2Elements() throws Exception { ClassPathResource inputResource = new ClassPathResource("expectations/OnboardedInstitutionInfo.json"); byte[] institutionInfoStream = Files.readAllBytes(inputResource.getFile().toPath()); - List onboardedInstitutionInfos = objectMapper.readValue(institutionInfoStream, new TypeReference<>() {}); - onboardedInstitutionInfos.forEach(onboardedInstitutionInfo -> onboardedInstitutionInfo.setState("ACTIVE")); + List onboardedInstitutionInfos = objectMapper.readValue(institutionInfoStream, new TypeReference<>() {}); + onboardedInstitutionInfos.forEach(onboardedInstitutionInfo -> onboardedInstitutionInfo.setStatus("ACTIVE")); ClassPathResource outputResource = new ClassPathResource("expectations/InstitutionResourceV2_2elements.json"); String expectedResource = StringUtils.deleteWhitespace(new String(Files.readAllBytes(outputResource.getFile().toPath()))); @@ -105,7 +105,8 @@ void getInstitutionsWith1Elements() throws Exception { ClassPathResource inputResource = new ClassPathResource("expectations/OnboardedInstitutionInfo.json"); byte[] institutionInfoStream = Files.readAllBytes(inputResource.getFile().toPath()); - List onboardedInstitutionInfos = objectMapper.readValue(institutionInfoStream, new TypeReference<>() {}); + List onboardedInstitutionInfos = objectMapper.readValue(institutionInfoStream, new TypeReference<>() {}); + onboardedInstitutionInfos.remove(1); ClassPathResource outputResource = new ClassPathResource("expectations/InstitutionResourceV2_1element.json"); String expectedResource = StringUtils.deleteWhitespace(new String(Files.readAllBytes(outputResource.getFile().toPath()))); diff --git a/web/src/test/resources/expectations/InstitutionResourceV2_1element.json b/web/src/test/resources/expectations/InstitutionResourceV2_1element.json index 603061c8..b1a2558d 100644 --- a/web/src/test/resources/expectations/InstitutionResourceV2_1element.json +++ b/web/src/test/resources/expectations/InstitutionResourceV2_1element.json @@ -13,7 +13,7 @@ "taxCodeInvoicing": "example_tax_code_invoicing", "origin":"example_origin", "userProductRoles":[ - "role1" + "admin","manager" ], "recipientCode":"example_recipient_code", "companyInformations":{ diff --git a/web/src/test/resources/expectations/InstitutionResourceV2_2elements.json b/web/src/test/resources/expectations/InstitutionResourceV2_2elements.json index 778933c7..5ecd93c6 100644 --- a/web/src/test/resources/expectations/InstitutionResourceV2_2elements.json +++ b/web/src/test/resources/expectations/InstitutionResourceV2_2elements.json @@ -13,7 +13,7 @@ "taxCodeInvoicing": "example_tax_code_invoicing", "origin":"example_origin", "userProductRoles":[ - "role1" + "admin","manager" ], "recipientCode":"example_recipient_code", "companyInformations":{ @@ -62,7 +62,7 @@ "taxCodeInvoicing": "example_tax_code_invoicing", "origin":"example_origin", "userProductRoles":[ - "role1" + "admin" ], "recipientCode":"example_recipient_code", "companyInformations":{ diff --git a/web/src/test/resources/expectations/OnboardedInstitutionInfo.json b/web/src/test/resources/expectations/OnboardedInstitutionInfo.json index f7925715..abaf0d72 100644 --- a/web/src/test/resources/expectations/OnboardedInstitutionInfo.json +++ b/web/src/test/resources/expectations/OnboardedInstitutionInfo.json @@ -10,25 +10,16 @@ "address": "example_address", "zipCode": "example_zip_code", "taxCode": "example_tax_code", - "pricingPlan": "piano_tariffario", - "billing": { - "vatNumber": "numero_iva", - "recipientCode": "example_recipient_code", - "taxCodeInvoicing": "example_tax_code_invoicing", - "publicServices": true - }, - "state": "ACTIVE", - "role": "MANAGER", - "productInfo": { - "id": "prod123", - "role": "role1", - "createdAt": "2023-01-01T00:00:00+00:00", - "status": "example_status" - }, + "recipientCode": "example_recipient_code", + "taxCodeInvoicing": "example_tax_code_invoicing", + "status": "ACTIVE", + "userProductRoles": [ + "admin", + "manager" + ], "subunitCode": "example_subunit_code", "subunitType": "example_subunit_type", "aooParentCode": "example_aoo_parent_code", - "userMailUuid": "uuid_mail_utente", "city": "example_city", "country": "example_country", "county": "example_county", @@ -65,25 +56,15 @@ "address": "example_address", "zipCode": "example_zip_code", "taxCode": "example_tax_code", - "pricingPlan": "piano_tariffario", - "billing": { - "vatNumber": "numero_iva", - "recipientCode": "example_recipient_code", - "taxCodeInvoicing": "example_tax_code_invoicing", - "publicServices": true - }, - "state": "DELETED", - "role": "MANAGER", - "productInfo": { - "id": "prod123", - "role": "role1", - "createdAt": "2023-01-01T00:00:00+00:00", - "status": "example_status" - }, + "recipientCode": "example_recipient_code", + "taxCodeInvoicing": "example_tax_code_invoicing", + "status": "DELETED", + "userProductRoles": [ + "admin" + ], "subunitCode": "example_subunit_code", "subunitType": "example_subunit_type", "aooParentCode": "example_aoo_parent_code", - "userMailUuid": "uuid_mail_utente", "city": "example_city", "country": "example_country", "county": "example_county",