From 95c2b2675de43a11be670042ecb657a6a2f8ba98 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 15 Jan 2025 15:50:43 +0100 Subject: [PATCH 01/14] Added new endpoint into OnboardingController --- apps/onboarding-ms/src/main/docs/openapi.json | 85 ++++++++++++ apps/onboarding-ms/src/main/docs/openapi.yaml | 62 +++++++++ .../controller/OnboardingController.java | 50 +++++-- .../OnboardingAggregationImportRequest.java | 16 +++ .../onboarding/service/OnboardingService.java | 7 +- .../service/OnboardingServiceDefault.java | 131 ++++++++++-------- 6 files changed, 284 insertions(+), 67 deletions(-) create mode 100644 apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingAggregationImportRequest.java diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index 894114b50..e0378c721 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -449,6 +449,44 @@ } ] } }, + "/v1/onboarding/aggregation/import" : { + "post" : { + "tags" : [ "Onboarding Controller" ], + "summary" : "Asynchronously import aggregated onboarding to COMPLETED status and create token", + "description" : "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase.", + "operationId" : "onboardingAggregationImport", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingAggregationImportRequest" + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/OnboardingResponse" + } + } + } + }, + "401" : { + "description" : "Not Authorized" + }, + "403" : { + "description" : "Not Allowed" + } + }, + "security" : [ { + "SecurityScheme" : [ ] + } ] + } + }, "/v1/onboarding/aggregation/increment" : { "post" : { "tags" : [ "Onboarding Controller" ], @@ -2356,6 +2394,53 @@ "type" : "string", "example" : "2022-03-10T12:15:50" }, + "OnboardingAggregationImportRequest" : { + "required" : [ "productId", "users", "institution" ], + "type" : "object", + "properties" : { + "productId" : { + "minLength" : 1, + "type" : "string" + }, + "users" : { + "minItems" : 1, + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserRequest" + } + }, + "aggregates" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AggregateInstitutionRequest" + } + }, + "isAggregator" : { + "type" : "boolean" + }, + "pricingPlan" : { + "type" : "string" + }, + "signContract" : { + "type" : "boolean" + }, + "institution" : { + "$ref" : "#/components/schemas/InstitutionBaseRequest" + }, + "billing" : { + "$ref" : "#/components/schemas/BillingRequest" + }, + "additionalInformations" : { + "$ref" : "#/components/schemas/AdditionalInformationsDto" + }, + "gpuData" : { + "$ref" : "#/components/schemas/GPUData" + }, + "onboardingImportContract" : { + "$ref" : "#/components/schemas/OnboardingImportContract" + } + } + }, "OnboardingDefaultRequest" : { "required" : [ "productId", "users", "institution" ], "type" : "object", diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index 46679ea32..73e6994ed 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -326,6 +326,33 @@ paths: description: Not Allowed security: - SecurityScheme: [] + /v1/onboarding/aggregation/import: + post: + tags: + - Onboarding Controller + summary: Asynchronously import aggregated onboarding to COMPLETED status and + create token + description: "Perform a manual onboarding with aggregator, create token and\ + \ set onboarding status to COMPLETED phase." + operationId: onboardingAggregationImport + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/OnboardingAggregationImportRequest" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/OnboardingResponse" + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] /v1/onboarding/aggregation/increment: post: tags: @@ -1712,6 +1739,41 @@ components: format: date-time type: string example: 2022-03-10T12:15:50 + OnboardingAggregationImportRequest: + required: + - productId + - users + - institution + type: object + properties: + productId: + minLength: 1 + type: string + users: + minItems: 1 + type: array + items: + $ref: "#/components/schemas/UserRequest" + aggregates: + type: array + items: + $ref: "#/components/schemas/AggregateInstitutionRequest" + isAggregator: + type: boolean + pricingPlan: + type: string + signContract: + type: boolean + institution: + $ref: "#/components/schemas/InstitutionBaseRequest" + billing: + $ref: "#/components/schemas/BillingRequest" + additionalInformations: + $ref: "#/components/schemas/AdditionalInformationsDto" + gpuData: + $ref: "#/components/schemas/GPUData" + onboardingImportContract: + $ref: "#/components/schemas/OnboardingImportContract" OnboardingDefaultRequest: required: - productId diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java index 83fa4ef66..b8055f549 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java @@ -1,5 +1,7 @@ package it.pagopa.selfcare.onboarding.controller; +import static it.pagopa.selfcare.onboarding.util.Utils.retrieveContractFromFormData; + import io.quarkus.security.Authenticated; import io.quarkus.security.identity.CurrentIdentityAssociation; import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal; @@ -7,13 +9,22 @@ import it.pagopa.selfcare.onboarding.common.OnboardingStatus; import it.pagopa.selfcare.onboarding.common.WorkflowType; import it.pagopa.selfcare.onboarding.constants.CustomError; -import it.pagopa.selfcare.onboarding.controller.request.*; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingDefaultRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingImportPspRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingImportRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPaRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPgRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingPspRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingUserPgRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingUserRequest; +import it.pagopa.selfcare.onboarding.controller.request.ReasonRequest; import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; import it.pagopa.selfcare.onboarding.entity.Billing; import it.pagopa.selfcare.onboarding.entity.CheckManagerResponse; import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.OnboardingAggregationImportRequest; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; import it.pagopa.selfcare.onboarding.model.OnboardingGetFilters; @@ -22,11 +33,24 @@ import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HEAD; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.SecurityContext; +import java.io.File; +import java.util.List; +import java.util.Objects; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpStatus; @@ -36,12 +60,6 @@ import org.jboss.resteasy.reactive.RestForm; import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext; -import java.io.File; -import java.util.List; -import java.util.Objects; - -import static it.pagopa.selfcare.onboarding.util.Utils.retrieveContractFromFormData; - @Authenticated @Path("/v1/onboarding") @Tag(name = "Onboarding Controller") @@ -567,4 +585,20 @@ public Uni checkRecipientCode(@QueryParam("recipientCode") return RecipientCodeStatus.ACCEPTED; }); } + + @Operation( + summary = "Asynchronously import aggregated onboarding to COMPLETED status and create token", + description = "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase." + ) + @Path("/aggregation/import") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni onboardingAggregationImport(@Valid OnboardingAggregationImportRequest onboardingRequest, + @Context SecurityContext ctx) { + return readUserIdFromToken(ctx) + .onItem().transformToUni(userId -> onboardingService + .onboardingAggregationImport(fillUserId(onboardingMapper.toEntity(onboardingRequest), userId), + onboardingRequest.getOnboardingImportContract(), onboardingRequest.getUsers(), onboardingRequest.getAggregates())); + } } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingAggregationImportRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingAggregationImportRequest.java new file mode 100644 index 000000000..eb7181f65 --- /dev/null +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingAggregationImportRequest.java @@ -0,0 +1,16 @@ +package it.pagopa.selfcare.onboarding.entity; + +import it.pagopa.selfcare.onboarding.controller.request.OnboardingDefaultRequest; +import it.pagopa.selfcare.onboarding.controller.request.OnboardingImportContract; +import jakarta.validation.Valid; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class OnboardingAggregationImportRequest extends OnboardingDefaultRequest { + + @Valid + private OnboardingImportContract onboardingImportContract; +} + diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java index 488be2e3a..0b41dcca5 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java @@ -15,7 +15,6 @@ import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.model.FormItem; import it.pagopa.selfcare.onboarding.model.OnboardingGetFilters; - import java.util.List; public interface OnboardingService { @@ -45,6 +44,12 @@ Uni onboardingAggregationCompletion( List userRequests, List aggregates); + Uni onboardingAggregationImport( + Onboarding onboarding, + OnboardingImportContract contractImported, + List userRequests, + List aggregates); + Uni onboardingUserPg(Onboarding onboarding, List userRequests); Uni approve(String onboardingId); 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 989b52f40..1e3e28e37 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 @@ -290,18 +290,32 @@ public Uni onboardingAggregationCompletion( return fillUsersAndOnboarding(onboarding, userRequests, aggregates, null, false); } + @Override + public Uni onboardingAggregationImport( + Onboarding onboarding, + OnboardingImportContract contractImported, + List userRequests, + List aggregates) { + onboarding.setWorkflowType(WorkflowType.CONTRACT_REGISTRATION_AGGREGATOR); + onboarding.setStatus(OnboardingStatus.PENDING); + + return fillUsersAndOnboardingForImport( + onboarding, userRequests, aggregates, contractImported, TIMEOUT_ORCHESTRATION_RESPONSE, false); + } + + /** * As onboarding but it is specific for IMPORT workflow */ @Override public Uni onboardingImport( - Onboarding onboarding, - List userRequests, - OnboardingImportContract contractImported, boolean forceImport) { + Onboarding onboarding, + List userRequests, + OnboardingImportContract contractImported, boolean forceImport) { onboarding.setWorkflowType(WorkflowType.IMPORT); onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( - onboarding, userRequests, contractImported, TIMEOUT_ORCHESTRATION_RESPONSE, forceImport); + onboarding, userRequests, null, contractImported, TIMEOUT_ORCHESTRATION_RESPONSE, forceImport); } /** @@ -438,65 +452,66 @@ private Uni verifyExistingOnboarding( } /** - * @param timeout The orchestration instances will try complete within the defined timeout and the - * response is delivered synchronously. If is null the timeout is default 1 sec and the - * response is delivered asynchronously + * @param timeout The orchestration instances will try complete within the defined timeout and the response is delivered synchronously. If is null + * the timeout is default 1 sec and the response is delivered asynchronously */ private Uni fillUsersAndOnboardingForImport( - Onboarding onboarding, - List userRequests, - OnboardingImportContract contractImported, - String timeout, boolean forceImport) { + Onboarding onboarding, + List userRequests, + List aggregateRequests, + OnboardingImportContract contractImported, + String timeout, boolean forceImport) { + 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, null)) - .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))) - .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))) + .onItem() + .transform(onboardingMapper::toResponse)); } private Uni persistOnboarding( From 8addb66168e95fd9ff90727379888c86967d931f Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 15 Jan 2025 16:06:02 +0100 Subject: [PATCH 02/14] Added junit test for controller and service --- .../controller/OnboardingControllerTest.java | 62 +++++++ .../service/OnboardingServiceDefaultTest.java | 162 +++++++++++++++--- 2 files changed, 203 insertions(+), 21 deletions(-) diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java index 9649cf238..0b06b764c 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -55,6 +55,7 @@ import it.pagopa.selfcare.onboarding.entity.Billing; import it.pagopa.selfcare.onboarding.entity.CheckManagerResponse; import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.OnboardingAggregationImportRequest; import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; import it.pagopa.selfcare.onboarding.model.OnboardingGetFilters; import it.pagopa.selfcare.onboarding.model.RecipientCodeStatus; @@ -1244,4 +1245,65 @@ void updateRecipientCodeByOnboardingIdTest() { assertEquals(captor.getValue().getBilling().getRecipientCode(), fakeRecipientCode); } + @Test + @TestSecurity(user = "userJwt") + void onboardingAggregationImportTest_KO() { + // given + OnboardingAggregationImportRequest onboardingImport = new OnboardingAggregationImportRequest(); + + //when + given() + .when() + .body(onboardingImport) + .contentType(ContentType.JSON) + .post("/aggregation/import") + .then() + .statusCode(400); + } + + @Test + @TestSecurity(user = "userJwt") + void onboardingAggregationImportTest_OK() { + // given + OnboardingAggregationImportRequest onboardingImport = dummyOnboardingAggregationImportRequest(); + + Mockito.when(onboardingService.onboardingAggregationImport(any(), any(), any(), any())) + .thenReturn(Uni.createFrom().item(new OnboardingResponse())); + + // when + given() + .when() + .body(onboardingImport) + .contentType(ContentType.JSON) + .post("/aggregation/import") + .then() + .statusCode(200); + + // then + Mockito.verify(onboardingService, times(1)) + .onboardingAggregationImport(any(), any(), any(), any()); + } + + private OnboardingAggregationImportRequest dummyOnboardingAggregationImportRequest() { + OnboardingAggregationImportRequest onboardingRequest = new OnboardingAggregationImportRequest(); + onboardingRequest.setBilling(new BillingRequest()); + InstitutionPspRequest institutionRequest = new InstitutionPspRequest(); + institutionRequest.setInstitutionType(InstitutionType.PSP); + institutionRequest.setDigitalAddress("address@gmail.com"); + PaymentServiceProviderRequest pspData = new PaymentServiceProviderRequest(); + pspData.setAbiCode("abiCode"); + pspData.setProviderNames(List.of("test")); + institutionRequest.setPaymentServiceProvider(new PaymentServiceProviderRequest()); + onboardingRequest.setInstitution(institutionRequest); + onboardingRequest.setProductId("prod-io"); + OnboardingImportContract importContract = new OnboardingImportContract(); + importContract.setFilePath("/test/path"); + String str = "2025-01-15 11:30"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + LocalDateTime dateTime = LocalDateTime.parse(str, formatter); + importContract.setCreatedAt(dateTime); + onboardingRequest.setOnboardingImportContract(new OnboardingImportContract()); + return onboardingRequest; + } + } \ No newline at end of file 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 5c459159d..3ee7545fc 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 @@ -1,5 +1,30 @@ package it.pagopa.selfcare.onboarding.service; +import static it.pagopa.selfcare.onboarding.common.InstitutionType.PSP; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_PAGOPA; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_PN; +import static it.pagopa.selfcare.onboarding.common.WorkflowType.INCREMENT_REGISTRATION_AGGREGATOR; +import static it.pagopa.selfcare.onboarding.service.OnboardingServiceDefault.USERS_FIELD_LIST; +import static it.pagopa.selfcare.onboarding.service.OnboardingServiceDefault.USERS_FIELD_TAXCODE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.openapi.quarkus.core_json.model.InstitutionProduct.StateEnum.PENDING; + import io.quarkus.mongodb.panache.common.reactive.ReactivePanacheUpdate; import io.quarkus.mongodb.panache.reactive.ReactivePanacheQuery; import io.quarkus.panache.mock.PanacheMock; @@ -14,14 +39,32 @@ import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; import it.pagopa.selfcare.azurestorage.AzureBlobClient; -import it.pagopa.selfcare.onboarding.common.*; +import it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType; +import it.pagopa.selfcare.onboarding.common.InstitutionType; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.Origin; +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.common.WorkflowType; import it.pagopa.selfcare.onboarding.constants.CustomError; import it.pagopa.selfcare.onboarding.controller.request.AggregateInstitutionRequest; import it.pagopa.selfcare.onboarding.controller.request.OnboardingImportContract; import it.pagopa.selfcare.onboarding.controller.request.OnboardingUserRequest; import it.pagopa.selfcare.onboarding.controller.request.UserRequest; -import it.pagopa.selfcare.onboarding.controller.response.*; -import it.pagopa.selfcare.onboarding.entity.*; +import it.pagopa.selfcare.onboarding.controller.response.BillingResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGet; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingGetResponse; +import it.pagopa.selfcare.onboarding.controller.response.OnboardingResponse; +import it.pagopa.selfcare.onboarding.controller.response.UserOnboardingResponse; +import it.pagopa.selfcare.onboarding.controller.response.UserResponse; +import it.pagopa.selfcare.onboarding.entity.AdditionalInformations; +import it.pagopa.selfcare.onboarding.entity.AggregateInstitution; +import it.pagopa.selfcare.onboarding.entity.Billing; +import it.pagopa.selfcare.onboarding.entity.CheckManagerResponse; +import it.pagopa.selfcare.onboarding.entity.Institution; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.PaymentServiceProvider; +import it.pagopa.selfcare.onboarding.entity.Token; +import it.pagopa.selfcare.onboarding.entity.User; import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; import it.pagopa.selfcare.onboarding.exception.OnboardingNotAllowedException; import it.pagopa.selfcare.onboarding.exception.ResourceConflictException; @@ -42,6 +85,15 @@ import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; +import java.io.File; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; import org.apache.http.HttpStatus; import org.bson.Document; import org.eclipse.microprofile.rest.client.inject.RestClient; @@ -57,8 +109,22 @@ import org.openapi.quarkus.core_json.model.InstitutionsResponse; import org.openapi.quarkus.onboarding_functions_json.api.OrchestrationApi; import org.openapi.quarkus.onboarding_functions_json.model.OrchestrationResponse; -import org.openapi.quarkus.party_registry_proxy_json.api.*; -import org.openapi.quarkus.party_registry_proxy_json.model.*; +import org.openapi.quarkus.party_registry_proxy_json.api.AooApi; +import org.openapi.quarkus.party_registry_proxy_json.api.GeographicTaxonomiesApi; +import org.openapi.quarkus.party_registry_proxy_json.api.InfocamereApi; +import org.openapi.quarkus.party_registry_proxy_json.api.InfocamerePdndApi; +import org.openapi.quarkus.party_registry_proxy_json.api.InsuranceCompaniesApi; +import org.openapi.quarkus.party_registry_proxy_json.api.NationalRegistriesApi; +import org.openapi.quarkus.party_registry_proxy_json.api.UoApi; +import org.openapi.quarkus.party_registry_proxy_json.model.AOOResource; +import org.openapi.quarkus.party_registry_proxy_json.model.BusinessResource; +import org.openapi.quarkus.party_registry_proxy_json.model.BusinessesResource; +import org.openapi.quarkus.party_registry_proxy_json.model.GeographicTaxonomyResource; +import org.openapi.quarkus.party_registry_proxy_json.model.InstitutionResource; +import org.openapi.quarkus.party_registry_proxy_json.model.InsuranceCompanyResource; +import org.openapi.quarkus.party_registry_proxy_json.model.LegalVerificationResult; +import org.openapi.quarkus.party_registry_proxy_json.model.PDNDBusinessResource; +import org.openapi.quarkus.party_registry_proxy_json.model.UOResource; import org.openapi.quarkus.user_json.model.UserInstitutionResponse; import org.openapi.quarkus.user_registry_json.api.UserApi; import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; @@ -66,22 +132,6 @@ import org.openapi.quarkus.user_registry_json.model.UserResource; import org.openapi.quarkus.user_registry_json.model.WorkContactResource; -import java.io.File; -import java.time.LocalDateTime; -import java.util.*; - -import static it.pagopa.selfcare.onboarding.common.InstitutionType.PSP; -import static it.pagopa.selfcare.onboarding.common.ProductId.*; -import static it.pagopa.selfcare.onboarding.common.WorkflowType.INCREMENT_REGISTRATION_AGGREGATOR; -import static it.pagopa.selfcare.onboarding.service.OnboardingServiceDefault.USERS_FIELD_LIST; -import static it.pagopa.selfcare.onboarding.service.OnboardingServiceDefault.USERS_FIELD_TAXCODE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.*; -import static org.openapi.quarkus.core_json.model.InstitutionProduct.StateEnum.PENDING; - @QuarkusTest @QuarkusTestResource(MongoTestResource.class) @@ -2925,6 +2975,76 @@ private void mockRetrieveUserInstitutions(String institutionId, boolean shouldRe .thenReturn(Uni.createFrom().item(shouldRetrieveUser ? List.of(userInstitutionResponse) : Collections.emptyList()))); } + @Test + @RunOnVertxContext + void onboardingAggregationImportTest(UniAsserter asserter) { + // given + Onboarding request = new Onboarding(); + Billing billing = new Billing(); + billing.setRecipientCode("recipientCode"); + request.setBilling(billing); + List users = List.of(manager); + request.setProductId(PROD_INTEROP.getValue()); + Institution institutionBaseRequest = new Institution(); + institutionBaseRequest.setOrigin(Origin.IPA); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setImported(true); + institutionBaseRequest.setDescription(DESCRIPTION_FIELD); + institutionBaseRequest.setDigitalAddress(DIGITAL_ADDRESS_FIELD); + request.setInstitution(institutionBaseRequest); + OnboardingImportContract contractImported = new OnboardingImportContract(); + contractImported.setFileName("filename"); + contractImported.setFilePath("filepath"); + contractImported.setCreatedAt(LocalDateTime.now()); + contractImported.setContractType("type"); + + mockPersistOnboarding(asserter); + mockPersistToken(asserter); + + mockSimpleSearchPOSTAndPersist(asserter); + mockSimpleProductValidAssert(request.getProductId(), false, asserter); + mockVerifyOnboardingNotFound(); + mockVerifyAllowedMap(request.getInstitution().getTaxCode(), request.getProductId(), asserter); + + asserter.execute(() -> when(userRegistryApi.updateUsingPATCH(any(), any())) + .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)); + + InstitutionResource institutionResource = new InstitutionResource(); + institutionResource.setCategory("L37"); + institutionResource.setDescription(DESCRIPTION_FIELD); + institutionResource.setDigitalAddress(DIGITAL_ADDRESS_FIELD); + institutionResource.setIstatCode("istatCode"); + asserter.execute(() -> when(institutionRegistryProxyApi.findInstitutionUsingGET(institutionBaseRequest.getTaxCode(), null, null)) + .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))); + + List aggregates = new ArrayList<>(); + + // when + asserter.assertThat(() -> onboardingService.onboardingAggregationImport(request, contractImported, users, aggregates), + Assertions::assertNotNull); + + // then + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verify(Onboarding.class).find(any(Document.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + private void mockFindOnboarding(UniAsserter asserter, Onboarding onboarding) { asserter.execute(() -> { PanacheMock.mock(Onboarding.class); From 1af6b3a27d7937a2ede5f8a5f22eaeff39fc30e0 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 15 Jan 2025 17:03:18 +0100 Subject: [PATCH 03/14] Fixed unused param --- .../controller/OnboardingController.java | 4 ++-- .../onboarding/service/OnboardingService.java | 3 +-- .../service/OnboardingServiceDefault.java | 19 +++++++++++-------- .../controller/OnboardingControllerTest.java | 13 ++++++------- .../service/OnboardingServiceDefaultTest.java | 4 ++-- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java index b8055f549..227eb7933 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java @@ -224,7 +224,7 @@ public Uni onboardingPaCompletion(@Valid OnboardingPaRequest public Uni onboardingPaImport(@Valid OnboardingImportRequest onboardingRequest, @Context SecurityContext ctx) { return readUserIdFromToken(ctx) .onItem().transformToUni(userId -> onboardingService - .onboardingImport(fillUserId(onboardingMapper.toEntity(onboardingRequest), userId), onboardingRequest.getUsers(), onboardingRequest.getContractImported(), onboardingRequest.isForceImport())); + .onboardingImport(fillUserId(onboardingMapper.toEntity(onboardingRequest), userId), onboardingRequest.getUsers(), onboardingRequest.getContractImported())); } @Operation( @@ -238,7 +238,7 @@ public Uni onboardingPaImport(@Valid OnboardingImportRequest public Uni onboardingPspImport(@Valid OnboardingImportPspRequest onboardingRequest, @Context SecurityContext ctx) { return readUserIdFromToken(ctx) .onItem().transformToUni(userId -> onboardingService - .onboardingImport(fillUserId(onboardingMapper.toEntity(onboardingRequest), userId), List.of(), onboardingRequest.getContractImported(), false)); + .onboardingImport(fillUserId(onboardingMapper.toEntity(onboardingRequest), userId), List.of(), onboardingRequest.getContractImported())); } @Operation( diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java index 0b41dcca5..8cf42459c 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingService.java @@ -30,8 +30,7 @@ Uni onboardingUsers( Uni onboardingImport( Onboarding onboarding, List userRequests, - OnboardingImportContract contractImported, - boolean forceImport); + OnboardingImportContract contractImported); Uni onboardingCompletion( Onboarding onboarding, List userRequests); 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 1e3e28e37..967658e43 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 @@ -300,7 +300,7 @@ public Uni onboardingAggregationImport( onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( - onboarding, userRequests, aggregates, contractImported, TIMEOUT_ORCHESTRATION_RESPONSE, false); + onboarding, userRequests, aggregates, contractImported); } @@ -311,11 +311,11 @@ public Uni onboardingAggregationImport( public Uni onboardingImport( Onboarding onboarding, List userRequests, - OnboardingImportContract contractImported, boolean forceImport) { + OnboardingImportContract contractImported) { onboarding.setWorkflowType(WorkflowType.IMPORT); onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( - onboarding, userRequests, null, contractImported, TIMEOUT_ORCHESTRATION_RESPONSE, forceImport); + onboarding, userRequests, null, contractImported); } /** @@ -452,15 +452,18 @@ private Uni verifyExistingOnboarding( } /** - * @param timeout The orchestration instances will try complete within the defined timeout and the response is delivered synchronously. If is null - * the timeout is default 1 sec and the response is delivered asynchronously + * + * @param onboarding + * @param userRequests + * @param aggregateRequests + * @param contractImported + * @return OnboardingResponse */ private Uni fillUsersAndOnboardingForImport( Onboarding onboarding, List userRequests, List aggregateRequests, - OnboardingImportContract contractImported, - String timeout, boolean forceImport) { + OnboardingImportContract contractImported) { onboarding.setCreatedAt(LocalDateTime.now()); @@ -509,7 +512,7 @@ private Uni fillUsersAndOnboardingForImport( persistAndStartOrchestrationOnboarding( currentOnboarding, orchestrationApi.apiStartOnboardingOrchestrationGet( - currentOnboarding.getId(), timeout))) + currentOnboarding.getId(), TIMEOUT_ORCHESTRATION_RESPONSE))) .onItem() .transform(onboardingMapper::toResponse)); } diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java index 0b06b764c..1a8d5d776 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; @@ -763,7 +762,7 @@ void onboardingImport() { OnboardingImportRequest onboardingImportRequest = dummyOnboardingImport(); - Mockito.when(onboardingService.onboardingImport(any(), any(), any(), anyBoolean())) + Mockito.when(onboardingService.onboardingImport(any(), any(), any())) .thenReturn(Uni.createFrom().item(new OnboardingResponse())); given() @@ -775,7 +774,7 @@ void onboardingImport() { .statusCode(200); Mockito.verify(onboardingService, times(1)) - .onboardingImport(any(), any(), any(), anyBoolean()); + .onboardingImport(any(), any(), any()); } @Test @@ -797,7 +796,7 @@ void onboardingImportPSP() { OnboardingImportPspRequest onboardingImportRequest = dummyOnboardingPspRequest(); - Mockito.when(onboardingService.onboardingImport(any(), any(), any(), anyBoolean())) + Mockito.when(onboardingService.onboardingImport(any(), any(), any())) .thenReturn(Uni.createFrom().item(new OnboardingResponse())); given() @@ -809,7 +808,7 @@ void onboardingImportPSP() { .statusCode(200); Mockito.verify(onboardingService, times(1)) - .onboardingImport(any(), any(), any(), anyBoolean()); + .onboardingImport(any(), any(), any()); } @Test @@ -819,7 +818,7 @@ void onboardingImportPSP_with_activatedAt() { OnboardingImportPspRequest onboardingImportRequest = dummyOnboardingPspRequest(); onboardingImportRequest.getContractImported().setActivatedAt(LocalDateTime.now()); - Mockito.when(onboardingService.onboardingImport(any(), any(), any(), anyBoolean())) + Mockito.when(onboardingService.onboardingImport(any(), any(), any())) .thenReturn(Uni.createFrom().item(new OnboardingResponse())); given() @@ -831,7 +830,7 @@ void onboardingImportPSP_with_activatedAt() { .statusCode(200); Mockito.verify(onboardingService, times(1)) - .onboardingImport(any(), any(), any(), anyBoolean()); + .onboardingImport(any(), any(), any()); } @Test 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 3ee7545fc..ff5b7b4f2 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 @@ -2091,7 +2091,7 @@ void onboarding_Onboarding_importPA(UniAsserter asserter) { asserter.execute(() -> when(geographicTaxonomiesApi.retrieveGeoTaxonomiesByCodeUsingGET(any())) .thenReturn(Uni.createFrom().item(geographicTaxonomyResource))); - asserter.assertThat(() -> onboardingService.onboardingImport(request, users, contractImported, false), Assertions::assertNotNull); + asserter.assertThat(() -> onboardingService.onboardingImport(request, users, contractImported), Assertions::assertNotNull); asserter.execute(() -> { PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); @@ -2128,7 +2128,7 @@ void onboarding_Onboarding_importPSP(UniAsserter asserter) { mockVerifyOnboardingNotFound(); mockVerifyAllowedMap(request.getInstitution().getTaxCode(), request.getProductId(), asserter); - asserter.assertThat(() -> onboardingService.onboardingImport(request, List.of(), contractImported, false), Assertions::assertNotNull); + asserter.assertThat(() -> onboardingService.onboardingImport(request, List.of(), contractImported), Assertions::assertNotNull); asserter.execute(() -> { PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); From 99f16761fecea1fc1e9212cd2eec7582fcd2bc8f Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Thu, 16 Jan 2025 13:07:54 +0100 Subject: [PATCH 04/14] Fixed test --- .../onboarding/controller/OnboardingControllerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java index 1a8d5d776..963edb140 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -1265,9 +1265,10 @@ void onboardingAggregationImportTest_KO() { void onboardingAggregationImportTest_OK() { // given OnboardingAggregationImportRequest onboardingImport = dummyOnboardingAggregationImportRequest(); + OnboardingResponse response = dummyOnboardingResponse(); Mockito.when(onboardingService.onboardingAggregationImport(any(), any(), any(), any())) - .thenReturn(Uni.createFrom().item(new OnboardingResponse())); + .thenReturn(Uni.createFrom().item(response)); // when given() @@ -1301,7 +1302,7 @@ private OnboardingAggregationImportRequest dummyOnboardingAggregationImportReque DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); LocalDateTime dateTime = LocalDateTime.parse(str, formatter); importContract.setCreatedAt(dateTime); - onboardingRequest.setOnboardingImportContract(new OnboardingImportContract()); + onboardingRequest.setOnboardingImportContract(importContract); return onboardingRequest; } From e073f256aba340e62e87ddf26136b9080a389735 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Thu, 16 Jan 2025 15:21:54 +0100 Subject: [PATCH 05/14] Fixed junit test --- .../controller/OnboardingControllerTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java index 963edb140..a40812a67 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -1287,14 +1287,14 @@ void onboardingAggregationImportTest_OK() { private OnboardingAggregationImportRequest dummyOnboardingAggregationImportRequest() { OnboardingAggregationImportRequest onboardingRequest = new OnboardingAggregationImportRequest(); onboardingRequest.setBilling(new BillingRequest()); - InstitutionPspRequest institutionRequest = new InstitutionPspRequest(); - institutionRequest.setInstitutionType(InstitutionType.PSP); - institutionRequest.setDigitalAddress("address@gmail.com"); - PaymentServiceProviderRequest pspData = new PaymentServiceProviderRequest(); - pspData.setAbiCode("abiCode"); - pspData.setProviderNames(List.of("test")); - institutionRequest.setPaymentServiceProvider(new PaymentServiceProviderRequest()); - onboardingRequest.setInstitution(institutionRequest); + InstitutionBaseRequest institution = new InstitutionBaseRequest(); + onboardingRequest.setProductId("productId"); + onboardingRequest.setUsers(List.of(userDTO)); + institution.setTaxCode("taxCode"); + institution.setDigitalAddress("digital@address.it"); + institution.setOrigin(Origin.SELC); + institution.setInstitutionType(InstitutionType.PRV); + onboardingRequest.setInstitution(institution); onboardingRequest.setProductId("prod-io"); OnboardingImportContract importContract = new OnboardingImportContract(); importContract.setFilePath("/test/path"); From 4aa834a6a1e1ae61abbbe50a9fd2609e6e03edc6 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Thu, 16 Jan 2025 15:43:36 +0100 Subject: [PATCH 06/14] Added api-group --- apps/onboarding-ms/src/main/docs/openapi.yaml | 2 +- .../selfcare/onboarding/controller/OnboardingController.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index 73e6994ed..2eae9b43e 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -329,7 +329,7 @@ paths: /v1/onboarding/aggregation/import: post: tags: - - Onboarding Controller + - internal-v1 summary: Asynchronously import aggregated onboarding to COMPLETED status and create token description: "Perform a manual onboarding with aggregator, create token and\ diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java index 227eb7933..f924b2deb 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java @@ -591,6 +591,7 @@ public Uni checkRecipientCode(@QueryParam("recipientCode") description = "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase." ) @Path("/aggregation/import") + @Tag(name = "internal-v1") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) From 4434ffd6bb12a3307770369e42a7e84c65033d37 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Thu, 16 Jan 2025 15:45:35 +0100 Subject: [PATCH 07/14] Added api-group --- apps/onboarding-ms/src/main/docs/openapi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index e0378c721..d6a8442f9 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -451,7 +451,7 @@ }, "/v1/onboarding/aggregation/import" : { "post" : { - "tags" : [ "Onboarding Controller" ], + "tags" : [ "internal-v1" ], "summary" : "Asynchronously import aggregated onboarding to COMPLETED status and create token", "description" : "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase.", "operationId" : "onboardingAggregationImport", From 4ec4da9620ae43840c90a7947cbd903fbb395625 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Mon, 20 Jan 2025 11:58:01 +0100 Subject: [PATCH 08/14] Merge branch 'main' into feature/SELC-6056 # Conflicts: # apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/OnboardingServiceDefault.java --- .../main/openapi/onboarding_functions.json | 1 + apps/onboarding-functions/pom.xml | 2 +- .../entity/OnboardingWorkflowUser.java | 4 +- apps/onboarding-ms/pom.xml | 2 +- .../entity/registry/BaseRegistryManager.java | 3 +- .../entity/registry/RegistryManagerIPA.java | 13 +- .../entity/registry/RegistryManagerIPAUo.java | 25 ++-- .../service/OnboardingServiceDefault.java | 115 ++++++++++-------- .../main/openapi/onboarding_functions.json | 3 +- .../service/OnboardingServiceDefaultTest.java | 113 +++++++++++++++++ apps/pom.xml | 2 +- libs/onboarding-sdk-azure-storage/pom.xml | 2 +- libs/onboarding-sdk-common/pom.xml | 2 +- .../onboarding/common/WorkflowType.java | 1 + libs/onboarding-sdk-crypto/pom.xml | 2 +- libs/onboarding-sdk-pom/pom.xml | 2 +- libs/onboarding-sdk-product/pom.xml | 4 +- test-coverage/pom.xml | 2 +- 18 files changed, 219 insertions(+), 79 deletions(-) diff --git a/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json b/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json index 48caf7a95..ecef61d09 100644 --- a/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json +++ b/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json @@ -518,6 +518,7 @@ "FOR_APPROVE_GPU", "CONFIRMATION", "IMPORT", + "IMPORT_AGGREGATION", "USERS", "USERS_IMPORT", "CONTRACT_REGISTRATION_AGGREGATOR", diff --git a/apps/onboarding-functions/pom.xml b/apps/onboarding-functions/pom.xml index 63ea64b35..6c9d025f8 100644 --- a/apps/onboarding-functions/pom.xml +++ b/apps/onboarding-functions/pom.xml @@ -22,7 +22,7 @@ true 3.1.2 1.5.5.Final - 0.6.3 + 0.6.4 diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingWorkflowUser.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingWorkflowUser.java index 2bcd082e5..34f7cc540 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingWorkflowUser.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/OnboardingWorkflowUser.java @@ -34,8 +34,8 @@ public String getEmailRegistrationPath(MailTemplatePathConfig config) { .map(User::getId) .findAny() .orElse(null); - if (Objects.nonNull(this.onboarding.getPreviousManagerId()) - && this.onboarding.getPreviousManagerId().equals(managerId)) { + if (Objects.isNull(this.onboarding.getPreviousManagerId()) + || this.onboarding.getPreviousManagerId().equals(managerId)) { return config.registrationUserPath(); } return config.registrationUserNewManagerPath(); diff --git a/apps/onboarding-ms/pom.xml b/apps/onboarding-ms/pom.xml index eea296f3f..b96693fd9 100644 --- a/apps/onboarding-ms/pom.xml +++ b/apps/onboarding-ms/pom.xml @@ -24,7 +24,7 @@ true 3.1.2 2.4.1 - 0.6.3 + 0.6.4 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 656f17eec..a7d73c5b3 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 @@ -13,7 +13,8 @@ public abstract class BaseRegistryManager implements RegistryManager { protected static final String ONBOARDING_NOT_ALLOWED_ERROR_MESSAGE_NOT_DELEGABLE = "Institution with external id '%s' is not allowed to onboard '%s' product because it is not delegable"; protected static final String PARENT_TAX_CODE_IS_INVALID = "The tax code of the parent entity of the request does not match the tax code of the parent entity retrieved by IPA"; 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 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 int DURATION_TIMEOUT = 5; protected static final int MAX_NUMBER_ATTEMPTS = 2; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPA.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPA.java index 1898067bc..af25fbe1c 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPA.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPA.java @@ -31,12 +31,12 @@ public RegistryManagerIPA(Onboarding onboarding, UoApi uoApi, InstitutionApi ins @Override public IPAEntity retrieveInstitution() { super.originIdEC = onboarding.getInstitution().getOriginId(); - InstitutionResource institutionResource = super.institutionApi.findInstitutionUsingGET(onboarding.getInstitution().getTaxCode(), null, null) - .onFailure().retry().atMost(MAX_NUMBER_ATTEMPTS) - .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException) ex).getResponse().getStatus() == 404 - ? Uni.createFrom().failure(new ResourceNotFoundException(String.format("Institution with taxCode %s not found", onboarding.getInstitution().getTaxCode()))) - : Uni.createFrom().failure(ex)) - .await().atMost(Duration.of(DURATION_TIMEOUT, ChronoUnit.SECONDS)); + InstitutionResource institutionResource = super.institutionApi.findInstitutionUsingGET(onboarding.getInstitution().getTaxCode(), null, null) + .onFailure().retry().atMost(MAX_NUMBER_ATTEMPTS) + .onFailure(WebApplicationException.class).recoverWithUni(ex -> ((WebApplicationException) ex).getResponse().getStatus() == 404 + ? Uni.createFrom().failure(new ResourceNotFoundException(String.format("Institution with taxCode %s not found", onboarding.getInstitution().getTaxCode()))) + : Uni.createFrom().failure(ex)) + .await().atMost(Duration.of(DURATION_TIMEOUT, ChronoUnit.SECONDS)); return IPAEntity.builder().institutionResource(institutionResource).build(); } @@ -48,6 +48,7 @@ public Uni isValid() { return Uni.createFrom().item(true); } + private boolean originIPA(Onboarding onboarding, InstitutionResource institutionResource) { return onboarding.getInstitution().getDigitalAddress().equals(institutionResource.getDigitalAddress()) && onboarding.getInstitution().getDescription().equals(institutionResource.getDescription()); diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java index 0d047d627..0d6023fff 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java @@ -15,14 +15,18 @@ import org.openapi.quarkus.party_registry_proxy_json.api.UoApi; import org.openapi.quarkus.party_registry_proxy_json.model.UOResource; +import java.util.List; import java.util.Objects; import static it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType.UO; import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO_PREMIUM; import static it.pagopa.selfcare.onboarding.constants.CustomError.*; public class RegistryManagerIPAUo extends ClientRegistryIPA { + private static final List ALLOWED_PRICING_PLANS = List.of("C0"); + public RegistryManagerIPAUo(Onboarding onboarding, UoApi uoApi, AooApi aooApi) { super(onboarding, uoApi, aooApi); } @@ -41,6 +45,10 @@ public Uni customValidation(Product product) { if (!PROD_INTEROP.getValue().equals(onboarding.getProductId()) && (Objects.isNull(onboarding.getBilling()) || Objects.isNull(onboarding.getBilling().getRecipientCode()))) { return Uni.createFrom().failure(new InvalidRequestException(BILLING_OR_RECIPIENT_CODE_REQUIRED)); + } else if (PROD_IO_PREMIUM.getValue().equals(onboarding.getProductId()) && + ALLOWED_PRICING_PLANS.stream().noneMatch( + pricingPlan -> pricingPlan.equals(onboarding.getPricingPlan()))) { + return Uni.createFrom().failure(new InvalidRequestException(BaseRegistryManager.NOT_ALLOWED_PRICING_PLAN)); } return Uni.createFrom().item(onboarding); }).onItem().transformToUni(unused -> billingChecks()); @@ -78,13 +86,13 @@ protected Uni checkRecipientCode() { } protected Uni validateRecipientCode(UOResource uoResource) { - if (Objects.nonNull(originIdEC) && !originIdEC.equals(uoResource.getCodiceIpa())) { - return Uni.createFrom().item(DENIED_NO_ASSOCIATION); - } - if (Objects.isNull(uoResource.getCodiceFiscaleSfe())) { - return Uni.createFrom().item(DENIED_NO_BILLING); - } - return Uni.createFrom().nullItem(); + if (Objects.nonNull(originIdEC) && !originIdEC.equals(uoResource.getCodiceIpa())) { + return Uni.createFrom().item(DENIED_NO_ASSOCIATION); + } + if (Objects.isNull(uoResource.getCodiceFiscaleSfe())) { + return Uni.createFrom().item(DENIED_NO_BILLING); + } + return Uni.createFrom().nullItem(); } protected boolean isInvoiceablePA(Onboarding onboarding) { @@ -116,8 +124,7 @@ private Uni checkTaxCodeInvoicing(Onboarding onboarding) { .flatMap(uosResource -> { /* if parent tax code is not into hierarchy, throw an exception */ if (Objects.nonNull(uosResource) && Objects.nonNull(uosResource.getItems()) - && uosResource.getItems().stream().anyMatch(uoResource -> !uoResource.getCodiceFiscaleEnte().equals(onboarding.getInstitution().getTaxCode()))) - { + && uosResource.getItems().stream().anyMatch(uoResource -> !uoResource.getCodiceFiscaleEnte().equals(onboarding.getInstitution().getTaxCode()))) { return Uni.createFrom().failure(new InvalidRequestException(TAX_CODE_INVOICING_IS_INVALID)); } return Uni.createFrom().item(onboarding); 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 967658e43..200093751 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 @@ -1398,7 +1398,7 @@ private Uni retrieveContractDigest(String onboardingId) { private Uni retrieveToken(String onboardingId) { return Token.list("onboardingId", onboardingId) - .map(tokens -> tokens.stream().findFirst().map(token -> (Token) token).orElseThrow()); + .map(tokens -> tokens.stream().findFirst().map(Token.class::cast).orElseThrow()); } private Uni> retrieveOnboardingUserFiscalCodeList(Onboarding onboarding) { @@ -1731,55 +1731,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); - } - - 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/main/openapi/onboarding_functions.json b/apps/onboarding-ms/src/main/openapi/onboarding_functions.json index a5b5946b0..b58258f4b 100644 --- a/apps/onboarding-ms/src/main/openapi/onboarding_functions.json +++ b/apps/onboarding-ms/src/main/openapi/onboarding_functions.json @@ -483,7 +483,8 @@ "FOR_APPROVE_PT", "FOR_APPROVE_GPU", "CONFIRMATION", - "IMPORT" + "IMPORT", + "IMPORT_AGGREGATION" ], "type": "string" }, 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 ff5b7b4f2..92be490db 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 @@ -756,6 +756,97 @@ void onboarding_Onboarding_addParentDescriptionForAooOrUo_UoException(UniAsserte asserter.assertFailedWith(() -> onboardingService.onboarding(request, users, null), WebApplicationException.class); } + @Test + @RunOnVertxContext + void onboardingPa_allowedPricingPlan(UniAsserter asserter) { + Onboarding request = new Onboarding(); + List users = List.of(manager); + request.setProductId(PROD_IO_PREMIUM.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("C0"); + 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.assertThat(() -> onboardingService.onboarding(request, users, null), Assertions::assertNotNull); + + asserter.execute(() -> { + PanacheMock.verify(Onboarding.class).persist(any(Onboarding.class), any()); + PanacheMock.verify(Onboarding.class).persistOrUpdate(any(List.class)); + PanacheMock.verify(Onboarding.class).find(any(Document.class)); + PanacheMock.verifyNoMoreInteractions(Onboarding.class); + }); + } + + @Test + @RunOnVertxContext + void onboardingPa_notAllowedPricingPlan(UniAsserter asserter) { + Onboarding request = new Onboarding(); + List users = List.of(manager); + request.setProductId(PROD_IO_PREMIUM.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)); @@ -2792,6 +2883,28 @@ void testCheckManagerWithEmptyOnboardings() { assertFalse(checkResponse.isResponse()); } + @Test + void testCheckManagerWithRemovedUser() { + OnboardingUserRequest request = createDummyUserRequest(); + PanacheMock.mock(Onboarding.class); + Onboarding onboarding = createDummyOnboarding(); + onboarding.getUsers().get(0).setRole(PartyRole.OPERATOR); + ReactivePanacheQuery query = Mockito.mock(ReactivePanacheQuery.class); + when(query.stream()).thenReturn(Multi.createFrom().items(onboarding)); + when(Onboarding.find((Document) any(), any())).thenReturn(query); + UserResource userResource = new UserResource(); + userResource.setId(UUID.randomUUID()); + when(userRegistryApi.searchUsingPOST(any(), any())) + .thenReturn(Uni.createFrom().item(userResource)); + + UniAssertSubscriber subscriber = onboardingService + .checkManager(request) + .subscribe() + .withSubscriber(UniAssertSubscriber.create()); + + subscriber.assertFailedWith(ResourceNotFoundException.class); + } + @Test void testCheckManagerWithEmptyUserList() { final UUID uuid = UUID.randomUUID(); diff --git a/apps/pom.xml b/apps/pom.xml index a43e05b79..eefb84296 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -13,7 +13,7 @@ pom - 0.6.3 + 0.6.4 diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml index 3b31b5f63..31b9626d3 100644 --- a/libs/onboarding-sdk-azure-storage/pom.xml +++ b/libs/onboarding-sdk-azure-storage/pom.xml @@ -6,7 +6,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.6.3 + 0.6.4 ../onboarding-sdk-pom diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml index ce0db2f65..add24bbaf 100644 --- a/libs/onboarding-sdk-common/pom.xml +++ b/libs/onboarding-sdk-common/pom.xml @@ -4,7 +4,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.6.3 + 0.6.4 ../onboarding-sdk-pom onboarding-sdk-common diff --git a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java index 80369b59f..a6bc17ff5 100644 --- a/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java +++ b/libs/onboarding-sdk-common/src/main/java/it/pagopa/selfcare/onboarding/common/WorkflowType.java @@ -10,6 +10,7 @@ public enum WorkflowType { USERS,//USER USERS_IMPORT,//USER IMPORT,//INSTITUTION + IMPORT_AGGREGATION, CONTRACT_REGISTRATION_AGGREGATOR,//AGGREGATION CONFIRMATION_AGGREGATE,//AGGREGATION INCREMENT_REGISTRATION_AGGREGATOR,//AGGREGATION diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml index 025f55b8c..8bd8cc718 100644 --- a/libs/onboarding-sdk-crypto/pom.xml +++ b/libs/onboarding-sdk-crypto/pom.xml @@ -4,7 +4,7 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.6.3 + 0.6.4 ../onboarding-sdk-pom onboarding-sdk-crypto diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml index cc26ea08a..53de22a27 100644 --- a/libs/onboarding-sdk-pom/pom.xml +++ b/libs/onboarding-sdk-pom/pom.xml @@ -5,7 +5,7 @@ onboarding-sdk-pom pom onboarding-sdk-pom - 0.6.3 + 0.6.4 17 diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index eeaafc4ae..0fb619f41 100644 --- a/libs/onboarding-sdk-product/pom.xml +++ b/libs/onboarding-sdk-product/pom.xml @@ -4,12 +4,12 @@ it.pagopa.selfcare onboarding-sdk-pom - 0.6.3 + 0.6.4 ../onboarding-sdk-pom onboarding-sdk-product onboarding-sdk-product - 0.6.3 + 0.6.4 2.15.2 diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index b83b14ef8..af4b2debf 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -19,7 +19,7 @@ **/utils/**, **/*Constant*, **/*Config.java, **/error/**, **/filter/**, org/** https://sonarcloud.io - 0.6.3 + 0.6.4 From b3636122768e5d51679156993947e155eabcfedb Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Mon, 20 Jan 2025 12:00:20 +0100 Subject: [PATCH 09/14] Changed workflow type --- .../selfcare/onboarding/service/OnboardingServiceDefault.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 200093751..df0852588 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 @@ -296,7 +296,7 @@ public Uni onboardingAggregationImport( OnboardingImportContract contractImported, List userRequests, List aggregates) { - onboarding.setWorkflowType(WorkflowType.CONTRACT_REGISTRATION_AGGREGATOR); + onboarding.setWorkflowType(WorkflowType.IMPORT_AGGREGATION); onboarding.setStatus(OnboardingStatus.PENDING); return fillUsersAndOnboardingForImport( From 079288fd4899315f8f98840b508ddeb3adf4dc06 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Mon, 20 Jan 2025 12:17:58 +0100 Subject: [PATCH 10/14] Fixed missing import --- .../onboarding/service/OnboardingServiceDefaultTest.java | 1 + 1 file changed, 1 insertion(+) 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 92be490db..88da777f4 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 @@ -3,6 +3,7 @@ import static it.pagopa.selfcare.onboarding.common.InstitutionType.PSP; import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO_PREMIUM; import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_PAGOPA; import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_PN; import static it.pagopa.selfcare.onboarding.common.WorkflowType.INCREMENT_REGISTRATION_AGGREGATOR; From c9aa69631f516d441011fbdda639a218f00178a7 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 22 Jan 2025 08:59:37 +0100 Subject: [PATCH 11/14] Fixed default tag on endpoint --- apps/onboarding-ms/src/main/docs/openapi.json | 2 +- apps/onboarding-ms/src/main/docs/openapi.yaml | 2 +- .../selfcare/onboarding/controller/OnboardingController.java | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index d6a8442f9..e0378c721 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -451,7 +451,7 @@ }, "/v1/onboarding/aggregation/import" : { "post" : { - "tags" : [ "internal-v1" ], + "tags" : [ "Onboarding Controller" ], "summary" : "Asynchronously import aggregated onboarding to COMPLETED status and create token", "description" : "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase.", "operationId" : "onboardingAggregationImport", diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index 2eae9b43e..73e6994ed 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -329,7 +329,7 @@ paths: /v1/onboarding/aggregation/import: post: tags: - - internal-v1 + - Onboarding Controller summary: Asynchronously import aggregated onboarding to COMPLETED status and create token description: "Perform a manual onboarding with aggregator, create token and\ diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java index f924b2deb..227eb7933 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/OnboardingController.java @@ -591,7 +591,6 @@ public Uni checkRecipientCode(@QueryParam("recipientCode") description = "Perform a manual onboarding with aggregator, create token and set onboarding status to COMPLETED phase." ) @Path("/aggregation/import") - @Tag(name = "internal-v1") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) From 972df64a710e94eeb37415c87b121ebb51fd9e08 Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 22 Jan 2025 16:53:52 +0100 Subject: [PATCH 12/14] Added case for not imported --- .../entity/registry/RegistryManagerIPAUo.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java index 0d6023fff..7cc4020c4 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/registry/RegistryManagerIPAUo.java @@ -1,28 +1,29 @@ package it.pagopa.selfcare.onboarding.entity.registry; +import static it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType.UO; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; +import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO_PREMIUM; +import static it.pagopa.selfcare.onboarding.constants.CustomError.DENIED_NO_ASSOCIATION; +import static it.pagopa.selfcare.onboarding.constants.CustomError.DENIED_NO_BILLING; +import static it.pagopa.selfcare.onboarding.constants.CustomError.UO_NOT_FOUND; + import io.smallrye.mutiny.Uni; import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.constants.CustomError; -import it.pagopa.selfcare.onboarding.entity.registry.client.ClientRegistryIPA; import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.registry.client.ClientRegistryIPA; import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import it.pagopa.selfcare.product.entity.Product; import jakarta.ws.rs.WebApplicationException; +import java.util.List; +import java.util.Objects; import org.openapi.quarkus.party_registry_proxy_json.api.AooApi; import org.openapi.quarkus.party_registry_proxy_json.api.GeographicTaxonomiesApi; import org.openapi.quarkus.party_registry_proxy_json.api.InstitutionApi; import org.openapi.quarkus.party_registry_proxy_json.api.UoApi; import org.openapi.quarkus.party_registry_proxy_json.model.UOResource; -import java.util.List; -import java.util.Objects; - -import static it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType.UO; -import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_INTEROP; -import static it.pagopa.selfcare.onboarding.common.ProductId.PROD_IO_PREMIUM; -import static it.pagopa.selfcare.onboarding.constants.CustomError.*; - public class RegistryManagerIPAUo extends ClientRegistryIPA { private static final List ALLOWED_PRICING_PLANS = List.of("C0"); @@ -42,7 +43,7 @@ public RegistryManagerIPAUo(Onboarding onboarding, UoApi uoApi, InstitutionApi i @Override public Uni customValidation(Product product) { return checkRecipientCode().onItem().transformToUni(unused -> { - if (!PROD_INTEROP.getValue().equals(onboarding.getProductId()) + if (!PROD_INTEROP.getValue().equals(onboarding.getProductId()) && !onboarding.getInstitution().isImported() && (Objects.isNull(onboarding.getBilling()) || Objects.isNull(onboarding.getBilling().getRecipientCode()))) { return Uni.createFrom().failure(new InvalidRequestException(BILLING_OR_RECIPIENT_CODE_REQUIRED)); } else if (PROD_IO_PREMIUM.getValue().equals(onboarding.getProductId()) && From 4126d2228543ec3eed6457b408284258d8f55e2d Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Thu, 30 Jan 2025 16:16:38 +0100 Subject: [PATCH 13/14] Fixed some sonar issues --- .../onboarding/service/OnboardingServiceDefault.java | 2 +- .../controller/OnboardingControllerTest.java | 12 ++++++------ .../service/OnboardingServiceDefaultTest.java | 11 +++++------ 3 files changed, 12 insertions(+), 13 deletions(-) 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 df0852588..53888df91 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 @@ -2135,7 +2135,7 @@ private Uni checkIfUserIsManagerOnADE(String userTaxCode, String businessT return Uni.createFrom() .failure( new InvalidRequestException( - "User is not manager of the institution on the registry")); + NOT_MANAGER_OF_THE_INSTITUTION_ON_THE_REGISTRY)); } return Uni.createFrom().failure(ex); diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java index a40812a67..356d7fd7b 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/OnboardingControllerTest.java @@ -1287,14 +1287,14 @@ void onboardingAggregationImportTest_OK() { private OnboardingAggregationImportRequest dummyOnboardingAggregationImportRequest() { OnboardingAggregationImportRequest onboardingRequest = new OnboardingAggregationImportRequest(); onboardingRequest.setBilling(new BillingRequest()); - InstitutionBaseRequest institution = new InstitutionBaseRequest(); + InstitutionBaseRequest institutionBaseRequest = new InstitutionBaseRequest(); onboardingRequest.setProductId("productId"); onboardingRequest.setUsers(List.of(userDTO)); - institution.setTaxCode("taxCode"); - institution.setDigitalAddress("digital@address.it"); - institution.setOrigin(Origin.SELC); - institution.setInstitutionType(InstitutionType.PRV); - onboardingRequest.setInstitution(institution); + institutionBaseRequest.setTaxCode("taxCode"); + institutionBaseRequest.setDigitalAddress("digital@address.it"); + institutionBaseRequest.setOrigin(Origin.SELC); + institutionBaseRequest.setInstitutionType(InstitutionType.PRV); + onboardingRequest.setInstitution(institutionBaseRequest); onboardingRequest.setProductId("prod-io"); OnboardingImportContract importContract = new OnboardingImportContract(); importContract.setFilePath("/test/path"); 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 88da777f4..c2c9e0748 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 @@ -133,7 +133,6 @@ import org.openapi.quarkus.user_registry_json.model.UserResource; import org.openapi.quarkus.user_registry_json.model.WorkContactResource; - @QuarkusTest @QuarkusTestResource(MongoTestResource.class) class OnboardingServiceDefaultTest { @@ -222,8 +221,8 @@ class OnboardingServiceDefaultTest { static final UserResource managerResourceWk; static final UserResource managerResourceWkSpid; - static final String productRoleAdminCode = "admin"; - static final String productRoleAdminPspCode = "admin-psp"; + static final String PRODUCT_ROLE_ADMIN_CODE = "admin"; + static final String PRODUCT_ROLE_ADMIN_PSP_CODE = "admin-psp"; static final String DIGITAL_ADDRESS_FIELD = "digitalAddress"; static final String DESCRIPTION_FIELD = "description"; static final File testFile = new File("src/test/resources/application.properties"); @@ -1281,18 +1280,18 @@ ProductRoleInfo dummyProductRoleInfo(String productRolCode) { Product createDummyProduct(String productId, boolean hasParent) { Map roleMappingByInstitutionType = new HashMap<>(); - roleMappingByInstitutionType.put(manager.getRole(), dummyProductRoleInfo(productRoleAdminPspCode)); + roleMappingByInstitutionType.put(manager.getRole(), dummyProductRoleInfo(PRODUCT_ROLE_ADMIN_PSP_CODE)); Product productResource = new Product(); productResource.setId(productId); - productResource.setRoleMappings(Map.of(manager.getRole(), dummyProductRoleInfo(productRoleAdminCode))); + productResource.setRoleMappings(Map.of(manager.getRole(), dummyProductRoleInfo(PRODUCT_ROLE_ADMIN_CODE))); productResource.setRoleMappingsByInstitutionType(Map.of(PSP.name(), roleMappingByInstitutionType)); productResource.setTitle("title"); if (hasParent) { Product parent = new Product(); parent.setId("productParentId"); - parent.setRoleMappings(Map.of(manager.getRole(), dummyProductRoleInfo(productRoleAdminCode))); + parent.setRoleMappings(Map.of(manager.getRole(), dummyProductRoleInfo(PRODUCT_ROLE_ADMIN_CODE))); productResource.setParentId(parent.getId()); productResource.setParent(parent); } From e90c4652c927c53033336fbf36cf880e8fa2fbff Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Fri, 31 Jan 2025 10:13:43 +0100 Subject: [PATCH 14/14] Added test case for aggregates --- .../service/OnboardingServiceDefaultTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 c2c9e0748..85734a6e2 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 @@ -3144,6 +3144,17 @@ void onboardingAggregationImportTest(UniAsserter asserter) { .thenReturn(Uni.createFrom().item(geographicTaxonomyResource))); List aggregates = new ArrayList<>(); + AggregateInstitutionRequest aggregateInstitutionRequest = new AggregateInstitutionRequest(); + aggregateInstitutionRequest.setTaxCode("taxCode"); + aggregateInstitutionRequest.setUsers(users); + aggregates.add(aggregateInstitutionRequest); + + AggregateInstitution aggregateInstitution = new AggregateInstitution(); + aggregateInstitution.setTaxCode("taxCode"); + aggregateInstitution.setUsers(List.of(User.builder().id("test") + .role(PartyRole.MANAGER) + .build())); + request.setAggregates(List.of(aggregateInstitution)); // when asserter.assertThat(() -> onboardingService.onboardingAggregationImport(request, contractImported, users, aggregates),