diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/BaseRegistryManager.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/BaseRegistryManager.java index a7d73c5b3..55a6987c0 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/BaseRegistryManager.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/BaseRegistryManager.java @@ -1,9 +1,14 @@ package it.pagopa.selfcare.onboarding.entity.registry; +import io.smallrye.mutiny.Uni; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.entity.User; +import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; +import it.pagopa.selfcare.product.entity.Product; + +import java.util.Objects; public abstract class BaseRegistryManager implements RegistryManager { @@ -15,6 +20,7 @@ public abstract class BaseRegistryManager implements RegistryManager { protected static final String TAX_CODE_INVOICING_IS_INVALID = "The tax code invoicing of the request does not match any tax code of institutions' hierarchy"; protected static final String PNPG_INSTITUTION_REGISTRY_NOT_FOUND = "Institution with taxCode %s is not into registry"; protected static final String NOT_ALLOWED_PRICING_PLAN = "onboarding pricing plan for io-premium is not allowed"; + protected static final String NOT_ALLOWED_INSTITUTION_TYPE = "institution with institution type %s is not allowed to onboard product %s"; protected static final int DURATION_TIMEOUT = 5; protected static final int MAX_NUMBER_ATTEMPTS = 2; @@ -38,6 +44,20 @@ public RegistryManager setResource(T registryResource) { return this; } + public Uni validateInstitutionType(Product product) { + if (Objects.nonNull(product.getInstitutionTypesAllowed()) && !product.getInstitutionTypesAllowed().isEmpty()) { + return product.getInstitutionTypesAllowed().stream() + .anyMatch(type -> type.equals(onboarding.getInstitution().getInstitutionType().name())) + ? Uni.createFrom().item(onboarding) + : Uni.createFrom().failure(new InvalidRequestException( + String.format(NOT_ALLOWED_INSTITUTION_TYPE, + onboarding.getInstitution().getInstitutionType().name(), + product.getId()) + )); + } + return Uni.createFrom().item(onboarding); + } + protected String getManagerIdFromOnboarding() { return onboarding.getUsers().stream() .filter(user -> user.getRole().equals(PartyRole.MANAGER)) diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManager.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManager.java index a5a08085a..9a8cb0eae 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManager.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManager.java @@ -17,5 +17,7 @@ public interface RegistryManager { Onboarding getOnboarding(); RegistryManager setResource(T registryResource); + + Uni validateInstitutionType(Product product); } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java index 691b8c153..9f3748265 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java @@ -266,15 +266,15 @@ public Uni onboardingAggregationCompletion( @Override public Uni onboardingAggregationImport( - Onboarding onboarding, - OnboardingImportContract contractImported, - List userRequests, - List aggregates) { + Onboarding onboarding, + OnboardingImportContract contractImported, + List userRequests, + List aggregates) { onboarding.setWorkflowType(WorkflowType.IMPORT_AGGREGATION); onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( - onboarding, userRequests, aggregates, contractImported); + onboarding, userRequests, aggregates, contractImported); } @@ -283,13 +283,13 @@ public Uni onboardingAggregationImport( */ @Override public Uni onboardingImport( - Onboarding onboarding, - List userRequests, - OnboardingImportContract contractImported) { + Onboarding onboarding, + List userRequests, + OnboardingImportContract contractImported) { onboarding.setWorkflowType(WorkflowType.IMPORT); onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( - onboarding, userRequests, null, contractImported); + onboarding, userRequests, null, contractImported); } /** @@ -360,6 +360,8 @@ private Uni validateAndPersistOnboarding( String timeout) { return registryManager.isValid() + .onItem() + .transformToUni(ignored -> registryManager.validateInstitutionType(product)) .onItem() .transformToUni(ignored -> registryManager.customValidation(product)) .onItem() @@ -426,7 +428,6 @@ private Uni verifyExistingOnboarding( } /** - * * @param onboarding * @param userRequests * @param aggregateRequests @@ -434,61 +435,61 @@ private Uni verifyExistingOnboarding( * @return OnboardingResponse */ private Uni fillUsersAndOnboardingForImport( - Onboarding onboarding, - List userRequests, - List aggregateRequests, - OnboardingImportContract contractImported) { + Onboarding onboarding, + List userRequests, + List aggregateRequests, + OnboardingImportContract contractImported) { onboarding.setCreatedAt(LocalDateTime.now()); return getProductByOnboarding(onboarding) - .onItem() - .transformToUni( - product -> - verifyAlreadyOnboardingForProductAndProductParent( - onboarding.getInstitution(), product.getId(), product.getParentId()) - .replaceWith(product)) - .onItem() - .transformToUni( - product -> - Uni.createFrom() - .item(registryResourceFactory.create(onboarding, getManagerTaxCode(userRequests))) - .onItem() - .invoke( - registryManager -> - registryManager.setResource(registryManager.retrieveInstitution())) - .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()) - .onItem() - .transformToUni( - registryManager -> - registryManager - .isValid() - .onItem() - .transformToUni( - ignored -> registryManager.customValidation(product))) - /* if product has some test environments, request must also onboard them (for ex. prod-interop-coll) */ - .onItem() - .invoke(() -> onboarding.setTestEnvProductIds(product.getTestEnvProductIds())) - .onItem() - .transformToUni( - current -> persistOnboarding(onboarding, userRequests, product, aggregateRequests)) - .onItem() - .call( - onboardingPersisted -> - Panache.withTransaction( - () -> - Token.persist( - getToken(onboardingPersisted, product, contractImported)))) - /* Update onboarding data with users and start orchestration */ - .onItem() - .transformToUni( - currentOnboarding -> - persistAndStartOrchestrationOnboarding( - currentOnboarding, - orchestrationApi.apiStartOnboardingOrchestrationGet( - currentOnboarding.getId(), TIMEOUT_ORCHESTRATION_RESPONSE))) - .onItem() - .transform(onboardingMapper::toResponse)); + .onItem() + .transformToUni( + product -> + verifyAlreadyOnboardingForProductAndProductParent( + onboarding.getInstitution(), product.getId(), product.getParentId()) + .replaceWith(product)) + .onItem() + .transformToUni( + product -> + Uni.createFrom() + .item(registryResourceFactory.create(onboarding, getManagerTaxCode(userRequests))) + .onItem() + .invoke( + registryManager -> + registryManager.setResource(registryManager.retrieveInstitution())) + .runSubscriptionOn(Infrastructure.getDefaultWorkerPool()) + .onItem() + .transformToUni( + registryManager -> + registryManager + .isValid() + .onItem() + .transformToUni( + ignored -> registryManager.customValidation(product))) + /* if product has some test environments, request must also onboard them (for ex. prod-interop-coll) */ + .onItem() + .invoke(() -> onboarding.setTestEnvProductIds(product.getTestEnvProductIds())) + .onItem() + .transformToUni( + current -> persistOnboarding(onboarding, userRequests, product, aggregateRequests)) + .onItem() + .call( + onboardingPersisted -> + Panache.withTransaction( + () -> + Token.persist( + getToken(onboardingPersisted, product, contractImported)))) + /* Update onboarding data with users and start orchestration */ + .onItem() + .transformToUni( + currentOnboarding -> + persistAndStartOrchestrationOnboarding( + currentOnboarding, + orchestrationApi.apiStartOnboardingOrchestrationGet( + currentOnboarding.getId(), TIMEOUT_ORCHESTRATION_RESPONSE))) + .onItem() + .transform(onboardingMapper::toResponse)); } private Uni persistOnboarding( @@ -1705,70 +1706,70 @@ public Uni checkManager(OnboardingUserRequest onboardingUs .orElseThrow( () -> new InvalidRequestException("At least one user should have role MANAGER")); - return userRegistryApi - .searchUsingPOST(USERS_FIELD_LIST, new UserSearchDto().fiscalCode(taxCodeManager)) - .onItem() - .transform(UserResource::getId) - .flatMap( - uuid -> - findOnboardingsByFilters(onboardingUserRequest) - .flatMap( - onboardings -> { - if (CollectionUtils.isEmpty(onboardings)) { - LOG.debugf( - "Onboarding for taxCode %s, origin %s, originId %s, productId %s, subunitCode %s not found", - onboardingUserRequest.getTaxCode(), - onboardingUserRequest.getOrigin(), - onboardingUserRequest.getOriginId(), - onboardingUserRequest.getProductId(), - onboardingUserRequest.getSubunitCode()); - - response.setResponse(false); - return Uni.createFrom().item(response); - } - - // If the list of onboardings filtered by manager's role is empty, the - // response is 404 - if (onboardings.stream() - .noneMatch( - onboarding -> - onboarding.getUsers().stream() - .map(User::getRole) - .toList() - .contains(PartyRole.MANAGER))) { - return Uni.createFrom() - .failure( - new ResourceNotFoundException( - "No manager found for the data in input")); - } - - String institutionId = onboardings.get(0).getInstitution().getId(); - return isUserActiveManager( - institutionId, - onboardingUserRequest.getProductId(), - String.valueOf(uuid)) - .map( - isActiveManager -> { - LOG.debugf( - "User with uuid %s is active manager: %s", - uuid, isActiveManager); - response.setResponse(isActiveManager); - return response; - }); - })) - .onFailure() - .recoverWithUni( - ex -> { - if (ex instanceof WebApplicationException - && ((WebApplicationException) ex).getResponse().getStatus() == 404) { - LOG.debugf("User not found on user-registry", taxCodeManager); - response.setResponse(false); - return Uni.createFrom().item(response); - } - - // If the exception raised is for a different status code, let it propagate - return Uni.createFrom().failure(ex); - }); + return userRegistryApi + .searchUsingPOST(USERS_FIELD_LIST, new UserSearchDto().fiscalCode(taxCodeManager)) + .onItem() + .transform(UserResource::getId) + .flatMap( + uuid -> + findOnboardingsByFilters(onboardingUserRequest) + .flatMap( + onboardings -> { + if (CollectionUtils.isEmpty(onboardings)) { + LOG.debugf( + "Onboarding for taxCode %s, origin %s, originId %s, productId %s, subunitCode %s not found", + onboardingUserRequest.getTaxCode(), + onboardingUserRequest.getOrigin(), + onboardingUserRequest.getOriginId(), + onboardingUserRequest.getProductId(), + onboardingUserRequest.getSubunitCode()); + + response.setResponse(false); + return Uni.createFrom().item(response); + } + + // If the list of onboardings filtered by manager's role is empty, the + // response is 404 + if (onboardings.stream() + .noneMatch( + onboarding -> + onboarding.getUsers().stream() + .map(User::getRole) + .toList() + .contains(PartyRole.MANAGER))) { + return Uni.createFrom() + .failure( + new ResourceNotFoundException( + "No manager found for the data in input")); + } + + String institutionId = onboardings.get(0).getInstitution().getId(); + return isUserActiveManager( + institutionId, + onboardingUserRequest.getProductId(), + String.valueOf(uuid)) + .map( + isActiveManager -> { + LOG.debugf( + "User with uuid %s is active manager: %s", + uuid, isActiveManager); + response.setResponse(isActiveManager); + return response; + }); + })) + .onFailure() + .recoverWithUni( + ex -> { + if (ex instanceof WebApplicationException + && ((WebApplicationException) ex).getResponse().getStatus() == 404) { + LOG.debugf("User not found on user-registry", taxCodeManager); + response.setResponse(false); + return Uni.createFrom().item(response); + } + + // If the exception raised is for a different status code, let it propagate + return Uni.createFrom().failure(ex); + }); } /** diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java index 2eec7db97..fdec6c989 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefaultTest.java @@ -796,6 +796,48 @@ void onboardingPa_notAllowedPricingPlan(UniAsserter asserter) { asserter.assertFailedWith(() -> onboardingService.onboarding(request, users, null), InvalidRequestException.class); } + @Test + @RunOnVertxContext + void onboarding_notAllowedInstitutionType(UniAsserter asserter) { + Onboarding request = new Onboarding(); + List users = List.of(manager); + request.setProductId(PROD_DASHBOARD_PSP.getValue()); + Institution institutionBaseRequest = new Institution(); + institutionBaseRequest.setInstitutionType(InstitutionType.PA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setDescription("TEST"); + institutionBaseRequest.setDigitalAddress(DIGITAL_ADDRESS_FIELD); + institutionBaseRequest.setOrigin(Origin.IPA); + request.setInstitution(institutionBaseRequest); + request.setPricingPlan("C1"); + Billing billing = new Billing(); + billing.setRecipientCode("recCode"); + request.setBilling(billing); + + mockPersistOnboarding(asserter); + mockVerifyAllowedMap(request.getInstitution().getTaxCode(), request.getProductId(), asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(), any())) + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(); + + UOResource uoResource = new UOResource(); + uoResource.setCodiceFiscaleSfe("codSfe"); + uoResource.setCodiceIpa("originId"); + when(uoApi.findByUnicodeUsingGET1("recCode", null)).thenReturn(Uni.createFrom().item(uoResource)); + + InstitutionResource institutionResource = new InstitutionResource(); + institutionResource.setDescription("TEST"); + institutionResource.setDigitalAddress(DIGITAL_ADDRESS_FIELD); + asserter.execute(() -> when(institutionRegistryProxyApi.findInstitutionUsingGET(institutionBaseRequest.getTaxCode(), null, null)) + .thenReturn(Uni.createFrom().item(institutionResource))); + + asserter.assertFailedWith(() -> onboardingService.onboarding(request, users, null), InvalidRequestException.class); + } + void mockSimpleSearchPOSTAndPersist(UniAsserter asserter) { asserter.execute(() -> PanacheMock.mock(Onboarding.class)); @@ -1236,6 +1278,11 @@ Product createDummyProduct(String productId, boolean hasParent) { productResource.setRoleMappings(Map.of(manager.getRole(), dummyProductRoleInfo(PRODUCT_ROLE_ADMIN_CODE))); productResource.setRoleMappingsByInstitutionType(Map.of(PSP.name(), roleMappingByInstitutionType)); productResource.setTitle("title"); + if (PROD_DASHBOARD_PSP.getValue().equals(productId)) { + List institutionTypeList = new ArrayList<>(); + institutionTypeList.add(PSP.name()); + productResource.setInstitutionTypesAllowed(institutionTypeList); + } if (hasParent) { Product parent = new Product(); @@ -3069,13 +3116,13 @@ void onboardingAggregationImportTest(UniAsserter asserter) { mockVerifyAllowedMap(request.getInstitution().getTaxCode(), request.getProductId(), asserter); asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(), any())) - .thenReturn(Uni.createFrom().item(Response.noContent().build()))); + .thenReturn(Uni.createFrom().item(Response.noContent().build()))); UOResource uoResource = new UOResource(); uoResource.setCodiceIpa("codiceIPA"); uoResource.setCodiceFiscaleSfe("codiceFiscaleSfe"); when(uoApi.findByUnicodeUsingGET1(any(), any())) - .thenReturn(Uni.createFrom().item(uoResource)); + .thenReturn(Uni.createFrom().item(uoResource)); InstitutionResource institutionResource = new InstitutionResource(); institutionResource.setCategory("L37"); @@ -3083,14 +3130,14 @@ void onboardingAggregationImportTest(UniAsserter asserter) { institutionResource.setDigitalAddress(DIGITAL_ADDRESS_FIELD); institutionResource.setIstatCode("istatCode"); asserter.execute(() -> when(institutionRegistryProxyApi.findInstitutionUsingGET(institutionBaseRequest.getTaxCode(), null, null)) - .thenReturn(Uni.createFrom().item(institutionResource))); + .thenReturn(Uni.createFrom().item(institutionResource))); GeographicTaxonomyResource geographicTaxonomyResource = new GeographicTaxonomyResource(); geographicTaxonomyResource.setCountryAbbreviation("IT"); geographicTaxonomyResource.setProvinceAbbreviation("RM"); geographicTaxonomyResource.setDesc("desc"); asserter.execute(() -> when(geographicTaxonomiesApi.retrieveGeoTaxonomiesByCodeUsingGET(any())) - .thenReturn(Uni.createFrom().item(geographicTaxonomyResource))); + .thenReturn(Uni.createFrom().item(geographicTaxonomyResource))); List aggregates = new ArrayList<>(); AggregateInstitutionRequest aggregateInstitutionRequest = new AggregateInstitutionRequest(); @@ -3101,13 +3148,13 @@ void onboardingAggregationImportTest(UniAsserter asserter) { AggregateInstitution aggregateInstitution = new AggregateInstitution(); aggregateInstitution.setTaxCode("taxCode"); aggregateInstitution.setUsers(List.of(User.builder().id("test") - .role(PartyRole.MANAGER) - .build())); + .role(PartyRole.MANAGER) + .build())); request.setAggregates(List.of(aggregateInstitution)); // when asserter.assertThat(() -> onboardingService.onboardingAggregationImport(request, contractImported, users, aggregates), - Assertions::assertNotNull); + Assertions::assertNotNull); // then asserter.execute(() -> {