From 7827edb5831b3ab4e10c05718af4245c846ddc27 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:01:44 +0200 Subject: [PATCH 01/27] [SELC-5560] feat: call CREATE_AGGREGATES_CSV_ACTIVITY function in WorkflowExecutorContractRegistrationAggregator (#523) --- .../onboarding/service/ContractServiceDefault.java | 2 +- ...flowExecutorContractRegistrationAggregator.java | 11 ++++------- .../functions/OnboardingFunctionsTest.java | 14 +++++++++----- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java index c9ecee0c9..e91f54ba8 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -300,7 +300,7 @@ private File generateCsv(List institutions, Path filePath) institution.getAddress(), institution.getCity(), institution.getCounty(), - Optional.ofNullable(institution.getSubunitType()).map(ignored -> institution.getOriginId()).orElse(""), + Optional.ofNullable(institution.getSubunitType()).map(originId -> "").orElse(institution.getOriginId()), institution.getSubunitType(), institution.getSubunitCode() ); diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistrationAggregator.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistrationAggregator.java index d37f2d9ea..ce6a53756 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistrationAggregator.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorContractRegistrationAggregator.java @@ -1,31 +1,28 @@ package it.pagopa.selfcare.onboarding.workflow; import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.durabletask.Task; import com.microsoft.durabletask.TaskOptions; import com.microsoft.durabletask.TaskOrchestrationContext; import it.pagopa.selfcare.onboarding.common.OnboardingStatus; -import it.pagopa.selfcare.onboarding.dto.OnboardingAggregateOrchestratorInput; -import it.pagopa.selfcare.onboarding.entity.AggregateInstitution; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.entity.OnboardingWorkflow; import it.pagopa.selfcare.onboarding.entity.OnboardingWorkflowAggregator; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; -import java.util.ArrayList; -import java.util.List; import java.util.Optional; import static it.pagopa.selfcare.onboarding.entity.OnboardingWorkflowType.AGGREGATOR; import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; -import static it.pagopa.selfcare.onboarding.utils.Utils.*; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingWorkflowString; +import static it.pagopa.selfcare.onboarding.utils.Utils.readOnboardingValue; public record WorkflowExecutorContractRegistrationAggregator(ObjectMapper objectMapper, TaskOptions optionsRetry, OnboardingMapper onboardingMapper) implements WorkflowExecutor { @Override public Optional executeRequestState(TaskOrchestrationContext ctx, OnboardingWorkflow onboardingWorkflow) { String onboardingWorkflowString = getOnboardingWorkflowString(objectMapper, onboardingWorkflow); - ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, getOnboardingWorkflowString(objectMapper, onboardingWorkflow), optionsRetry, String.class).await(); + ctx.callActivity(CREATE_AGGREGATES_CSV_ACTIVITY, onboardingWorkflowString, optionsRetry, String.class).await(); + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, onboardingWorkflowString, optionsRetry, String.class).await(); ctx.callActivity(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, onboardingWorkflowString, optionsRetry, String.class).await(); ctx.callActivity(SEND_MAIL_REGISTRATION_FOR_CONTRACT, onboardingWorkflowString, optionsRetry, String.class).await(); return Optional.of(OnboardingStatus.PENDING); diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctionsTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctionsTest.java index e03d7e62a..8fe643cf6 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctionsTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/functions/OnboardingFunctionsTest.java @@ -27,7 +27,10 @@ import org.mockito.Mockito; import org.mockito.stubbing.Answer; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.logging.Logger; import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.*; @@ -148,11 +151,12 @@ void onboardingOrchestratorContractRegistrationAggregator(){ function.onboardingsOrchestrator(orchestrationContext, executionContext); ArgumentCaptor captorActivity = ArgumentCaptor.forClass(String.class); - verify(orchestrationContext, times(3)) + verify(orchestrationContext, times(4)) .callActivity(captorActivity.capture(), any(), any(),any()); - assertEquals(BUILD_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(0)); - assertEquals(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(1)); - assertEquals(SEND_MAIL_REGISTRATION_FOR_CONTRACT, captorActivity.getAllValues().get(2)); + assertEquals(CREATE_AGGREGATES_CSV_ACTIVITY, captorActivity.getAllValues().get(0)); + assertEquals(BUILD_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(1)); + assertEquals(SAVE_TOKEN_WITH_CONTRACT_ACTIVITY_NAME, captorActivity.getAllValues().get(2)); + assertEquals(SEND_MAIL_REGISTRATION_FOR_CONTRACT, captorActivity.getAllValues().get(3)); verify(service, times(1)) .updateOnboardingStatus(onboarding.getId(), OnboardingStatus.PENDING); From 657090498d5e3685d17eef7bf1c9673ac14b62de Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:02:08 +0200 Subject: [PATCH 02/27] [SELC-5561] feat: call CREATE_AGGREGATES_CSV_ACTIVITY function in WorkflowExecutorIncrementRegistrationAggregator (#522) --- .../WorkflowExecutorIncrementRegistrationAggregator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorIncrementRegistrationAggregator.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorIncrementRegistrationAggregator.java index 428c34eec..caab0f645 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorIncrementRegistrationAggregator.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/workflow/WorkflowExecutorIncrementRegistrationAggregator.java @@ -12,12 +12,15 @@ import java.util.Optional; import static it.pagopa.selfcare.onboarding.entity.OnboardingWorkflowType.AGGREGATOR; +import static it.pagopa.selfcare.onboarding.functions.utils.ActivityName.BUILD_CONTRACT_ACTIVITY_NAME; +import static it.pagopa.selfcare.onboarding.utils.Utils.getOnboardingWorkflowString; public record WorkflowExecutorIncrementRegistrationAggregator(ObjectMapper objectMapper, TaskOptions optionsRetry, OnboardingMapper onboardingMapper) implements WorkflowExecutor { @Override public Optional executeRequestState(TaskOrchestrationContext ctx, OnboardingWorkflow onboardingWorkflow) { + ctx.callActivity(BUILD_CONTRACT_ACTIVITY_NAME, getOnboardingWorkflowString(objectMapper, onboardingWorkflow), optionsRetry, String.class).await(); return Optional.empty(); } From 230494113a173d0a5fdbc4208ad2af2e5d97efef Mon Sep 17 00:00:00 2001 From: flaminiaScarciofolo <113031535+flaminiaScarciofolo@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:20:03 +0200 Subject: [PATCH 03/27] [SELC-5681] Feat: Added additional fields in verify csv for PAGOPA (#524) --- apps/onboarding-ms/src/main/docs/openapi.json | 57 ++++++++++++++ apps/onboarding-ms/src/main/docs/openapi.yaml | 42 ++++++++++ .../controller/AggregatesController.java | 14 +++- .../onboarding/mapper/OnboardingMapper.java | 1 + .../selfcare/onboarding/model/Aggregate.java | 4 + .../onboarding/model/CsvAggregatePagoPa.java | 28 ++----- .../onboarding/model/CsvAggregateSend.java | 35 +++------ .../onboarding/service/AggregatesService.java | 2 + .../service/AggregatesServiceDefault.java | 59 +++++++++++++- .../controller/AggregatesControllerTest.java | 20 +++++ .../model/CsvAggregatePagoPaTest.java | 56 ++++++++++++++ .../service/AggregatesServiceDefaultTest.java | 76 +++++++++++++++++++ .../src/test/resources/aggregates-pagopa.csv | 12 ++- .../src/test/resources/aggregates-send.csv | 19 ++++- 14 files changed, 368 insertions(+), 57 deletions(-) create mode 100644 apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPaTest.java diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index 04a268251..bd80f97b9 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -70,6 +70,51 @@ } ] } }, + "/v1/aggregates/verification/prod-pagopa" : { + "post" : { + "tags" : [ "Aggregates Controller" ], + "summary" : "Validate the data related to the aggregated entities present in a CSV file", + "description" : "Validates aggregated entity data specific to the PROD-Pagopa environment by processing the provided CSV file. This ensures that all entries meet the required criteria before further processing.", + "operationId" : "verifyPagoPaAggregatesCsv", + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "aggregates" ], + "type" : "object", + "properties" : { + "aggregates" : { + "format" : "binary", + "type" : "string" + } + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/VerifyAggregateResponse" + } + } + } + }, + "401" : { + "description" : "Not Authorized" + }, + "403" : { + "description" : "Not Allowed" + } + }, + "security" : [ { + "SecurityScheme" : [ ] + } ] + } + }, "/v1/notification/resend" : { "post" : { "tags" : [ "Notification Controller" ], @@ -1391,6 +1436,18 @@ "origin" : { "type" : "string" }, + "taxCodePT" : { + "type" : "string" + }, + "iban" : { + "type" : "string" + }, + "service" : { + "type" : "string" + }, + "syncAsyncMode" : { + "type" : "string" + }, "rowNumber" : { "format" : "int32", "type" : "integer" diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index f0bca40be..ffa08a24a 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -50,6 +50,40 @@ paths: description: Not Allowed security: - SecurityScheme: [] + /v1/aggregates/verification/prod-pagopa: + post: + tags: + - Aggregates Controller + summary: Validate the data related to the aggregated entities present in a CSV + file + description: Validates aggregated entity data specific to the PROD-Pagopa environment + by processing the provided CSV file. This ensures that all entries meet the + required criteria before further processing. + operationId: verifyPagoPaAggregatesCsv + requestBody: + content: + multipart/form-data: + schema: + required: + - aggregates + type: object + properties: + aggregates: + format: binary + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyAggregateResponse" + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] /v1/notification/resend: post: tags: @@ -1017,6 +1051,14 @@ components: type: string origin: type: string + taxCodePT: + type: string + iban: + type: string + service: + type: string + syncAsyncMode: + type: string rowNumber: format: int32 type: integer diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java index 6bd9f5868..0065de5e7 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java @@ -2,7 +2,7 @@ import io.quarkus.security.Authenticated; import io.smallrye.mutiny.Uni; -import it.pagopa.selfcare.onboarding.model.*; +import it.pagopa.selfcare.onboarding.model.VerifyAggregateResponse; import it.pagopa.selfcare.onboarding.service.AggregatesService; import jakarta.inject.Inject; import jakarta.validation.constraints.NotNull; @@ -37,6 +37,18 @@ public Uni verifyAppIoAggregatesCsv(@NotNull @RestForm( return aggregatesService.validateAppIoAggregatesCsv(file); } + @Operation( + summary = "Validate the data related to the aggregated entities present in a CSV file", + description = "Validates aggregated entity data specific to the PROD-Pagopa environment by processing the provided CSV file. This ensures that all entries meet the required criteria before further processing." + ) + @POST + @Path("/verification/prod-pagopa") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Uni verifyPagoPaAggregatesCsv(@NotNull @RestForm("aggregates") File file){ + + return aggregatesService.validatePagoPaAggregatesCsv(file); + } } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java index 66d5f8928..1ee781395 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java @@ -116,6 +116,7 @@ default OffsetDateTime toOffsetDateTime(java.time.LocalDateTime localDateTime) { Aggregate csvToAggregateAppIo(CsvAggregateAppIo csvAggregateAppIo); + Aggregate csvToAggregatePagoPa(CsvAggregatePagoPa csvAggregatePagoPa); default List mapCsvAppIoAggregatesToAggregates(List csvAggregateAppIoList) { if (csvAggregateAppIoList == null) { diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java index a96ab2369..e4cf09498 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java @@ -17,6 +17,10 @@ public class Aggregate { private String zipCode; private String originId; private String origin; + private String taxCodePT; + private String iban; + private String service; + private String syncAsyncMode; @JsonIgnoreProperties private Integer rowNumber; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPa.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPa.java index 25c0e7ceb..a20aec11f 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPa.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPa.java @@ -7,39 +7,21 @@ public class CsvAggregatePagoPa implements Csv { @CsvBindByPosition(position = 0) - private String description; - - @CsvBindByPosition(position = 1) - private String pec; - - @CsvBindByPosition(position = 2) private String taxCode; - @CsvBindByPosition(position = 3) + @CsvBindByPosition(position = 1) private String vatNumber; - @CsvBindByPosition(position = 4) - private String address; - - @CsvBindByPosition(position = 5) - private String city; - - @CsvBindByPosition(position = 6) - private String province; - - @CsvBindByPosition(position = 7) - private String aggragateNamePT; - - @CsvBindByPosition(position = 8) + @CsvBindByPosition(position = 2) private String taxCodePT; - @CsvBindByPosition(position = 9) + @CsvBindByPosition(position = 3) private String iban; - @CsvBindByPosition(position = 10) + @CsvBindByPosition(position = 4) private String service; - @CsvBindByPosition(position = 11) + @CsvBindByPosition(position = 5) private String syncAsyncMode; private Integer rowNumber; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java index fb859a316..58f262aae 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java @@ -7,49 +7,32 @@ public class CsvAggregateSend implements Csv { @CsvBindByPosition(position = 0) - private String description; - - @CsvBindByPosition(position = 1) - private String pec; - - @CsvBindByPosition(position = 2) private String taxCode; - @CsvBindByPosition(position = 3) + @CsvBindByPosition(position = 1) private String vatNumber; - @CsvBindByPosition(position = 4) + @CsvBindByPosition(position = 2) private String codeSDI; - @CsvBindByPosition(position = 5) - private String address; - - @CsvBindByPosition(position = 6) - private String city; - - @CsvBindByPosition(position = 7) - private String province; - - @CsvBindByPosition(position = 8) - private String ipaCode; - - @CsvBindByPosition(position = 9) + @CsvBindByPosition(position = 3) private String subunitType; - @CsvBindByPosition(position = 10) + @CsvBindByPosition(position = 4) private String subunitCode; - @CsvBindByPosition(position = 11) + @CsvBindByPosition(position = 5) private String adminAggregateName; - @CsvBindByPosition(position = 12) + @CsvBindByPosition(position = 6) private String adminAggregateSurname; - @CsvBindByPosition(position = 13) + @CsvBindByPosition(position = 7) private String adminAggregateTaxCode; - @CsvBindByPosition(position = 14) + @CsvBindByPosition(position = 8) private String adminAggregateEmail; + private Integer rowNumber; @Override public void setRowNumber(int lineNumber) { diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java index 5716ebb2a..26c4743bc 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java @@ -9,4 +9,6 @@ public interface AggregatesService { Uni validateAppIoAggregatesCsv (File file); + Uni validatePagoPaAggregatesCsv (File file); + } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java index 4bfb7b27f..eeb7accd2 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java @@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import net.jodah.expiringmap.ExpiringMap; import org.apache.commons.lang3.StringUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.jboss.logging.Logger; import org.openapi.quarkus.party_registry_proxy_json.api.AooApi; @@ -74,6 +75,10 @@ public AggregatesServiceDefault (){ public static final String ERROR_SUBUNIT_TYPE = "SubunitType non valido"; public static final String ERROR_AOO_UO = "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"; public static final String ERROR_VATNUMBER = "La partita IVA è obbligatoria"; + public static final String ERROR_TAXCODE_PT = "Codice Fiscale Partner Tecnologico è obbligatorio"; + public static final String ERROR_IBAN = "IBAN è obbligatorio"; + public static final String ERROR_SERVICE = "Servizio è obbligatorio"; + public static final String ERROR_SYNC_ASYNC_MODE = "Modalità Sincrona/Asincrona è obbligatorio"; private static final String PEC = "Pec"; @@ -93,7 +98,20 @@ public Uni validateAppIoAggregatesCsv(File file) { verifyAggregateAppIoResponse.getErrors().size())); } + @Override + public Uni validatePagoPaAggregatesCsv(File file) { + AggregatesCsv aggregatesCsv = csvService.readItemsFromCsv(file, CsvAggregatePagoPa.class); + List csvAggregates = aggregatesCsv.getCsvAggregateList(); + VerifyAggregateResponse verifyAggregatePagoPaResponse = new VerifyAggregateResponse(); + return Multi.createFrom().iterable(csvAggregates) + .onItem().transformToUniAndMerge(csvAggregatePagoPa -> checkCsvAggregatePagoPaAndFillAggregateOrErrorList(csvAggregatePagoPa, verifyAggregatePagoPaResponse)) + .collect().asList() + .replaceWith(verifyAggregatePagoPaResponse) + .onItem().invoke(() -> LOG.infof(LOG_CSV_ROWS, + verifyAggregatePagoPaResponse.getAggregates().size(), + verifyAggregatePagoPaResponse.getErrors().size())); + } private Uni checkCsvAggregateAppIoAndFillAggregateOrErrorList(CsvAggregateAppIo csvAggregateAppIo, VerifyAggregateResponse verifyAggregateAppIoResponse) { @@ -112,6 +130,22 @@ private Uni checkCsvAggregateAppIoAndFillAggregateOrErrorList(CsvAggregate .replaceWithVoid(); } + private Uni checkCsvAggregatePagoPaAndFillAggregateOrErrorList(CsvAggregatePagoPa csvAggregatePagoPa, VerifyAggregateResponse verifyAggregatePagoPaResponse) { + return checkCsvAggregatePagoPa(csvAggregatePagoPa) + .onItem().invoke(aggregateSend -> verifyAggregatePagoPaResponse.getAggregates().add(aggregateSend)) + .onFailure(ResourceNotFoundException.class) + .recoverWithUni(throwable -> { + verifyAggregatePagoPaResponse.getErrors().add(mapToErrorRow(csvAggregatePagoPa.getRowNumber(), csvAggregatePagoPa.getTaxCode(), throwable)); + return Uni.createFrom().nullItem(); + }) + .onFailure(InvalidRequestException.class) + .recoverWithUni(throwable -> { + verifyAggregatePagoPaResponse.getErrors().add(mapToErrorRow(csvAggregatePagoPa.getRowNumber(), csvAggregatePagoPa.getTaxCode(), throwable)); + return Uni.createFrom().nullItem(); + }) + .replaceWithVoid(); + } + private static RowError mapToErrorRow(Integer rowNumber, String taxCode, Throwable throwable) { return new RowError(rowNumber, taxCode, throwable.getMessage()); } @@ -121,10 +155,15 @@ private Uni checkCsvAggregateAppIo(CsvAggregateAppIo csvAggregateAppI .onItem().transformToUni(unused -> retrieveDataFromIpa(onboardingMapper.csvToAggregateAppIo(csvAggregateAppIo))); } + private Uni checkCsvAggregatePagoPa(CsvAggregatePagoPa csvAggregatePagoPa) { + return checkRequiredFieldsPagoPa(csvAggregatePagoPa) + .onItem().transformToUni(unused -> retrieveDataFromIpa(onboardingMapper.csvToAggregatePagoPa(csvAggregatePagoPa))); + } + private Uni retrieveDataFromIpa(Aggregate aggregate) { aggregate.setOrigin(InstitutionResource.OriginEnum.IPA.value()); - if (Objects.isNull(aggregate.getSubunitType())){ + if (StringUtils.isEmpty(aggregate.getSubunitType())) { return institutionApi.findInstitutionUsingGET(aggregate.getTaxCode(), null, null) .onFailure(this::checkIfNotFound).recoverWithUni(Uni.createFrom().failure(new ResourceNotFoundException(ERROR_IPA))) .onItem().transformToUni(institutionResource -> retrieveCityCountyAndMapIpaFieldForPA(institutionResource, aggregate)); @@ -220,4 +259,22 @@ private Uni checkRequiredFieldsAppIo(CsvAggregateAppIo csvAggregateAppIo) } return Uni.createFrom().voidItem(); } + + private Uni checkRequiredFieldsPagoPa(CsvAggregatePagoPa csvAggregate) { + + if (StringUtils.isEmpty(csvAggregate.getTaxCode())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_TAXCODE)); + } else if (StringUtils.isEmpty(csvAggregate.getVatNumber())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_VATNUMBER)); + } else if (StringUtils.isEmpty(csvAggregate.getTaxCodePT())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_TAXCODE_PT)); + } else if (StringUtils.isEmpty(csvAggregate.getIban())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_IBAN)); + } else if (StringUtils.isEmpty(csvAggregate.getService())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_SERVICE)); + } else if (StringUtils.isEmpty(csvAggregate.getSyncAsyncMode())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_SYNC_ASYNC_MODE)); + } + return Uni.createFrom().voidItem(); + } } diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java index 89ac6a37a..7723829a4 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java @@ -47,4 +47,24 @@ void verifyAggregatesCsv_succeeds() { .validateAppIoAggregatesCsv(any()); } + + @TestSecurity(user = "userJwt") + @Test + void verifyAggregatesSendCsv_succeeds() { + File testFile = new File("src/test/resources/aggregates-pagopa.csv"); + + when(aggregatesService.validatePagoPaAggregatesCsv(any())) + .thenReturn(Uni.createFrom().item(new VerifyAggregateResponse())); + + given() + .when() + .contentType(ContentType.MULTIPART) + .multiPart("aggregates", testFile) + .post("/verification/prod-pagopa") + .then() + .statusCode(200); + + verify(aggregatesService, times(1)) + .validatePagoPaAggregatesCsv(any()); + } } diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPaTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPaTest.java new file mode 100644 index 000000000..37dc53809 --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregatePagoPaTest.java @@ -0,0 +1,56 @@ +package it.pagopa.selfcare.onboarding.model; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class CsvAggregatePagoPaTest { + + @Test + void testCsvAggregatePagoPaConstructorAndGetters() { + String taxCode = "PAGOTAX12345"; + String vatNumber = "PAGOVAT12345678"; + String taxCodePT = "PTTAXCODE123"; + String iban = "IT60X0542811101000000123456"; + String service = "PagoPa Service"; + String syncAsyncMode = "SYNC"; + Integer rowNumber = 2; + + CsvAggregatePagoPa csvAggregatePagoPa = new CsvAggregatePagoPa(); + csvAggregatePagoPa.setTaxCode(taxCode); + csvAggregatePagoPa.setVatNumber(vatNumber); + csvAggregatePagoPa.setIban(iban); + csvAggregatePagoPa.setService(service); + csvAggregatePagoPa.setSyncAsyncMode(syncAsyncMode); + csvAggregatePagoPa.setRowNumber(rowNumber); + csvAggregatePagoPa.setTaxCodePT(taxCodePT); + + assertEquals(taxCode, csvAggregatePagoPa.getTaxCode()); + assertEquals(vatNumber, csvAggregatePagoPa.getVatNumber()); + assertEquals(taxCodePT, csvAggregatePagoPa.getTaxCodePT()); + assertEquals(iban, csvAggregatePagoPa.getIban()); + assertEquals(service, csvAggregatePagoPa.getService()); + assertEquals(syncAsyncMode, csvAggregatePagoPa.getSyncAsyncMode()); + assertEquals(rowNumber, csvAggregatePagoPa.getRowNumber()); + } + + @Test + void testSetRowNumber() { + CsvAggregatePagoPa csvAggregatePagoPa = new CsvAggregatePagoPa(); + int expectedRowNumber = 15; + + csvAggregatePagoPa.setRowNumber(expectedRowNumber); + + assertEquals(expectedRowNumber, csvAggregatePagoPa.getRowNumber()); + } + + @Test + void testCsvBindByPositionAnnotations() { + CsvAggregatePagoPa csvAggregatePagoPa = new CsvAggregatePagoPa(); + csvAggregatePagoPa.setTaxCode("TESTTAXCODE"); + csvAggregatePagoPa.setIban("IT60X0542811101000000123456"); + + assertNotNull(csvAggregatePagoPa); + assertEquals("TESTTAXCODE", csvAggregatePagoPa.getTaxCode()); + assertEquals("IT60X0542811101000000123456", csvAggregatePagoPa.getIban()); + } +} diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java index 76b486120..a4b2703cf 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java @@ -128,6 +128,47 @@ void testValidateAppIoAggregatesCsv() { } + @Test + void testValidatePagoPaAggregatesCsv() { + + File file = new File("src/test/resources/aggregates-pagopa.csv"); + + WebClientApplicationException webClientApplicationException = mock(WebClientApplicationException.class); + Response response = mock(Response.class); + when(webClientApplicationException.getResponse()).thenReturn(response); + when(response.getStatus()).thenReturn(404); + + InstitutionResource institutionResource = mock(InstitutionResource.class); + when(institutionResource.getIstatCode()).thenReturn("789"); + when(institutionResource.getOriginId()).thenReturn("test"); + when(institutionResource.getDigitalAddress()).thenReturn("pec@Pec"); + + GeographicTaxonomyResource geographicTaxonomyResource = new GeographicTaxonomyResource(); + geographicTaxonomyResource.setCode("789"); + geographicTaxonomyResource.setDesc("città"); + geographicTaxonomyResource.setProvinceAbbreviation("Provincia"); + + VerifyAggregateResponse verifiyAggregateResponse = mockPagoPaResponse(); + when(institutionApi.findInstitutionUsingGET("12345678901", null, null)).thenReturn(Uni.createFrom().item(institutionResource)); + when(institutionApi.findInstitutionUsingGET("12345901", null, null)).thenReturn(Uni.createFrom().failure(webClientApplicationException)); + when(geographicTaxonomiesApi.retrieveGeoTaxonomiesByCodeUsingGET("789")).thenReturn(Uni.createFrom().item(geographicTaxonomyResource)); + + UniAssertSubscriber resp = aggregatesServiceDefault.validatePagoPaAggregatesCsv(file) + .subscribe().withSubscriber(UniAssertSubscriber.create()) + .assertCompleted(); + + Assertions.assertEquals(1, resp.getItem().getAggregates().size()); + Assertions.assertEquals(verifiyAggregateResponse.getAggregates().get(0), resp.getItem().getAggregates().get(0)); + Assertions.assertEquals(7, resp.getItem().getErrors().size()); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(0), resp.getItem().getErrors().get(0)); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(1), resp.getItem().getErrors().get(1)); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(2), resp.getItem().getErrors().get(2)); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(3), resp.getItem().getErrors().get(3)); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(4), resp.getItem().getErrors().get(4)); + Assertions.assertEquals(verifiyAggregateResponse.getErrors().get(5), resp.getItem().getErrors().get(5)); + + } + private static VerifyAggregateResponse mockResponseForIO() { VerifyAggregateResponse verifyAggregateResponse = new VerifyAggregateResponse(); Aggregate aggregateUO = new Aggregate(); @@ -184,4 +225,39 @@ private static VerifyAggregateResponse mockResponseForIO() { verifyAggregateResponse.setErrors(List.of(error0, error1,error4,error2, error3)); return verifyAggregateResponse; } + + private VerifyAggregateResponse mockPagoPaResponse() { + VerifyAggregateResponse verifyAggregateResponse = new VerifyAggregateResponse(); + Aggregate aggregate = new Aggregate(); + aggregate.setSubunitCode(null); + aggregate.setSubunitType(null); + aggregate.setDescription(null); + aggregate.setDigitalAddress("pec@Pec"); + aggregate.setTaxCode("12345678901"); + aggregate.setVatNumber("12345678901"); + aggregate.setAddress(null); + aggregate.setCity("città"); + aggregate.setCounty("Provincia"); + aggregate.setZipCode(null); + aggregate.setOriginId(null); + aggregate.setOrigin("IPA"); + aggregate.setOriginId("test"); + aggregate.setService("XXXXXXX"); + aggregate.setIban("IT60 X054 2811 1010 0000 0123 456"); + aggregate.setSyncAsyncMode("Sincrona"); + aggregate.setTaxCodePT("98765432101"); + aggregate.setRowNumber(1); + + verifyAggregateResponse.setAggregates(List.of(aggregate)); + + RowError error0 = new RowError(2,null, "Il codice fiscale è obbligatorio"); + RowError error1 = new RowError(3,"12345678901","La partita IVA è obbligatoria"); + RowError error2 = new RowError(4,"12345678901","Codice Fiscale Partner Tecnologico è obbligatorio"); + RowError error3 = new RowError(5,"12345678901","IBAN è obbligatorio"); + RowError error4 = new RowError(6,"12345678901","Servizio è obbligatorio"); + RowError error5 = new RowError(7,"12345678901","Modalità Sincrona/Asincrona è obbligatorio"); + + verifyAggregateResponse.setErrors(List.of(error0, error1,error2,error3, error4, error5)); + return verifyAggregateResponse; + } } diff --git a/apps/onboarding-ms/src/test/resources/aggregates-pagopa.csv b/apps/onboarding-ms/src/test/resources/aggregates-pagopa.csv index 96347c38d..686b40e65 100644 --- a/apps/onboarding-ms/src/test/resources/aggregates-pagopa.csv +++ b/apps/onboarding-ms/src/test/resources/aggregates-pagopa.csv @@ -1,2 +1,10 @@ -Ragione Sociale*;PEC*;Codice Fiscale*;P.IVA*;Sede legale - Indirizzo*;Sede legale - Città*;Sede legale - Provincia (sigla)*;Ragine Sociale Partner Tecnologico*;Codice Fiscale Partner Tecnologico*;IBAN*;Servizio*;Modalità Sincrona/Asincrona* -Acme srl.;acme@pec.aruba.it;12345678901;12345678901;Via Roma, 12;Bologna;BO;MyPartnerTech;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona +Codice Fiscale*;P.IVA*;Codice Fiscale Partner Tecnologico*;IBAN*;Servizio*;Modalit� Sincrona/Asincrona* +12345678901;12345678901;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona +;12345678901;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona +12345678901;;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona +12345678901;12345678901;;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona +12345678901;12345678901;98765432101;;XXXXXXX;Sincrona +12345678901;12345678901;98765432101;IT60 X054 2811 1010 0000 0123 456;;Sincrona +12345678901;12345678901;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX; +12345901;12345678901;98765432101;IT60 X054 2811 1010 0000 0123 456;XXXXXXX;Sincrona + diff --git a/apps/onboarding-ms/src/test/resources/aggregates-send.csv b/apps/onboarding-ms/src/test/resources/aggregates-send.csv index c8baf22de..52e25ab91 100644 --- a/apps/onboarding-ms/src/test/resources/aggregates-send.csv +++ b/apps/onboarding-ms/src/test/resources/aggregates-send.csv @@ -1,4 +1,15 @@ -Ragione Sociale*;PEC*;Codice Fiscale*;P.IVA*;Codice SDI*;Sede legale - Indirizzo*;Sede legale - Città*;Sede legale - Provincia (sigla)*;Codice IPA***;AOO/UO**;Codice Univoco**;Nome Amministratore Ente Aggregato*;Cognome Amministratore Ente Aggregato*;Codice Fiscale Amministratore Ente Aggregato*;email Amministratore Ente Aggregato* -Ufficio centrale di fatturazione;protocollo.rivalta@cert.legalmail.it;1864440019;1864440019;NYJTPK;Via Balma , 5;Rivalta di Torino;TO;;UO;NYJTPK;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it -(**) campo obbligatorio in caso di AOO/UO;;;;;;;;;;;;;; -(***) campo obbligatorio in caso di Ente Centrale;;;;;;;;;;;;;; +Codice Fiscale*;P.IVA*;Codice SDI*;AOO/UO**;Codice Univoco**;Nome Amministratore Ente Aggregato*;Cognome Amministratore Ente Aggregato*;Codice Fiscale Amministratore Ente Aggregato*;email Amministratore Ente Aggregato* +1307110484;1864440019;NYJTPK;UO;18SU3R;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;UOO;18SU3R;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;UO;18SU3R;Mario;Rossi;RSSMRA66A01H501W; +1307110484;1864440019;NYJTPK;UO;18SU3R;Mario;Rossi;;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;UO;18SU3R;Mario;;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;;NYJTPK;UO;18SU3R;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;;NYJTPK;UO;18SU3R;;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;UO;;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;AOO;18SU3S;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;AOO;18SU3R;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;;;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +;;;;;Mario;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it +1307110484;1864440019;NYJTPK;;;;Rossi;RSSMRA66A01H501W;mario.rossi@acme.it + From bfbded3d77124828cb19d8ff4641e84ac0ba4b73 Mon Sep 17 00:00:00 2001 From: flaminiaScarciofolo <113031535+flaminiaScarciofolo@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:57:04 +0200 Subject: [PATCH 04/27] [SELC-5680] Feat: Refactor API to verify csv for SEND (#528) --- apps/onboarding-ms/src/main/docs/openapi.json | 76 +++++++- apps/onboarding-ms/src/main/docs/openapi.yaml | 55 +++++- .../controller/AggregatesController.java | 13 ++ .../request/AggregateInstitutionRequest.java | 2 +- .../entity/AggregateInstitution.java | 2 +- .../onboarding/mapper/OnboardingMapper.java | 12 ++ .../selfcare/onboarding/model/Aggregate.java | 4 + .../onboarding/model/CsvAggregateSend.java | 2 +- .../onboarding/service/AggregatesService.java | 2 + .../service/AggregatesServiceDefault.java | 74 +++++++- .../src/main/resources/application.properties | 1 + .../controller/AggregatesControllerTest.java | 22 ++- .../mapper/OnboardingMapperTest.java | 15 ++ .../model/CsvAggregateSendTest.java | 66 +++++++ ...teAppIoTest.java => CsvAggregateTest.java} | 0 .../service/AggregatesServiceDefaultTest.java | 175 ++++++++++++++++-- .../src/test/resources/application.properties | 2 +- 17 files changed, 493 insertions(+), 30 deletions(-) create mode 100644 apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSendTest.java rename apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/{CsvAggregateAppIoTest.java => CsvAggregateTest.java} (100%) diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index bd80f97b9..e9e3445f7 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -115,6 +115,51 @@ } ] } }, + "/v1/aggregates/verification/prod-pn" : { + "post" : { + "tags" : [ "Aggregates Controller" ], + "summary" : "Validate the data related to the aggregated entities present in a CSV file", + "description" : "Validates aggregated entity data specific to the PROD-PN environment by processing the provided CSV file. This ensures that all entries meet the required criteria before further processing.", + "operationId" : "verifySendAggregatesCsv", + "requestBody" : { + "content" : { + "multipart/form-data" : { + "schema" : { + "required" : [ "aggregates" ], + "type" : "object", + "properties" : { + "aggregates" : { + "format" : "binary", + "type" : "string" + } + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/VerifyAggregateResponse" + } + } + } + }, + "401" : { + "description" : "Not Authorized" + }, + "403" : { + "description" : "Not Allowed" + } + }, + "security" : [ { + "SecurityScheme" : [ ] + } ] + } + }, "/v1/notification/resend" : { "post" : { "tags" : [ "Notification Controller" ], @@ -1409,6 +1454,15 @@ "description" : { "type" : "string" }, + "recipientCode" : { + "type" : "string" + }, + "users" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/AggregateUser" + } + }, "digitalAddress" : { "type" : "string" }, @@ -1497,7 +1551,7 @@ "$ref" : "#/components/schemas/UserRequest" } }, - "codeSDI" : { + "recipientCode" : { "type" : "string" }, "digitalAddress" : { @@ -1523,6 +1577,26 @@ } } }, + "AggregateUser" : { + "type" : "object", + "properties" : { + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + }, + "taxCode" : { + "type" : "string" + }, + "email" : { + "type" : "string" + }, + "role" : { + "type" : "string" + } + } + }, "BillingPaRequest" : { "type" : "object", "properties" : { diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index ffa08a24a..0a11fe1d2 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -84,6 +84,40 @@ paths: description: Not Allowed security: - SecurityScheme: [] + /v1/aggregates/verification/prod-pn: + post: + tags: + - Aggregates Controller + summary: Validate the data related to the aggregated entities present in a CSV + file + description: Validates aggregated entity data specific to the PROD-PN environment + by processing the provided CSV file. This ensures that all entries meet the + required criteria before further processing. + operationId: verifySendAggregatesCsv + requestBody: + content: + multipart/form-data: + schema: + required: + - aggregates + type: object + properties: + aggregates: + format: binary + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyAggregateResponse" + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] /v1/notification/resend: post: tags: @@ -1033,6 +1067,12 @@ components: type: string description: type: string + recipientCode: + type: string + users: + type: array + items: + $ref: "#/components/schemas/AggregateUser" digitalAddress: type: string taxCode: @@ -1094,7 +1134,7 @@ components: type: array items: $ref: "#/components/schemas/UserRequest" - codeSDI: + recipientCode: type: string digitalAddress: type: string @@ -1110,6 +1150,19 @@ components: type: string syncAsyncMode: type: string + AggregateUser: + type: object + properties: + name: + type: string + surname: + type: string + taxCode: + type: string + email: + type: string + role: + type: string BillingPaRequest: type: object properties: diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java index 0065de5e7..0d4c538a1 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java @@ -50,5 +50,18 @@ public Uni verifyPagoPaAggregatesCsv(@NotNull @RestForm return aggregatesService.validatePagoPaAggregatesCsv(file); } + @Operation( + summary = "Validate the data related to the aggregated entities present in a CSV file", + description = "Validates aggregated entity data specific to the PROD-PN environment by processing the provided CSV file. This ensures that all entries meet the required criteria before further processing." + ) + @POST + @Path("/verification/prod-pn") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Uni verifySendAggregatesCsv(@NotNull @RestForm("aggregates") File file){ + + return aggregatesService.validateSendAggregatesCsv(file); + } + } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/AggregateInstitutionRequest.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/AggregateInstitutionRequest.java index 683871381..ed61f7396 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/AggregateInstitutionRequest.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/request/AggregateInstitutionRequest.java @@ -26,7 +26,7 @@ public class AggregateInstitutionRequest { private Origin origin; private List users; - private String codeSDI; + private String recipientCode; private String digitalAddress; private String city; private String county; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java index 0cca8322e..2b44ef696 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java @@ -21,7 +21,7 @@ public class AggregateInstitution { private String vatNumber; private List users; - private String codeSDI; + private String recipientCode; private String digitalAddress; private String city; private String county; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java index 1ee781395..1e299177c 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapper.java @@ -118,6 +118,18 @@ default OffsetDateTime toOffsetDateTime(java.time.LocalDateTime localDateTime) { Aggregate csvToAggregatePagoPa(CsvAggregatePagoPa csvAggregatePagoPa); + @Mapping(target = "users", source = ".") + Aggregate csvToAggregateSend(CsvAggregateSend csvAggregateSend); + + default List mapCsvSendAggregatesToAggregates(List csvAggregateSendList) { + if (csvAggregateSendList == null) { + return null; + } + return csvAggregateSendList.stream() + .map(this::csvToAggregateSend) + .collect(Collectors.toList()); + } + default List mapCsvAppIoAggregatesToAggregates(List csvAggregateAppIoList) { if (csvAggregateAppIoList == null) { return Collections.emptyList(); diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java index e4cf09498..6ee2efd5c 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/Aggregate.java @@ -3,11 +3,15 @@ import lombok.Data; import wiremock.com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + @Data public class Aggregate { private String subunitCode; private String subunitType; private String description; + private String recipientCode; + private List users; private String digitalAddress; private String taxCode; private String vatNumber; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java index 58f262aae..df43ab61f 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSend.java @@ -13,7 +13,7 @@ public class CsvAggregateSend implements Csv { private String vatNumber; @CsvBindByPosition(position = 2) - private String codeSDI; + private String recipientCode; @CsvBindByPosition(position = 3) private String subunitType; diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java index 26c4743bc..2b70006ec 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java @@ -11,4 +11,6 @@ public interface AggregatesService { Uni validatePagoPaAggregatesCsv (File file); + Uni validateSendAggregatesCsv (File file); + } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java index eeb7accd2..e8feb255a 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java @@ -62,9 +62,10 @@ public class AggregatesServiceDefault implements AggregatesService { private final ExpiringMap expiringMap; - public AggregatesServiceDefault (){ + @Inject + public AggregatesServiceDefault(@ConfigProperty(name = "onboarding-ms.istat-cache-duration-minutes") int cacheDuration) { this.expiringMap = ExpiringMap.builder() - .expiration(30, TimeUnit.MINUTES) + .expiration(cacheDuration, TimeUnit.MINUTES) .build(); } @@ -75,10 +76,15 @@ public AggregatesServiceDefault (){ public static final String ERROR_SUBUNIT_TYPE = "SubunitType non valido"; public static final String ERROR_AOO_UO = "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"; public static final String ERROR_VATNUMBER = "La partita IVA è obbligatoria"; + public static final String ERROR_ADMIN_NAME = "Nome Amministratore Ente Aggregato è obbligatorio"; + public static final String ERROR_ADMIN_SURNAME = "Cognome Amministratore Ente Aggregato è obbligatorio"; + public static final String ERROR_ADMIN_EMAIL = "Email Amministratore Ente Aggregato è obbligatorio"; + public static final String ERROR_ADMIN_TAXCODE = "Codice Fiscale Amministratore Ente Aggregato è obbligatorio"; public static final String ERROR_TAXCODE_PT = "Codice Fiscale Partner Tecnologico è obbligatorio"; public static final String ERROR_IBAN = "IBAN è obbligatorio"; public static final String ERROR_SERVICE = "Servizio è obbligatorio"; public static final String ERROR_SYNC_ASYNC_MODE = "Modalità Sincrona/Asincrona è obbligatorio"; + public static final String ERROR_CODICE_SDI = "Codice SDI è obbligatorio"; private static final String PEC = "Pec"; @@ -113,6 +119,21 @@ public Uni validatePagoPaAggregatesCsv(File file) { verifyAggregatePagoPaResponse.getErrors().size())); } + @Override + public Uni validateSendAggregatesCsv(File file) { + AggregatesCsv aggregatesCsv = csvService.readItemsFromCsv(file, CsvAggregateSend.class); + List csvAggregates = aggregatesCsv.getCsvAggregateList(); + VerifyAggregateResponse verifyAggregateSendResponse = new VerifyAggregateResponse(); + + return Multi.createFrom().iterable(csvAggregates) + .onItem().transformToUniAndMerge(csvAggregateSend -> checkCsvAggregateSendAndFillAggregateOrErrorList(csvAggregateSend, verifyAggregateSendResponse)) + .collect().asList() + .replaceWith(verifyAggregateSendResponse) + .onItem().invoke(() -> LOG.infof(LOG_CSV_ROWS, + verifyAggregateSendResponse.getAggregates().size(), + verifyAggregateSendResponse.getErrors().size())); + } + private Uni checkCsvAggregateAppIoAndFillAggregateOrErrorList(CsvAggregateAppIo csvAggregateAppIo, VerifyAggregateResponse verifyAggregateAppIoResponse) { return checkCsvAggregateAppIo(csvAggregateAppIo) @@ -146,6 +167,22 @@ private Uni checkCsvAggregatePagoPaAndFillAggregateOrErrorList(CsvAggregat .replaceWithVoid(); } + private Uni checkCsvAggregateSendAndFillAggregateOrErrorList(CsvAggregateSend csvAggregateSend, VerifyAggregateResponse verifyAggregateSendResponse) { + return checkCsvAggregateSend(csvAggregateSend) + .onItem().invoke(aggregateSend -> verifyAggregateSendResponse.getAggregates().add(aggregateSend)) + .onFailure(ResourceNotFoundException.class) + .recoverWithUni(throwable -> { + verifyAggregateSendResponse.getErrors().add(mapToErrorRow(csvAggregateSend.getRowNumber(), csvAggregateSend.getTaxCode(), throwable)); + return Uni.createFrom().nullItem(); + }) + .onFailure(InvalidRequestException.class) + .recoverWithUni(throwable -> { + verifyAggregateSendResponse.getErrors().add(mapToErrorRow(csvAggregateSend.getRowNumber(), csvAggregateSend.getTaxCode(), throwable)); + return Uni.createFrom().nullItem(); + }) + .replaceWithVoid(); + } + private static RowError mapToErrorRow(Integer rowNumber, String taxCode, Throwable throwable) { return new RowError(rowNumber, taxCode, throwable.getMessage()); } @@ -155,6 +192,11 @@ private Uni checkCsvAggregateAppIo(CsvAggregateAppIo csvAggregateAppI .onItem().transformToUni(unused -> retrieveDataFromIpa(onboardingMapper.csvToAggregateAppIo(csvAggregateAppIo))); } + private Uni checkCsvAggregateSend(CsvAggregateSend csvAggregateSend) { + return checkRequiredFieldsSend(csvAggregateSend) + .onItem().transformToUni(unused -> retrieveDataFromIpa(onboardingMapper.csvToAggregateSend(csvAggregateSend))); + } + private Uni checkCsvAggregatePagoPa(CsvAggregatePagoPa csvAggregatePagoPa) { return checkRequiredFieldsPagoPa(csvAggregatePagoPa) .onItem().transformToUni(unused -> retrieveDataFromIpa(onboardingMapper.csvToAggregatePagoPa(csvAggregatePagoPa))); @@ -185,7 +227,7 @@ private Uni retrieveDataFromIpa(Aggregate aggregate) { private Uni retrieveCityCountyAndMapIpaFieldForUO(UOResource uoResource, Aggregate aggregateAppIo) { return retrieveGeographicTaxonomies(uoResource.getCodiceComuneISTAT()) .onItem().transformToUni(geographicTaxonomyResource -> { - mapIpaField(uoResource.getDenominazioneEnte(), uoResource.getIndirizzo(), uoResource.getCap(), null, aggregateAppIo, geographicTaxonomyResource); + mapIpaField(uoResource.getDescrizioneUo(), uoResource.getIndirizzo(), uoResource.getCap(), null, aggregateAppIo, geographicTaxonomyResource); return retrieveDigitalAddress(uoResource.getTipoMail1(), uoResource.getMail1(), uoResource.getCodiceFiscaleEnte(), aggregateAppIo); }); } @@ -193,7 +235,7 @@ private Uni retrieveCityCountyAndMapIpaFieldForUO(UOResource uoResour private Uni retrieveCityCountyAndMapIpaFieldForAOO(AOOResource aooResource, Aggregate aggregateAppIo) { return retrieveGeographicTaxonomies(aooResource.getCodiceComuneISTAT()) .onItem().transformToUni(geographicTaxonomyResource -> { - mapIpaField(aooResource.getDenominazioneEnte(), aooResource.getIndirizzo(), aooResource.getCap(), null, aggregateAppIo, geographicTaxonomyResource); + mapIpaField(aooResource.getDenominazioneAoo(), aooResource.getIndirizzo(), aooResource.getCap(), null, aggregateAppIo, geographicTaxonomyResource); return retrieveDigitalAddress(aooResource.getTipoMail1(), aooResource.getMail1(), aooResource.getCodiceFiscaleEnte(), aggregateAppIo); }); } @@ -277,4 +319,28 @@ private Uni checkRequiredFieldsPagoPa(CsvAggregatePagoPa csvAggregate) { } return Uni.createFrom().voidItem(); } + + private Uni checkRequiredFieldsSend(CsvAggregateSend csvAggregate) { + + if (StringUtils.isEmpty(csvAggregate.getTaxCode())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_TAXCODE)); + } else if (StringUtils.isEmpty(csvAggregate.getVatNumber())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_VATNUMBER)); + } else if ((StringUtils.isEmpty(csvAggregate.getSubunitType()) && StringUtils.isNotEmpty(csvAggregate.getSubunitCode())) + || (StringUtils.isNotEmpty(csvAggregate.getSubunitType()) && StringUtils.isEmpty(csvAggregate.getSubunitCode()))) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_AOO_UO)); + } else if (StringUtils.isEmpty(csvAggregate.getAdminAggregateName())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_ADMIN_NAME)); + } else if (StringUtils.isEmpty(csvAggregate.getAdminAggregateSurname())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_ADMIN_SURNAME)); + } else if (StringUtils.isEmpty(csvAggregate.getAdminAggregateTaxCode())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_ADMIN_TAXCODE)); + } else if (StringUtils.isEmpty(csvAggregate.getAdminAggregateEmail())) { + return Uni.createFrom().failure(new InvalidRequestException(ERROR_ADMIN_EMAIL)); + } else if(StringUtils.isEmpty(csvAggregate.getRecipientCode())){ + return Uni.createFrom().failure(new InvalidRequestException(ERROR_CODICE_SDI)); + + } + return Uni.createFrom().voidItem(); + } } diff --git a/apps/onboarding-ms/src/main/resources/application.properties b/apps/onboarding-ms/src/main/resources/application.properties index 245639580..46fd9e314 100644 --- a/apps/onboarding-ms/src/main/resources/application.properties +++ b/apps/onboarding-ms/src/main/resources/application.properties @@ -80,6 +80,7 @@ quarkus.rest-client."org.openapi.quarkus.core_json.api.InstitutionApi".read-time mp.openapi.extensions.smallrye.operationIdStrategy=METHOD +onboarding-ms.istat-cache-duration-minutes=${ISTAT_CACHE_DURATION_MIN:30} ## AZURE STORAGE ## onboarding-ms.blob-storage.container-product=${STORAGE_CONTAINER_PRODUCT:selc-d-product} diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java index 7723829a4..da17629b5 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java @@ -47,10 +47,30 @@ void verifyAggregatesCsv_succeeds() { .validateAppIoAggregatesCsv(any()); } - @TestSecurity(user = "userJwt") @Test void verifyAggregatesSendCsv_succeeds() { + File testFile = new File("src/test/resources/aggregates-send.csv"); + + when(aggregatesService.validateSendAggregatesCsv(any())) + .thenReturn(Uni.createFrom().item(new VerifyAggregateResponse())); + + given() + .when() + .contentType(ContentType.MULTIPART) + .multiPart("aggregates", testFile) + .post("/verification/prod-pn") + .then() + .statusCode(200); + + verify(aggregatesService, times(1)) + .validateSendAggregatesCsv(any()); + } + + + @TestSecurity(user = "userJwt") + @Test + void verifyAggregatesPagoPaCsv_succeeds() { File testFile = new File("src/test/resources/aggregates-pagopa.csv"); when(aggregatesService.validatePagoPaAggregatesCsv(any())) diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapperTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapperTest.java index 83b196119..9bba175d9 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapperTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/mapper/OnboardingMapperTest.java @@ -119,6 +119,21 @@ void mapCsvAppIoAggregateToAggregates_withNullList_returnsEmptyList() { assertTrue(result.isEmpty()); } + @Test + void mapCsvSendAggregateToAggregates_withValidList_returnsMappedList() { + List input = List.of(new CsvAggregateSend()); + List result = mapper.mapCsvSendAggregatesToAggregates(input); + assertNotNull(result); + assertEquals(1, result.size()); + } + + @Test + void mapCsvSendAggregateToAggregates_withNullList_returnsNull() { + List input = null; + List result = mapper.mapCsvSendAggregatesToAggregates(input); + assertNull(result); + } + @Test void mapUsers_withValidCsvAggregateSend_returnsMappedUserList() { CsvAggregateSend input = new CsvAggregateSend(); diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSendTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSendTest.java new file mode 100644 index 000000000..04e0e0d6b --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateSendTest.java @@ -0,0 +1,66 @@ +package it.pagopa.selfcare.onboarding.model; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class CsvAggregateSendTest { + + @Test + void testCsvAggregateSendConstructorAndGetters() { + String taxCode = "TAX12345"; + String vatNumber = "VAT12345678"; + String recipientCode = "SDI123456"; + String subunitType = "Department"; + String subunitCode = "DEP001"; + String adminAggregateName = "Admin Name"; + String adminAggregateSurname = "Admin Surname"; + String adminAggregateTaxCode = "ADMIN12345"; + String adminAggregateEmail = "admin@example.com"; + Integer rowNumber = 5; + + CsvAggregateSend csvAggregateSend = new CsvAggregateSend(); + csvAggregateSend.setTaxCode(taxCode); + csvAggregateSend.setVatNumber(vatNumber); + csvAggregateSend.setRecipientCode(recipientCode); + csvAggregateSend.setSubunitType(subunitType); + csvAggregateSend.setSubunitCode(subunitCode); + csvAggregateSend.setAdminAggregateName(adminAggregateName); + csvAggregateSend.setAdminAggregateSurname(adminAggregateSurname); + csvAggregateSend.setAdminAggregateTaxCode(adminAggregateTaxCode); + csvAggregateSend.setAdminAggregateEmail(adminAggregateEmail); + csvAggregateSend.setRowNumber(rowNumber); + + + assertEquals(taxCode, csvAggregateSend.getTaxCode()); + assertEquals(vatNumber, csvAggregateSend.getVatNumber()); + assertEquals(recipientCode, csvAggregateSend.getRecipientCode()); + assertEquals(subunitType, csvAggregateSend.getSubunitType()); + assertEquals(subunitCode, csvAggregateSend.getSubunitCode()); + assertEquals(adminAggregateName, csvAggregateSend.getAdminAggregateName()); + assertEquals(adminAggregateSurname, csvAggregateSend.getAdminAggregateSurname()); + assertEquals(adminAggregateTaxCode, csvAggregateSend.getAdminAggregateTaxCode()); + assertEquals(adminAggregateEmail, csvAggregateSend.getAdminAggregateEmail()); + assertEquals(rowNumber, csvAggregateSend.getRowNumber()); + } + + @Test + void testSetRowNumber() { + CsvAggregateSend csvAggregateSend = new CsvAggregateSend(); + int expectedRowNumber = 10; + + csvAggregateSend.setRowNumber(expectedRowNumber); + + assertEquals(expectedRowNumber, csvAggregateSend.getRowNumber()); + } + + @Test + void testCsvBindByPositionAnnotations() { + CsvAggregateSend csvAggregateSend = new CsvAggregateSend(); + csvAggregateSend.setTaxCode("SAMPLETAXCODE"); + csvAggregateSend.setAdminAggregateEmail("admin@example.com"); + + assertNotNull(csvAggregateSend); + assertEquals("SAMPLETAXCODE", csvAggregateSend.getTaxCode()); + assertEquals("admin@example.com", csvAggregateSend.getAdminAggregateEmail()); + } +} diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateAppIoTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateTest.java similarity index 100% rename from apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateAppIoTest.java rename to apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/model/CsvAggregateTest.java diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java index a4b2703cf..bcc6660e8 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java @@ -8,6 +8,7 @@ import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; import it.pagopa.selfcare.onboarding.model.Aggregate; +import it.pagopa.selfcare.onboarding.model.AggregateUser; import it.pagopa.selfcare.onboarding.model.RowError; import it.pagopa.selfcare.onboarding.model.VerifyAggregateResponse; import it.pagopa.selfcare.onboarding.service.profile.OnboardingTestProfile; @@ -71,7 +72,7 @@ void testValidateAppIoAggregatesCsv() { uoResource.setTipoMail1("Pec"); uoResource.setCodiceUniAoo("18SU3S"); uoResource.setCap("00100"); - uoResource.setDenominazioneEnte("denominazione"); + uoResource.setDescrizioneUo("denominazione"); uoResource.setIndirizzo("Palazzo Vecchio Piazza Della Signoria"); uoResource.setCodiceComuneISTAT("123"); @@ -79,7 +80,7 @@ void testValidateAppIoAggregatesCsv() { aooResource.setTipoMail1("Altro"); aooResource.setMail1("pec@Pec"); aooResource.setCodiceUniAoo("18SU3S"); - aooResource.setDenominazioneEnte("denominazione"); + aooResource.setDenominazioneAoo("denominazione"); aooResource.setCap("00100"); aooResource.setCodiceFiscaleEnte("1307110484"); aooResource.setIndirizzo("Palazzo Vecchio Piazza Della Signoria"); @@ -121,10 +122,10 @@ void testValidateAppIoAggregatesCsv() { Assertions.assertEquals(verifyAggregateResponse.getErrors().get(2), resp.getItem().getErrors().get(2)); Assertions.assertEquals(verifyAggregateResponse.getErrors().get(3), resp.getItem().getErrors().get(3)); - verify(geographicTaxonomiesApi,times(1)).retrieveGeoTaxonomiesByCodeUsingGET("123"); - verify(aooApi,times(1)).findByUnicodeUsingGET("18SU3R", null); - verify(aooApi,times(1)).findByUnicodeUsingGET("18SU3S", null); - verify(institutionApi,times(2)).findInstitutionUsingGET("1307110484", null, null); + verify(geographicTaxonomiesApi, times(1)).retrieveGeoTaxonomiesByCodeUsingGET("123"); + verify(aooApi, times(1)).findByUnicodeUsingGET("18SU3R", null); + verify(aooApi, times(1)).findByUnicodeUsingGET("18SU3S", null); + verify(institutionApi, times(2)).findInstitutionUsingGET("1307110484", null, null); } @@ -169,6 +170,71 @@ void testValidatePagoPaAggregatesCsv() { } + @Test + @RunOnVertxContext + void validateSendAggregates() { + + File file = new File("src/test/resources/aggregates-send.csv"); + + UOResource uoResource = new UOResource(); + uoResource.setMail1("pec@Pec"); + uoResource.setTipoMail1("Pec"); + uoResource.setCodiceUniAoo("18SU3S"); + uoResource.setCap("00100"); + uoResource.setDescrizioneUo("denominazione"); + uoResource.setIndirizzo("Palazzo Vecchio Piazza Della Signoria"); + uoResource.setCodiceComuneISTAT("456"); + + AOOResource aooResource = new AOOResource(); + aooResource.setTipoMail1("Pec"); + aooResource.setMail1("pec@Pec"); + aooResource.setCodiceUniAoo("18SU3S"); + aooResource.setDenominazioneAoo("denominazione"); + aooResource.setCap("00100"); + aooResource.setIndirizzo("Palazzo Vecchio Piazza Della Signoria"); + aooResource.setCodiceComuneISTAT("456"); + + InstitutionResource institutionResource = mock(InstitutionResource.class); + when(institutionResource.getIstatCode()).thenReturn("456"); + when(institutionResource.getOriginId()).thenReturn("test"); + + GeographicTaxonomyResource geographicTaxonomyResource = new GeographicTaxonomyResource(); + geographicTaxonomyResource.setCode("456"); + geographicTaxonomyResource.setDesc("città"); + geographicTaxonomyResource.setProvinceAbbreviation("Provincia"); + + WebClientApplicationException webClientApplicationException = mock(WebClientApplicationException.class); + Response response = mock(Response.class); + when(webClientApplicationException.getResponse()).thenReturn(response); + when(response.getStatus()).thenReturn(404); + when(aooApi.findByUnicodeUsingGET("18SU3S", null)).thenReturn(Uni.createFrom().item(aooResource)); + when(aooApi.findByUnicodeUsingGET("18SU3R", null)).thenReturn(Uni.createFrom().failure(webClientApplicationException)); + when(institutionApi.findInstitutionUsingGET("1307110484", null, null)).thenReturn(Uni.createFrom().item(institutionResource)); + when(uoApi.findByUnicodeUsingGET1("18SU3R", null)).thenReturn(Uni.createFrom().item(uoResource)); + when(geographicTaxonomiesApi.retrieveGeoTaxonomiesByCodeUsingGET("456")).thenReturn(Uni.createFrom().item(geographicTaxonomyResource)); + + VerifyAggregateResponse verifyAggregateResponse = mockResponseForSEND(); + + UniAssertSubscriber resp = aggregatesServiceDefault.validateSendAggregatesCsv(file) + .subscribe().withSubscriber(UniAssertSubscriber.create()) + .assertCompleted(); + + Assertions.assertEquals(3, resp.getItem().getAggregates().size()); + Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(0), resp.getItem().getAggregates().get(0)); + Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(1), resp.getItem().getAggregates().get(1)); + Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(2), resp.getItem().getAggregates().get(2)); + Assertions.assertEquals(10, resp.getItem().getErrors().size()); + Assertions.assertEquals(verifyAggregateResponse.getErrors().get(0), resp.getItem().getErrors().get(0)); + Assertions.assertEquals(verifyAggregateResponse.getErrors().get(1), resp.getItem().getErrors().get(1)); + Assertions.assertEquals(verifyAggregateResponse.getErrors().get(2), resp.getItem().getErrors().get(2)); + Assertions.assertEquals(verifyAggregateResponse.getErrors().get(3), resp.getItem().getErrors().get(3)); + + verify(geographicTaxonomiesApi, times(1)).retrieveGeoTaxonomiesByCodeUsingGET("456"); + verify(aooApi, times(1)).findByUnicodeUsingGET("18SU3R", null); + verify(aooApi, times(1)).findByUnicodeUsingGET("18SU3S", null); + verify(institutionApi, times(0)).findInstitutionUsingGET("00297110389", null, null); + } + private static VerifyAggregateResponse mockResponseForIO() { VerifyAggregateResponse verifyAggregateResponse = new VerifyAggregateResponse(); Aggregate aggregateUO = new Aggregate(); @@ -217,12 +283,12 @@ private static VerifyAggregateResponse mockResponseForIO() { verifyAggregateResponse.setAggregates(List.of(aggregateUO, aggregateAOO, aggregate)); - RowError error0 = new RowError(2,"1307110484","SubunitType non valido"); - RowError error1 = new RowError(3,"1307110484","La partita IVA è obbligatoria"); - RowError error2 = new RowError(7,null,"Il codice fiscale è obbligatorio"); - RowError error4 = new RowError(4,"1307110484","Codice fiscale non presente su IPA"); - RowError error3 = new RowError(8,"1307110484","In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"); - verifyAggregateResponse.setErrors(List.of(error0, error1,error4,error2, error3)); + RowError error0 = new RowError(2, "1307110484", "SubunitType non valido"); + RowError error1 = new RowError(3, "1307110484", "La partita IVA è obbligatoria"); + RowError error2 = new RowError(7, null, "Il codice fiscale è obbligatorio"); + RowError error4 = new RowError(4, "1307110484", "Codice fiscale non presente su IPA"); + RowError error3 = new RowError(8, "1307110484", "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"); + verifyAggregateResponse.setErrors(List.of(error0, error1, error4, error2, error3)); return verifyAggregateResponse; } @@ -250,14 +316,85 @@ private VerifyAggregateResponse mockPagoPaResponse() { verifyAggregateResponse.setAggregates(List.of(aggregate)); - RowError error0 = new RowError(2,null, "Il codice fiscale è obbligatorio"); - RowError error1 = new RowError(3,"12345678901","La partita IVA è obbligatoria"); - RowError error2 = new RowError(4,"12345678901","Codice Fiscale Partner Tecnologico è obbligatorio"); - RowError error3 = new RowError(5,"12345678901","IBAN è obbligatorio"); - RowError error4 = new RowError(6,"12345678901","Servizio è obbligatorio"); - RowError error5 = new RowError(7,"12345678901","Modalità Sincrona/Asincrona è obbligatorio"); + RowError error0 = new RowError(2, null, "Il codice fiscale è obbligatorio"); + RowError error1 = new RowError(3, "12345678901", "La partita IVA è obbligatoria"); + RowError error2 = new RowError(4, "12345678901", "Codice Fiscale Partner Tecnologico è obbligatorio"); + RowError error3 = new RowError(5, "12345678901", "IBAN è obbligatorio"); + RowError error4 = new RowError(6, "12345678901", "Servizio è obbligatorio"); + RowError error5 = new RowError(7, "12345678901", "Modalità Sincrona/Asincrona è obbligatorio"); + + verifyAggregateResponse.setErrors(List.of(error0, error1, error2, error3, error4, error5)); + return verifyAggregateResponse; + } + + private static VerifyAggregateResponse mockResponseForSEND() { + AggregateUser aggregateUser = new AggregateUser(); + aggregateUser.setName("Mario"); + aggregateUser.setSurname("Rossi"); + aggregateUser.setTaxCode("RSSMRA66A01H501W"); + aggregateUser.setEmail("mario.rossi@acme.it"); + aggregateUser.setRole(org.openapi.quarkus.core_json.model.Person.RoleEnum.DELEGATE.name()); + + VerifyAggregateResponse verifyAggregateResponse = new VerifyAggregateResponse(); + Aggregate aggregateUO = new Aggregate(); + aggregateUO.setSubunitCode("18SU3R"); + aggregateUO.setSubunitType("UO"); + aggregateUO.setDescription("denominazione"); + aggregateUO.setDigitalAddress("pec@Pec"); + aggregateUO.setTaxCode("1307110484"); + aggregateUO.setVatNumber("1864440019"); + aggregateUO.setAddress("Palazzo Vecchio Piazza Della Signoria"); + aggregateUO.setCity("città"); + aggregateUO.setCounty("Provincia"); + aggregateUO.setZipCode("00100"); + aggregateUO.setOrigin("IPA"); + aggregateUO.setRecipientCode("NYJTPK"); + aggregateUO.setRowNumber(1); + aggregateUO.setUsers(List.of(aggregateUser)); + + Aggregate aggregateAOO = new Aggregate(); + aggregateAOO.setSubunitCode("18SU3S"); + aggregateAOO.setSubunitType("AOO"); + aggregateAOO.setDescription("denominazione"); + aggregateAOO.setDigitalAddress("pec@Pec"); + aggregateAOO.setTaxCode("1307110484"); + aggregateAOO.setVatNumber("1864440019"); + aggregateAOO.setAddress("Palazzo Vecchio Piazza Della Signoria"); + aggregateAOO.setCity("città"); + aggregateAOO.setCounty("Provincia"); + aggregateAOO.setZipCode("00100"); + aggregateAOO.setRecipientCode("NYJTPK"); + aggregateAOO.setOrigin("IPA"); + aggregateAOO.setRowNumber(9); + aggregateAOO.setUsers(List.of(aggregateUser)); + + Aggregate aggregate = new Aggregate(); + aggregate.setSubunitCode(null); + aggregate.setSubunitType(null); + aggregate.setDescription(null); + aggregate.setDigitalAddress(null); + aggregate.setTaxCode("1307110484"); + aggregate.setVatNumber("1864440019"); + aggregate.setAddress(null); + aggregate.setCity("città"); + aggregate.setCounty("Provincia"); + aggregate.setZipCode(null); + aggregate.setOriginId(null); + aggregate.setRecipientCode("NYJTPK"); + aggregate.setOrigin("IPA"); + aggregate.setOriginId("test"); + aggregate.setRowNumber(11); + aggregate.setUsers(List.of(aggregateUser)); + + + verifyAggregateResponse.setAggregates(List.of(aggregateUO, aggregateAOO, aggregate)); - verifyAggregateResponse.setErrors(List.of(error0, error1,error2,error3, error4, error5)); + RowError error0 = new RowError(2, "1307110484", "SubunitType non valido"); + RowError error1 = new RowError(3, "1307110484", "Email Amministratore Ente Aggregato è obbligatorio"); + RowError error2 = new RowError(5, "1307110484", "Cognome Amministratore Ente Aggregato è obbligatorio"); + RowError error4 = new RowError(4, "1307110484", "Codice Fiscale Amministratore Ente Aggregato è obbligatorio"); + RowError error3 = new RowError(7, "1307110484", "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"); + verifyAggregateResponse.setErrors(List.of(error0, error1, error4, error2, error3)); return verifyAggregateResponse; } } diff --git a/apps/onboarding-ms/src/test/resources/application.properties b/apps/onboarding-ms/src/test/resources/application.properties index 2f24bed44..2a59319fc 100644 --- a/apps/onboarding-ms/src/test/resources/application.properties +++ b/apps/onboarding-ms/src/test/resources/application.properties @@ -2,5 +2,5 @@ mp.jwt.verify.publickey="" mp.jwt.verify.issuer=SPID onboarding-ms.signature.verify-enabled=false -onboarding-ms.istat-cache-duration-minute=30 +onboarding-ms.istat-cache-duration-minutes=30 From 5625bdf0fe1c70f9d213100686f707bca8523077 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:29:48 +0200 Subject: [PATCH 05/27] [SELC-5564] feat: new endpoint to download aggregates csv (#525) --- apps/onboarding-ms/src/main/docs/openapi.json | 45 +++++++++++++++++++ apps/onboarding-ms/src/main/docs/openapi.yaml | 33 ++++++++++++++ .../onboarding/conf/OnboardingMsConfig.java | 3 ++ .../controller/AggregatesController.java | 13 ++++++ .../onboarding/service/AggregatesService.java | 3 ++ .../service/AggregatesServiceDefault.java | 24 +++++++++- .../src/main/resources/application.properties | 1 + .../controller/AggregatesControllerTest.java | 21 +++++++++ .../service/AggregatesServiceDefaultTest.java | 23 ++++++++++ 9 files changed, 165 insertions(+), 1 deletion(-) diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index e9e3445f7..ddb57d9e0 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -25,6 +25,51 @@ "name" : "support" } ], "paths" : { + "/v1/aggregates/csv/{onboardingId}/products/{productId}" : { + "get" : { + "tags" : [ "Aggregates Controller" ], + "summary" : "Retrieve aggregates csv for a given onboarding and product", + "description" : "Downloads the aggregates csv associated with the specified onboarding ID and product.", + "operationId" : "getAggregatesCsv", + "parameters" : [ { + "name" : "onboardingId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "productId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/octet-stream" : { + "schema" : { + "format" : "binary", + "type" : "string" + } + } + } + }, + "401" : { + "description" : "Not Authorized" + }, + "403" : { + "description" : "Not Allowed" + } + }, + "security" : [ { + "SecurityScheme" : [ ] + } ] + } + }, "/v1/aggregates/verification/prod-io" : { "post" : { "tags" : [ "Aggregates Controller" ], diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index 0a11fe1d2..3bf30d9fc 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -16,6 +16,39 @@ tags: - name: internal-v1 - name: support paths: + /v1/aggregates/csv/{onboardingId}/products/{productId}: + get: + tags: + - Aggregates Controller + summary: Retrieve aggregates csv for a given onboarding and product + description: Downloads the aggregates csv associated with the specified onboarding + ID and product. + operationId: getAggregatesCsv + parameters: + - name: onboardingId + in: path + required: true + schema: + type: string + - name: productId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK + content: + application/octet-stream: + schema: + format: binary + type: string + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] /v1/aggregates/verification/prod-io: post: tags: diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java index ca5230cdb..d2bb006d0 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/conf/OnboardingMsConfig.java @@ -29,6 +29,9 @@ public class OnboardingMsConfig { @ConfigProperty(name = "onboarding-ms.blob-storage.path-contracts") String contractPath; + @ConfigProperty(name = "onboarding-ms.blob-storage.path-aggregates") + String aggregatesPath; + void onStart(@Observes StartupEvent ev) { log.info(String.format("Database %s is starting...", Onboarding.mongoDatabase().getName())); } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java index 0d4c538a1..e0efe69d7 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/controller/AggregatesController.java @@ -12,6 +12,7 @@ import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.jboss.resteasy.reactive.RestForm; +import org.jboss.resteasy.reactive.RestResponse; import java.io.File; @@ -63,5 +64,17 @@ public Uni verifySendAggregatesCsv(@NotNull @RestForm(" return aggregatesService.validateSendAggregatesCsv(file); } + @Operation( + summary = "Retrieve aggregates csv for a given onboarding and product", + description = "Downloads the aggregates csv associated with the specified onboarding ID and product." + ) + @GET + @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Path("/csv/{onboardingId}/products/{productId}") + public Uni> getAggregatesCsv(@PathParam(value = "onboardingId") String onboardingId, + @PathParam(value = "productId") String productId){ + return aggregatesService.retrieveAggregatesCsv(onboardingId, productId); + } + } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java index 2b70006ec..a46d0336c 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesService.java @@ -2,6 +2,7 @@ import io.smallrye.mutiny.Uni; import it.pagopa.selfcare.onboarding.model.*; +import org.jboss.resteasy.reactive.RestResponse; import java.io.File; @@ -13,4 +14,6 @@ public interface AggregatesService { Uni validateSendAggregatesCsv (File file); + Uni> retrieveAggregatesCsv(String onboardingId, String productId); + } diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java index e8feb255a..ad567f6dd 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefault.java @@ -2,7 +2,9 @@ import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; import it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType; +import it.pagopa.selfcare.onboarding.conf.OnboardingMsConfig; import it.pagopa.selfcare.onboarding.exception.InvalidRequestException; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; @@ -10,12 +12,15 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; import lombok.extern.slf4j.Slf4j; import net.jodah.expiringmap.ExpiringMap; import org.apache.commons.lang3.StringUtils; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.jboss.logging.Logger; +import org.jboss.resteasy.reactive.RestResponse; 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; @@ -28,6 +33,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import static it.pagopa.selfcare.onboarding.common.InstitutionPaSubunitType.UO; @@ -60,10 +66,14 @@ public class AggregatesServiceDefault implements AggregatesService { @Inject CsvService csvService; + private final AzureBlobClient azureBlobClient; + private final OnboardingMsConfig onboardingMsConfig; private final ExpiringMap expiringMap; @Inject - public AggregatesServiceDefault(@ConfigProperty(name = "onboarding-ms.istat-cache-duration-minutes") int cacheDuration) { + public AggregatesServiceDefault(AzureBlobClient azureBlobClient, OnboardingMsConfig onboardingMsConfig, @ConfigProperty(name = "onboarding-ms.istat-cache-duration-minutes") int cacheDuration) { + this.azureBlobClient = azureBlobClient; + this.onboardingMsConfig = onboardingMsConfig; this.expiringMap = ExpiringMap.builder() .expiration(cacheDuration, TimeUnit.MINUTES) .build(); @@ -86,6 +96,7 @@ public AggregatesServiceDefault(@ConfigProperty(name = "onboarding-ms.istat-cach public static final String ERROR_SYNC_ASYNC_MODE = "Modalità Sincrona/Asincrona è obbligatorio"; public static final String ERROR_CODICE_SDI = "Codice SDI è obbligatorio"; private static final String PEC = "Pec"; + private static final String FILE_NAME_AGGREGATES_CSV = "aggregates.csv"; @Override @@ -134,6 +145,17 @@ public Uni validateSendAggregatesCsv(File file) { verifyAggregateSendResponse.getErrors().size())); } + @Override + public Uni> retrieveAggregatesCsv(String onboardingId, String productId) { + return Uni.createFrom().item(() -> azureBlobClient.getFileAsPdf(String.format("%s%s/%s/%s", onboardingMsConfig.getAggregatesPath(), onboardingId, productId, FILE_NAME_AGGREGATES_CSV))) + .runSubscriptionOn(Executors.newSingleThreadExecutor()) + .onItem().transform(csv -> { + RestResponse.ResponseBuilder response = RestResponse.ResponseBuilder.ok(csv, MediaType.APPLICATION_OCTET_STREAM); + response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + FILE_NAME_AGGREGATES_CSV); + return response.build(); + }); + } + private Uni checkCsvAggregateAppIoAndFillAggregateOrErrorList(CsvAggregateAppIo csvAggregateAppIo, VerifyAggregateResponse verifyAggregateAppIoResponse) { return checkCsvAggregateAppIo(csvAggregateAppIo) diff --git a/apps/onboarding-ms/src/main/resources/application.properties b/apps/onboarding-ms/src/main/resources/application.properties index 46fd9e314..a93d90a88 100644 --- a/apps/onboarding-ms/src/main/resources/application.properties +++ b/apps/onboarding-ms/src/main/resources/application.properties @@ -88,6 +88,7 @@ onboarding-ms.blob-storage.filepath-product = products.json onboarding-ms.blob-storage.connection-string-product = ${BLOB-STORAGE-PRODUCT-CONNECTION-STRING:UseDevelopmentStorage=true;} onboarding-ms.blob-storage.path-contracts = parties/docs/ +onboarding-ms.blob-storage.path-aggregates = parties/csv/aggregates/ onboarding-ms.blob-storage.container-contracts=${STORAGE_CONTAINER_CONTRACT:selc-d-contracts-blob} onboarding-ms.blob-storage.connection-string-contracts = ${BLOB-STORAGE-CONTRACT-CONNECTION-STRING:UseDevelopmentStorage=true;} diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java index da17629b5..1c4c59b36 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/controller/AggregatesControllerTest.java @@ -10,6 +10,8 @@ import io.smallrye.mutiny.Uni; import it.pagopa.selfcare.onboarding.model.VerifyAggregateResponse; import it.pagopa.selfcare.onboarding.service.AggregatesService; +import jakarta.ws.rs.core.MediaType; +import org.jboss.resteasy.reactive.RestResponse; import org.junit.jupiter.api.Test; import java.io.File; @@ -47,6 +49,25 @@ void verifyAggregatesCsv_succeeds() { .validateAppIoAggregatesCsv(any()); } + @Test + @TestSecurity(user = "userJwt") + void getAggregatesCsv() { + final String onboardingId = "onboardingId"; + final String productId = "productId"; + RestResponse.ResponseBuilder response = RestResponse.ResponseBuilder.ok(); + when(aggregatesService.retrieveAggregatesCsv(onboardingId,productId)) + .thenReturn(Uni.createFrom().item(response.build())); + + given() + .when() + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .get("csv/{onboardingId}/products/{productId}", onboardingId, productId) + .then() + .statusCode(200); + + + } + @TestSecurity(user = "userJwt") @Test void verifyAggregatesSendCsv_succeeds() { diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java index bcc6660e8..b74328fbc 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java @@ -6,6 +6,8 @@ import io.quarkus.test.vertx.RunOnVertxContext; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; +import it.pagopa.selfcare.azurestorage.AzureBlobClient; +import it.pagopa.selfcare.onboarding.entity.Token; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; import it.pagopa.selfcare.onboarding.model.Aggregate; import it.pagopa.selfcare.onboarding.model.AggregateUser; @@ -15,6 +17,7 @@ import jakarta.inject.Inject; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.resteasy.reactive.RestResponse; import org.jboss.resteasy.reactive.client.api.WebClientApplicationException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -62,6 +65,9 @@ class AggregatesServiceDefaultTest { @InjectMock UoApi uoApi; + @InjectMock + AzureBlobClient azureBlobClient; + @Test @RunOnVertxContext void testValidateAppIoAggregatesCsv() { @@ -397,4 +403,21 @@ private static VerifyAggregateResponse mockResponseForSEND() { verifyAggregateResponse.setErrors(List.of(error0, error1, error4, error2, error3)); return verifyAggregateResponse; } + + @Test + void retrieveContractNotSigned() { + Token token = new Token(); + token.setContractFilename("fileName"); + final String onboardingId = "onboardingId"; + final String productId = "productId"; + + when(azureBlobClient.getFileAsPdf(anyString())).thenReturn(new File("fileName")); + + UniAssertSubscriber> subscriber = aggregatesServiceDefault.retrieveAggregatesCsv(onboardingId, productId) + .subscribe().withSubscriber(UniAssertSubscriber.create()); + + RestResponse actual = subscriber.awaitItem().getItem(); + Assertions.assertNotNull(actual); + Assertions.assertEquals(RestResponse.Status.OK.getStatusCode(), actual.getStatus()); + } } From 16e651bc97ae32dae76dbb06a158ea05f428d36a Mon Sep 17 00:00:00 2001 From: flaminiaScarciofolo <113031535+flaminiaScarciofolo@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:25:52 +0200 Subject: [PATCH 06/27] [SELC-5708] Feat: Added check to clean blank row and skip note row (#529) --- .../onboarding/service/CsvService.java | 18 +++++++++-- .../service/AggregatesServiceDefaultTest.java | 7 ++-- .../onboarding/service/CsvServiceTest.java | 32 +++++++++++++++++++ .../src/test/resources/test-read.csv | 9 ++++++ 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/CsvServiceTest.java create mode 100644 apps/onboarding-ms/src/test/resources/test-read.csv diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/CsvService.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/CsvService.java index 33483dba8..2ac8b738e 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/CsvService.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/service/CsvService.java @@ -27,6 +27,10 @@ public class CsvService { public static final String ERROR_READING_CSV = "Error reading CSV: "; public static final String MALFORMED_ROW = "Riga malformata"; + public static final String NOTE_PREFIX = "Note:"; + public static final String REQUIREMENT_PREFIX = "(*"; + public static final char SEPARATOR = ';'; + public AggregatesCsv readItemsFromCsv(File file, Class csv) { List resultList = new ArrayList<>(); List errors = new ArrayList<>(); @@ -41,7 +45,7 @@ public AggregatesCsv readItemsFromCsv(File file, Class csv String nextLine; while ((nextLine = bufferedReader.readLine()) != null) { - if (!nextLine.startsWith("(*")) { + if (!nextLine.startsWith(REQUIREMENT_PREFIX) && !nextLine.startsWith(NOTE_PREFIX) && !isBlankRow(nextLine)) { parseLine(nextLine, lineNumber, resultList, errors, csv); lineNumber++; } @@ -55,6 +59,16 @@ public AggregatesCsv readItemsFromCsv(File file, Class csv } } + public static boolean isBlankRow(String line) { + String[] values = line.split(String.valueOf(SEPARATOR)); + for (String value : values) { + if (!value.trim().isEmpty()) { + return false; + } + } + return true; + } + private void parseLine(String nextLine, int lineNumber, List resultList, List errors, Class csv) { try { StringReader lineReader = new StringReader(nextLine); @@ -75,7 +89,7 @@ private void parseLine(String nextLine, int lineNumber, List CsvToBean getAggregateCsvToBean(BufferedReader bufferedReader, Class csv) { CsvToBeanBuilder csvToBeanBuilder = new CsvToBeanBuilder<>(bufferedReader); csvToBeanBuilder.withType(csv); - csvToBeanBuilder.withSeparator(';'); + csvToBeanBuilder.withSeparator(SEPARATOR); csvToBeanBuilder.withQuoteChar(DEFAULT_QUOTE_CHARACTER); csvToBeanBuilder.withOrderedResults(true); csvToBeanBuilder.withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS); diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java index b74328fbc..e795fdf02 100644 --- a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/AggregatesServiceDefaultTest.java @@ -122,7 +122,7 @@ void testValidateAppIoAggregatesCsv() { Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(0), resp.getItem().getAggregates().get(0)); Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(1), resp.getItem().getAggregates().get(1)); Assertions.assertEquals(verifyAggregateResponse.getAggregates().get(2), resp.getItem().getAggregates().get(2)); - Assertions.assertEquals(6, resp.getItem().getErrors().size()); + Assertions.assertEquals(5, resp.getItem().getErrors().size()); Assertions.assertEquals(verifyAggregateResponse.getErrors().get(0), resp.getItem().getErrors().get(0)); Assertions.assertEquals(verifyAggregateResponse.getErrors().get(1), resp.getItem().getErrors().get(1)); Assertions.assertEquals(verifyAggregateResponse.getErrors().get(2), resp.getItem().getErrors().get(2)); @@ -291,10 +291,9 @@ private static VerifyAggregateResponse mockResponseForIO() { RowError error0 = new RowError(2, "1307110484", "SubunitType non valido"); RowError error1 = new RowError(3, "1307110484", "La partita IVA è obbligatoria"); - RowError error2 = new RowError(7, null, "Il codice fiscale è obbligatorio"); + RowError error2 = new RowError(7, "1307110484", "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"); RowError error4 = new RowError(4, "1307110484", "Codice fiscale non presente su IPA"); - RowError error3 = new RowError(8, "1307110484", "In caso di AOO/UO è necessario specificare la tipologia e il codice univoco IPA AOO/UO"); - verifyAggregateResponse.setErrors(List.of(error0, error1, error4, error2, error3)); + verifyAggregateResponse.setErrors(List.of(error0, error1, error4, error2)); return verifyAggregateResponse; } diff --git a/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/CsvServiceTest.java b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/CsvServiceTest.java new file mode 100644 index 000000000..2e06ede2c --- /dev/null +++ b/apps/onboarding-ms/src/test/java/it/pagopa/selfcare/onboarding/service/CsvServiceTest.java @@ -0,0 +1,32 @@ +package it.pagopa.selfcare.onboarding.service; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import it.pagopa.selfcare.onboarding.model.AggregatesCsv; +import it.pagopa.selfcare.onboarding.model.CsvAggregateAppIo; +import it.pagopa.selfcare.onboarding.service.profile.OnboardingTestProfile; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + +@QuarkusTest +@TestProfile(OnboardingTestProfile.class) +class CsvServiceTest { + + @Inject + CsvService csvService; + + @Test + void readItemsFromCsv_withValidCsvFile_returnsAggregatesCsv() { + File file = new File("src/test/resources/test-read.csv"); + + AggregatesCsv result = csvService.readItemsFromCsv(file, CsvAggregateAppIo.class); + + assertNotNull(result); + assertEquals(1, result.getCsvAggregateList().size()); + assertTrue(result.getRowErrorList().isEmpty()); + } +} \ No newline at end of file diff --git a/apps/onboarding-ms/src/test/resources/test-read.csv b/apps/onboarding-ms/src/test/resources/test-read.csv new file mode 100644 index 000000000..55a08c82d --- /dev/null +++ b/apps/onboarding-ms/src/test/resources/test-read.csv @@ -0,0 +1,9 @@ +Codice Fiscale*;P.IVA*;AOO/UO**;Codice Univoco** +80000750622;80000750622;AOO;A85E1C3 +;;; +;;; +;;; +;;; +Note: ;;; +(*) campo obbligatorio;;; +(**) campo obbligatorio in caso di AOO/UO;;; \ No newline at end of file From a0bc0bfb44b43531a732ea01d4deecae662b8d59 Mon Sep 17 00:00:00 2001 From: Manuel Rafeli Date: Mon, 7 Oct 2024 15:11:49 +0200 Subject: [PATCH 07/27] [SELC-5632] feat: added getProductRaw on product-sdk to retrieve data without refreshing configuration (#531) --- apps/onboarding-functions/pom.xml | 6 +++--- apps/onboarding-ms/pom.xml | 4 ++-- apps/pom.xml | 2 +- libs/onboarding-sdk-azure-storage/pom.xml | 2 +- libs/onboarding-sdk-common/pom.xml | 2 +- libs/onboarding-sdk-crypto/pom.xml | 2 +- libs/onboarding-sdk-pom/pom.xml | 2 +- libs/onboarding-sdk-product/pom.xml | 4 ++-- .../product/service/ProductService.java | 4 +++- .../service/ProductServiceCacheable.java | 16 +++++++++++++++ .../service/ProductServiceDefault.java | 14 +++++++++++++ .../service/ProductServiceCacheableTest.java | 20 +++++++++++++++++-- .../service/ProductServiceDefaultTest.java | 6 ++++++ test-coverage/pom.xml | 8 ++++---- 14 files changed, 73 insertions(+), 19 deletions(-) diff --git a/apps/onboarding-functions/pom.xml b/apps/onboarding-functions/pom.xml index 4689b00bc..4d3f463bd 100644 --- a/apps/onboarding-functions/pom.xml +++ b/apps/onboarding-functions/pom.xml @@ -193,17 +193,17 @@ it.pagopa.selfcare onboarding-sdk-crypto - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-product - 0.3.0 + 0.3.1 org.apache.commons diff --git a/apps/onboarding-ms/pom.xml b/apps/onboarding-ms/pom.xml index 83f065b6b..3b4a72ffc 100644 --- a/apps/onboarding-ms/pom.xml +++ b/apps/onboarding-ms/pom.xml @@ -243,12 +243,12 @@ it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-product - 0.3.0 + 0.3.1 diff --git a/apps/pom.xml b/apps/pom.xml index 36c7810cb..ea291c017 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -16,7 +16,7 @@ it.pagopa.selfcare onboarding-sdk-common - 0.3.0 + 0.3.1 diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml index 99b6a2256..c79aed3d4 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.3.0 + 0.3.1 ../onboarding-sdk-pom diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml index 9d49a2d81..753a353b0 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.3.0 + 0.3.1 ../onboarding-sdk-pom onboarding-sdk-common diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml index 637f99da7..8152a65ba 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.3.0 + 0.3.1 ../onboarding-sdk-pom onboarding-sdk-crypto diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml index ecf91e737..6f8f9a8c7 100644 --- a/libs/onboarding-sdk-pom/pom.xml +++ b/libs/onboarding-sdk-pom/pom.xml @@ -6,7 +6,7 @@ onboarding-sdk-pom pom onboarding-sdk-pom - 0.3.0 + 0.3.1 17 diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index e650b8f27..6951051c1 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.3.0 + 0.3.1 ../onboarding-sdk-pom onboarding-sdk-product onboarding-sdk-product - 0.3.0 + 0.3.1 2.15.2 diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java index f0959af09..c34b09b6a 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductService.java @@ -11,12 +11,14 @@ import java.util.Map; public interface ProductService { - public List getProducts(boolean rootOnly, boolean valid) ; + List getProducts(boolean rootOnly, boolean valid) ; void validateRoleMappings(Map roleMappings); Product getProduct(String productId); + Product getProductRaw(String productId); + void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType); Product getProductIsValid(String productId); diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java index fd7d2bd00..fa09bbe20 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceCacheable.java @@ -8,6 +8,7 @@ import it.pagopa.selfcare.product.entity.Product; import it.pagopa.selfcare.product.entity.ProductRole; import it.pagopa.selfcare.product.entity.ProductRoleInfo; +import it.pagopa.selfcare.product.exception.ProductNotFoundException; import java.time.LocalDateTime; import java.util.List; @@ -63,6 +64,21 @@ public Product getProduct(String productId) { return productService.getProduct(productId); } + + /** + * Return a product present on the map by productId without any filter + * retrieving data from institutionContractMappings map + * + * @param productId String + * @return Product + * @throws IllegalArgumentException if @param id is null + * @throws ProductNotFoundException if product is not found + */ + @Override + public Product getProductRaw(String productId) { + return productService.getProduct(productId); + } + @Override public void fillContractTemplatePathAndVersion(Product product, InstitutionType institutionType) { refreshProduct(); diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java index 414f84c57..650baab20 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/service/ProductServiceDefault.java @@ -113,6 +113,20 @@ public Product getProduct(String productId) { return getProduct(productId, false); } + /** + * Return a product present on the map by productId without any filter + * retrieving data from institutionContractMappings map + * + * @param productId String + * @return Product + * @throws IllegalArgumentException if @param id is null + * @throws ProductNotFoundException if product is not found + */ + @Override + public Product getProductRaw(String productId) { + return getProduct(productId, false); + } + private Product getProduct(String productId, boolean filterValid) { if (Objects.isNull(productId)) { diff --git a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java index 0d7e369b8..973c53bab 100644 --- a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceCacheableTest.java @@ -18,8 +18,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; class ProductServiceCacheableTest { private static final String PRODUCT_JSON_STRING = "[{\"id\":\"prod-test-parent\",\"status\":\"ACTIVE\"}," + @@ -168,6 +167,23 @@ void getProduct() { assertNotNull(product); } + @Test + void getProductRaw() { + final String filePath = "filePath"; + AzureBlobClient azureBlobClient = mock(AzureBlobClient.class); + BlobProperties blobPropertiesMock = mock(BlobProperties.class); + + when(azureBlobClient.getProperties(any())).thenReturn(blobPropertiesMock); + when(blobPropertiesMock.getLastModified()).thenReturn(OffsetDateTime.now()); + when(azureBlobClient.getFileAsText(any())).thenReturn(PRODUCT_JSON_STRING); + ProductServiceCacheable productServiceCacheable = new ProductServiceCacheable(azureBlobClient, filePath); + //when + Product product = productServiceCacheable.getProductRaw("prod-test"); + //then + assertNotNull(product); + verify(blobPropertiesMock, times(1)).getLastModified(); + } + @Test void getProduct_notFoundInactive() { diff --git a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java index 6908f6e94..53c6a97a4 100644 --- a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/service/ProductServiceDefaultTest.java @@ -113,6 +113,12 @@ void getProduct_shouldGetProduct() throws JsonProcessingException { assertNotNull(productService.getProduct("prod-test")); } + @Test + void getProductRaw_shouldGetProduct() throws JsonProcessingException { + ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); + assertNotNull(productService.getProductRaw("prod-test")); + } + @Test void getProductValid_shouldThrowProductNotFoundExceptionIfProductInactive() throws JsonProcessingException { ProductServiceDefault productService = new ProductServiceDefault(PRODUCT_JSON_STRING); diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index 88acc0a6c..60e706314 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -77,22 +77,22 @@ it.pagopa.selfcare onboarding-sdk-product - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-common - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.0 + 0.3.1 it.pagopa.selfcare onboarding-sdk-crypto - 0.3.0 + 0.3.1 From 9e7d16538d8224cd67d4a5eeaf95e8b797f51dd3 Mon Sep 17 00:00:00 2001 From: Manuel Rafeli Date: Mon, 7 Oct 2024 16:34:46 +0200 Subject: [PATCH 08/27] [SELC-5629] fix: getAllRoleMappings sdk when both maps are non-null with overlapping keys (#532) --- .github/workflows/pr_libs.yml | 2 +- .../selfcare/product/entity/Product.java | 12 +- .../selfcare/product/entity/ProductRole.java | 14 ++ .../product/entity/ProductRoleInfo.java | 13 ++ .../selfcare/product/entity/ProductTest.java | 127 ++++++++++++++++++ 5 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/entity/ProductTest.java diff --git a/.github/workflows/pr_libs.yml b/.github/workflows/pr_libs.yml index c0064f1b6..470270c02 100644 --- a/.github/workflows/pr_libs.yml +++ b/.github/workflows/pr_libs.yml @@ -13,7 +13,7 @@ on: - reopened - ready_for_review paths: - - './libs/**' + - 'libs/**' - '.github/workflows/pr_libs.yml' - '.github/workflows/call_code_review.yml' diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java index 62ea6f039..b8e52c3d0 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/Product.java @@ -152,12 +152,20 @@ public Map getRoleMappings(String institutionType) { public Map> getAllRoleMappings() { Map> roleInfoMap = new HashMap<>(); Optional.ofNullable(roleMappings) - .ifPresent(roleMappings -> roleMappings.forEach((key, value) -> roleInfoMap.put(key, List.of(value)))); + .ifPresent(roleMappings -> roleMappings.forEach((key, value) -> { + List productRoles = new ArrayList<>(); + productRoles.add(value); + roleInfoMap.put(key, productRoles); + })); Optional.ofNullable(roleMappingsByInstitutionType) .map(Map::values) .ifPresent(items -> items.stream() .map(Map::entrySet) - .forEach(item -> item.forEach(entry -> roleInfoMap.put(entry.getKey(), List.of(entry.getValue()))))); + .forEach(item -> item.forEach(entry -> { + List productRoles = roleInfoMap.getOrDefault(entry.getKey(), new ArrayList<>()); + productRoles.add(entry.getValue()); + roleInfoMap.put(entry.getKey(), productRoles); + } ))); return roleInfoMap; } diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java index 6d5793f1b..44e1f47df 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRole.java @@ -1,5 +1,7 @@ package it.pagopa.selfcare.product.entity; +import java.util.Objects; + public class ProductRole { private String code; @@ -29,4 +31,16 @@ public String getDescription() { public void setDescription(String description) { this.description = description; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ProductRole that)) return false; + return Objects.equals(getCode(), that.getCode()) && Objects.equals(getLabel(), that.getLabel()) && Objects.equals(getDescription(), that.getDescription()); + } + + @Override + public int hashCode() { + return Objects.hash(getCode(), getLabel(), getDescription()); + } } diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java index 1cb9cdbe5..1dce9b870 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/entity/ProductRoleInfo.java @@ -1,6 +1,7 @@ package it.pagopa.selfcare.product.entity; import java.util.List; +import java.util.Objects; public class ProductRoleInfo { @@ -35,4 +36,16 @@ public List getRoles() { public void setRoles(List roles) { this.roles = roles; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ProductRoleInfo that)) return false; + return isMultiroleAllowed() == that.isMultiroleAllowed() && Objects.equals(getPhasesAdditionAllowed(), that.getPhasesAdditionAllowed()) && Objects.equals(getRoles(), that.getRoles()); + } + + @Override + public int hashCode() { + return Objects.hash(isMultiroleAllowed(), getPhasesAdditionAllowed(), getRoles()); + } } diff --git a/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/entity/ProductTest.java b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/entity/ProductTest.java new file mode 100644 index 000000000..e3c9e6923 --- /dev/null +++ b/libs/onboarding-sdk-product/src/test/java/it/pagopa/selfcare/product/entity/ProductTest.java @@ -0,0 +1,127 @@ +package it.pagopa.selfcare.product.entity; + +import it.pagopa.selfcare.onboarding.common.PartyRole; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +public class ProductTest { + + ProductRoleInfo dummmyProductRoleInfo(PartyRole partyRole) { + ProductRoleInfo productRoleInfo = new ProductRoleInfo(); + ProductRole productRole = new ProductRole(); + productRole.setCode(partyRole.name()); + productRoleInfo.setRoles(List.of(productRole)); + return productRoleInfo; + } + + @Test + @DisplayName("Test when only roleMappings is non-null") + public void testGetAllRoleMappings_OnlyRoleMappings() { + Map roleMappings = new HashMap<>(); + ProductRoleInfo manager = dummmyProductRoleInfo(PartyRole.MANAGER); + ProductRoleInfo operator = dummmyProductRoleInfo(PartyRole.OPERATOR); + roleMappings.put(PartyRole.MANAGER, manager); + roleMappings.put(PartyRole.OPERATOR, operator); + + Product product = new Product(); + product.setRoleMappings(roleMappings); + product.setRoleMappingsByInstitutionType(null); + + Map> result = product.getAllRoleMappings(); + + assertEquals(2, result.size(), "Map should contain 2 keys"); + assertEquals(List.of(manager), result.get(PartyRole.MANAGER)); + assertEquals(List.of(operator), result.get(PartyRole.OPERATOR)); + } + + @Test + @DisplayName("Test when only roleMappingsByInstitutionType is non-null") + public void testGetAllRoleMappings_OnlyRoleMappingsByInstitutionType() { + Map> roleMappingsByInstitutionType = new HashMap<>(); + + Map institution1 = new HashMap<>(); + institution1.put(PartyRole.MANAGER, dummmyProductRoleInfo(PartyRole.MANAGER)); + institution1.put(PartyRole.OPERATOR, dummmyProductRoleInfo(PartyRole.OPERATOR)); + + Map institution2 = new HashMap<>(); + institution2.put(PartyRole.DELEGATE, dummmyProductRoleInfo(PartyRole.DELEGATE)); + institution2.put(PartyRole.OPERATOR, dummmyProductRoleInfo(PartyRole.OPERATOR)); + + roleMappingsByInstitutionType.put("Institution1", institution1); + roleMappingsByInstitutionType.put("Institution2", institution2); + + Product product = new Product(); + product.setRoleMappings(null); + product.setRoleMappingsByInstitutionType(roleMappingsByInstitutionType); + + Map> result = product.getAllRoleMappings(); + + assertEquals(3, result.size(), "Map should contain 3 keys"); + assertEquals(List.of(dummmyProductRoleInfo(PartyRole.MANAGER)), result.get(PartyRole.MANAGER)); + assertEquals(List.of(dummmyProductRoleInfo(PartyRole.DELEGATE)), result.get(PartyRole.DELEGATE)); + assertEquals(Arrays.asList( + dummmyProductRoleInfo(PartyRole.OPERATOR), + dummmyProductRoleInfo(PartyRole.OPERATOR) + ), result.get(PartyRole.OPERATOR)); + } + + @Test + @DisplayName("Test when both maps are non-null with overlapping keys") + public void testGetAllRoleMappings_BothMapsNonNullWithOverlap() { + // Setup roleMappings + Map roleMappings = new HashMap<>(); + roleMappings.put(PartyRole.MANAGER, dummmyProductRoleInfo(PartyRole.MANAGER)); + roleMappings.put(PartyRole.DELEGATE, dummmyProductRoleInfo(PartyRole.OPERATOR)); + + // Setup roleMappingsByInstitutionType + Map> roleMappingsByInstitutionType = new HashMap<>(); + + Map institution1 = new HashMap<>(); + institution1.put(PartyRole.MANAGER, dummmyProductRoleInfo(PartyRole.MANAGER)); + institution1.put(PartyRole.OPERATOR, dummmyProductRoleInfo(PartyRole.OPERATOR)); + + Map institution2 = new HashMap<>(); + institution2.put(PartyRole.DELEGATE, dummmyProductRoleInfo(PartyRole.DELEGATE)); + institution2.put(PartyRole.OPERATOR, dummmyProductRoleInfo(PartyRole.OPERATOR)); + + roleMappingsByInstitutionType.put("Institution1", institution1); + roleMappingsByInstitutionType.put("Institution2", institution2); + + Product product = new Product(); + product.setRoleMappings(roleMappings); + product.setRoleMappingsByInstitutionType(roleMappingsByInstitutionType); + + Map> result = product.getAllRoleMappings(); + + assertEquals(3, result.size(), "Map should contain 3 keys"); + + // Verify MANAGER + List adminList = result.get(PartyRole.MANAGER); + assertNotNull(adminList, "List for MANAGER should not be null"); + assertEquals(2, adminList.size(), "List for MANAGER should contain 2 elements"); + assertTrue(adminList.contains(dummmyProductRoleInfo(PartyRole.MANAGER))); + assertTrue(adminList.contains(dummmyProductRoleInfo(PartyRole.MANAGER))); + + // Verify DELEGATE + List userList = result.get(PartyRole.DELEGATE); + assertNotNull(userList, "List for DELEGATE should not be null"); + assertEquals(2, userList.size(), "List for DELEGATE should contain 2 elements"); + assertTrue(userList.contains(dummmyProductRoleInfo(PartyRole.DELEGATE))); + assertTrue(userList.contains(dummmyProductRoleInfo(PartyRole.DELEGATE))); + + // Verify OPERATOR + List guestList = result.get(PartyRole.OPERATOR); + assertNotNull(guestList, "List for OPERATOR should not be null"); + assertEquals(2, guestList.size(), "List for OPERATOR should contain 2 elements"); + assertTrue(guestList.contains(dummmyProductRoleInfo(PartyRole.OPERATOR))); + assertTrue(guestList.contains(dummmyProductRoleInfo(PartyRole.OPERATOR))); + } + +} From abe0cffd8c7ca46a857f37461bb8516390c42d45 Mon Sep 17 00:00:00 2001 From: andrea-putzu <106688558+andrea-putzu@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:13:11 +0200 Subject: [PATCH 09/27] Update azure linux function app configuration (#533) --- .../onboarding-functions/.terraform.lock.hcl | 87 ------------------- .../env/dev-pnpg/terraform.tfvars | 2 + .../env/dev/terraform.tfvars | 14 +-- .../env/prod-pnpg/terraform.tfvars | 2 + .../env/prod/terraform.tfvars | 2 + .../env/uat-pnpg/terraform.tfvars | 2 + .../env/uat/terraform.tfvars | 2 + .../onboarding-functions/functions.tf | 12 +-- .../onboarding-functions/variables.tf | 4 + 9 files changed, 28 insertions(+), 99 deletions(-) delete mode 100644 infra/functions/onboarding-functions/.terraform.lock.hcl diff --git a/infra/functions/onboarding-functions/.terraform.lock.hcl b/infra/functions/onboarding-functions/.terraform.lock.hcl deleted file mode 100644 index 25baf19a8..000000000 --- a/infra/functions/onboarding-functions/.terraform.lock.hcl +++ /dev/null @@ -1,87 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/azuread" { - version = "2.30.0" - constraints = "2.30.0" - hashes = [ - "h1:Uw4TcmJBEJ71h+oCwwidlkk5jFpyFRDPAFCMs/bT/cw=", - "h1:WnSPiREAFwnBUKREokMdHQ8Cjs47MzvS9pG8VS1ktec=", - "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7", - "zh:2e62c193030e04ebb10cc0526119cf69824bf2d7e4ea5a2f45bd5d5fb7221d36", - "zh:2f3c7a35257332d68b778cefc5201a5f044e4914dd03794a4da662ddfe756483", - "zh:35d0d3a1b58fdb8b8c4462d6b7e7016042da43ea9cc734ce897f52a73407d9b0", - "zh:47ede0cd0206ec953d40bf4a80aa6e59af64e26cbbd877614ac424533dbb693b", - "zh:48c190307d4d42ea67c9b8cc544025024753f46cef6ea64db84735e7055a72da", - "zh:6fff9b2c6a962252a70a15b400147789ab369b35a781e9d21cce3804b04d29af", - "zh:7646980cf3438bff29c91ffedb74458febbb00a996638751fbd204ab1c628c9b", - "zh:77aa2fa7ca6d5446afa71d4ff83cb87b70a2f3b72110fc442c339e8e710b2928", - "zh:e20b2b2c37175b89dd0db058a096544d448032e28e3b56e2db368343533a9684", - "zh:eab175b1dfe9865ad9404dccb6d5542899f8c435095aa7c679314b811c717ce7", - "zh:efc862bd78c55d2ff089729e2a34c1831ab4b0644fc11b36ee4ebed00a4797ba", - ] -} - -provider "registry.terraform.io/hashicorp/azurerm" { - version = "3.84.0" - constraints = ">= 3.30.0, <= 3.84.0, <= 3.85.0, <= 3.86.0" - hashes = [ - "h1:1Ucponuagrx5kNeIlcZwG2urqoRXBCTddDKqL265+xM=", - "h1:y/NWRLvnJmyJ5lf/AnLFy25jfyJqp6xwwxLxZnvovAs=", - "zh:14a96daf672541dbc27137d9cc0a96a737710597262ecaaa64a328eb1174e5df", - "zh:16d8e794fdd87ed8e64291fe8a617f420d8263f21672033333a020d06f4c9618", - "zh:64e5cd1bb6a81bccffff0d1f77790286ab46179cf12442134c3f3bca722afc1b", - "zh:7010ada67fbae971ac8b7204a30b1317aee7ccac7227afc6ac27277c642996a1", - "zh:77c2616ecd29685d2a4dc3ec3e9771e5ecf652e127946767d9b7ef19bbf58a21", - "zh:861922cfae724eacf1bd915efd5dbf6c23e4e762a2bbe60993099648e64aedb5", - "zh:8fb797c98bb08e7342995317810d28c41bb519fbc128adaa170896356b9eaebd", - "zh:982e85a4a9d282e3c8f7d7836037ccc98ff3ef50af246fad2e04684a81d16201", - "zh:a2ef29ff907cf6622e58afa0a27e23a3160ba3d70d531795b4d9a6c42c354630", - "zh:c46ccc4eecb79d096bcb652af0cffe300ec480d80a13a5b302c71b1aac9f9f1c", - "zh:cc6a06bf6d5e811fe8c0d9ad652e143b4e94bd16a03fb8a86f5086f0ae5abfa9", - "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - ] -} - -provider "registry.terraform.io/hashicorp/null" { - version = "3.2.2" - hashes = [ - "h1:IMVAUHKoydFrlPrl9OzasDnw/8ntZFerCC9iXw1rXQY=", - "h1:vWAsYRd7MjYr3adj8BVKRohVfHpWQdvkIwUQ2Jf5FVM=", - "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7", - "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a", - "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3", - "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606", - "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546", - "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539", - "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422", - "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae", - "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1", - "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e", - ] -} - -provider "registry.terraform.io/integrations/github" { - version = "5.18.3" - constraints = "5.18.3" - hashes = [ - "h1:WbZvLB2qXKVoh4BvOOwFfEds+SZQrkINfSAWPnWFxGo=", - "h1:rv3mwpUeJ0n13sY+KZMI25WAVCSeipX4n8JMWKD1XcE=", - "zh:050b37d96628cb7451137755929ca8d21ea546bc46d11a715652584070e83ff2", - "zh:053051061f1b7f7673b0ceffac1f239ba28b0e5b375999206fd39976e85d9f2b", - "zh:0c300a977ca66d0347ed62bb116fd8fc9abb376a554d4c192d14f3ea71c83500", - "zh:1d5a1a5243eba78819d2f92ff2d504ebf9a9008a6670fb5f5660f44eb6a156d8", - "zh:a13ac15d251ebf4e7dc40acb0e40df066f443f4c7799186a29e2e44addc7d8e7", - "zh:a316d94b885953c036ebc9fba64a23da93974746bc3ac9d207462a6f02d44540", - "zh:a658a00373bff5979cc227052c693cbde8ca4c8f9fef1bc8094a3516f2e2a96d", - "zh:a7bfc6ad8465d5dc11b6f19d6805364de87fffe27622bb4f37da2319bb1c4956", - "zh:d7379a76861f1a6bfc36eca7a20f1f477711247563b105744d69d7bd1f365fad", - "zh:de1cd959fd4821248e8d21570601193408648474e74f49597f1d0c43185a4ab7", - "zh:e0b281240dd6f2aa405b2d6fe329bc15ab877161affe163fb150d1efca2fccdb", - "zh:e372c171358757a983d7aa878abfd05a84484fb4d22167e45c9c1267e78ed060", - "zh:f6d3116526030b3f6905f530cd6c04b23d42890d973fa2abe10ce9c89cb1db80", - "zh:f99eec731e03cc6a28996c875bd435887cd7ea75ec07cc77b9e768bb12da2227", - ] -} diff --git a/infra/functions/onboarding-functions/env/dev-pnpg/terraform.tfvars b/infra/functions/onboarding-functions/env/dev-pnpg/terraform.tfvars index 7be46e15c..2e2a42738 100644 --- a/infra/functions/onboarding-functions/env/dev-pnpg/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/dev-pnpg/terraform.tfvars @@ -36,6 +36,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = false + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/env/dev/terraform.tfvars b/infra/functions/onboarding-functions/env/dev/terraform.tfvars index ba41927c2..ebbdde5c9 100644 --- a/infra/functions/onboarding-functions/env/dev/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/dev/terraform.tfvars @@ -21,12 +21,12 @@ cidr_subnet_selc_onboarding_fn = ["10.1.144.0/24"] function_always_on = false app_service_plan_info = { - kind = "Linux" - sku_size = "P1v3" - sku_tier = "PremiumV3" - maximum_elastic_worker_count = 1 - worker_count = 1 - zone_balancing_enabled = false + kind = "Linux" + sku_size = "P1v3" + sku_tier = "PremiumV3" + maximum_elastic_worker_count = 1 + worker_count = 1 + zone_balancing_enabled = false } storage_account_info = { @@ -35,6 +35,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = false + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/env/prod-pnpg/terraform.tfvars b/infra/functions/onboarding-functions/env/prod-pnpg/terraform.tfvars index 0f5142dd5..d9d2c923f 100644 --- a/infra/functions/onboarding-functions/env/prod-pnpg/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/prod-pnpg/terraform.tfvars @@ -36,6 +36,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = true + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/env/prod/terraform.tfvars b/infra/functions/onboarding-functions/env/prod/terraform.tfvars index a2a50498f..2821a35dc 100644 --- a/infra/functions/onboarding-functions/env/prod/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/prod/terraform.tfvars @@ -35,6 +35,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = true + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/env/uat-pnpg/terraform.tfvars b/infra/functions/onboarding-functions/env/uat-pnpg/terraform.tfvars index 9d7a9ef3c..eb6a9eab3 100644 --- a/infra/functions/onboarding-functions/env/uat-pnpg/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/uat-pnpg/terraform.tfvars @@ -36,6 +36,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = false + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/env/uat/terraform.tfvars b/infra/functions/onboarding-functions/env/uat/terraform.tfvars index 1df034e1f..33c9f4aa3 100644 --- a/infra/functions/onboarding-functions/env/uat/terraform.tfvars +++ b/infra/functions/onboarding-functions/env/uat/terraform.tfvars @@ -35,6 +35,8 @@ storage_account_info = { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = false + use_legacy_defender_version = true + public_network_access_enabled = false } app_settings = { diff --git a/infra/functions/onboarding-functions/functions.tf b/infra/functions/onboarding-functions/functions.tf index 2c7c26f26..8244e8f5f 100644 --- a/infra/functions/onboarding-functions/functions.tf +++ b/infra/functions/onboarding-functions/functions.tf @@ -22,8 +22,13 @@ module "onboarding_fn_snet" { } } +data "azurerm_key_vault" "key_vault" { + resource_group_name = var.key_vault.resource_group_name + name = var.key_vault.name +} + module "selc_onboarding_fn" { - source = "github.com/pagopa/terraform-azurerm-v3.git//function_app?ref=v7.47.2" + source = "github.com/pagopa/terraform-azurerm-v3.git//function_app?ref=v7.77.0" name = local.app_name location = azurerm_resource_group.onboarding_fn_rg.location @@ -47,11 +52,6 @@ module "selc_onboarding_fn" { tags = var.tags } -data "azurerm_key_vault" "key_vault" { - resource_group_name = var.key_vault.resource_group_name - name = var.key_vault.name -} - resource "azurerm_key_vault_access_policy" "keyvault_functions_access_policy" { key_vault_id = data.azurerm_key_vault.key_vault.id tenant_id = data.azurerm_client_config.current.tenant_id diff --git a/infra/functions/onboarding-functions/variables.tf b/infra/functions/onboarding-functions/variables.tf index 14573228a..2858699ba 100644 --- a/infra/functions/onboarding-functions/variables.tf +++ b/infra/functions/onboarding-functions/variables.tf @@ -59,6 +59,8 @@ variable "storage_account_info" { account_replication_type = string access_tier = string advanced_threat_protection_enable = bool + use_legacy_defender_version = bool + public_network_access_enabled = bool }) default = { @@ -67,6 +69,8 @@ variable "storage_account_info" { account_replication_type = "LRS" access_tier = "Hot" advanced_threat_protection_enable = true + use_legacy_defender_version = true + public_network_access_enabled = false } } From 3a9ae24e1afdfb4981f55299fd7897d9f9d2f022 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:14:17 +0200 Subject: [PATCH 10/27] [SELC-5564] feat: add method to replace csv aggregates placeholder (#530) --- .../service/ContractServiceDefault.java | 12 ++++++-- .../selfcare/onboarding/utils/PdfMapper.java | 21 +++++++++++++ .../service/ContractServiceDefaultTest.java | 30 +++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java index e91f54ba8..efc9587da 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -5,6 +5,7 @@ import it.pagopa.selfcare.azurestorage.AzureBlobClient; import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.config.AzureStorageConfig; +import it.pagopa.selfcare.onboarding.config.MailTemplatePlaceholdersConfig; import it.pagopa.selfcare.onboarding.config.PagoPaSignatureConfig; import it.pagopa.selfcare.onboarding.crypto.PadesSignService; import it.pagopa.selfcare.onboarding.crypto.entity.SignatureInformation; @@ -53,6 +54,7 @@ public class ContractServiceDefault implements ContractService { private final AzureBlobClient azureBlobClient; private final PadesSignService padesSignService; private final PagoPaSignatureConfig pagoPaSignatureConfig; + private final MailTemplatePlaceholdersConfig templatePlaceholdersConfig; Boolean isLogoEnable; @@ -67,13 +69,14 @@ public class ContractServiceDefault implements ContractService { public ContractServiceDefault(AzureStorageConfig azureStorageConfig, AzureBlobClient azureBlobClient, PadesSignService padesSignService, - PagoPaSignatureConfig pagoPaSignatureConfig, + PagoPaSignatureConfig pagoPaSignatureConfig, MailTemplatePlaceholdersConfig templatePlaceholdersConfig, @ConfigProperty(name = "onboarding-functions.logo-path") String logoPath, @ConfigProperty(name = "onboarding-functions.logo-enable") Boolean isLogoEnable) { this.azureStorageConfig = azureStorageConfig; this.azureBlobClient = azureBlobClient; this.padesSignService = padesSignService; this.pagoPaSignatureConfig = pagoPaSignatureConfig; + this.templatePlaceholdersConfig = templatePlaceholdersConfig; this.logoPath = logoPath; this.isLogoEnable = isLogoEnable; } @@ -135,6 +138,8 @@ private File createPdfFileContract(String contractTemplatePath, Onboarding onboa // Prepare common data for the contract document. Map data = setUpCommonData(manager, users, onboarding); + StringBuilder baseUrl = new StringBuilder(templatePlaceholdersConfig.rejectOnboardingUrlValue()); + // Customize data based on the product and institution type. if (PROD_PAGOPA.getValue().equalsIgnoreCase(productId) && InstitutionType.PSP == institution.getInstitutionType()) { @@ -146,8 +151,9 @@ private File createPdfFileContract(String contractTemplatePath, Onboarding onboa InstitutionType.PSP != institution.getInstitutionType() && InstitutionType.PT != institution.getInstitutionType()) { setECData(data, onboarding); - } else if (PROD_IO.getValue().equalsIgnoreCase(productId) - || PROD_IO_PREMIUM.getValue().equalsIgnoreCase(productId) + } else if (PROD_IO.getValue().equalsIgnoreCase(productId)){ + setupProdIODataAggregates(onboarding, data, manager, baseUrl.toString()); + } else if (PROD_IO_PREMIUM.getValue().equalsIgnoreCase(productId) || PROD_IO_SIGN.getValue().equalsIgnoreCase(productId)) { setupProdIOData(onboarding, data, manager); } else if (PROD_PN.getValue().equalsIgnoreCase(productId)){ diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java index 7dc49d7a9..05baa4822 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java @@ -29,7 +29,9 @@ public class PdfMapper { public static final String PRICING_PLAN_BASE_CHECKBOX = "pricingPlanBaseCheckbox"; public static final String PRICING_PLAN = "pricingPlan"; public static final String INSTITUTION_REGISTER_LABEL_VALUE = "institutionRegisterLabelValue"; + public static final String CSV_AGGREGATES_LABEL_VALUE = "aggregatesCsvLink"; public static final String ORIGIN_ID_LABEL = "
  • codice di iscrizione all’Indice delle Pubbliche Amministrazioni e dei gestori di pubblici servizi (I.P.A.) ${originId}
  • "; + public static final String CSV_AGGREGATES_LABEL = ""; public static final String INSTITUTION_RECIPIENT_CODE = "institutionRecipientCode"; private PdfMapper() { @@ -163,6 +165,11 @@ public static void setupProdIOData(Onboarding onboarding, Map ma addPricingPlan(onboarding.getPricingPlan(), map); } + public static void setupProdIODataAggregates(Onboarding onboarding, Map map, UserResource validManager, String baseUrl) { + setupProdIOData(onboarding, map,validManager); + addAggregatesCsvLink(onboarding,map, baseUrl); + } + public static void setupSAProdInteropData(Map map, Institution institution) { map.put(INSTITUTION_REA, Optional.ofNullable(institution.getRea()).orElse(UNDERSCORE)); @@ -200,6 +207,20 @@ private static void addPricingPlan(String pricingPlan, Map map) } } + private static void addAggregatesCsvLink(Onboarding onboarding, Map map, String baseUrl) { + String csvLink = StringUtils.EMPTY; + String products = "/products/"; + String aggregates = "/aggregates"; + + if (Boolean.TRUE.equals(onboarding.getIsAggregator())) { + String url = baseUrl + onboarding.getId() + products + onboarding.getProductId() + aggregates; + csvLink = String.format(CSV_AGGREGATES_LABEL, url); + } + + map.put(CSV_AGGREGATES_LABEL_VALUE, csvLink); + + } + private static void addInstitutionRegisterLabelValue(Institution institution, Map map) { String businessRegisterNumber = StringUtils.EMPTY; String businessRegisterNumberLabel = StringUtils.EMPTY; diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java index 5db2837b2..75381e1f1 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java @@ -5,12 +5,15 @@ import it.pagopa.selfcare.azurestorage.AzureBlobClient; import it.pagopa.selfcare.onboarding.common.InstitutionType; import it.pagopa.selfcare.onboarding.config.AzureStorageConfig; +import it.pagopa.selfcare.onboarding.config.MailTemplatePlaceholdersConfig; import it.pagopa.selfcare.onboarding.config.PagoPaSignatureConfig; import it.pagopa.selfcare.onboarding.crypto.PadesSignService; import it.pagopa.selfcare.onboarding.entity.*; import jakarta.inject.Inject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.openapi.quarkus.user_registry_json.model.CertifiableFieldResourceOfstring; @@ -41,13 +44,17 @@ class ContractServiceDefaultTest { @Inject PagoPaSignatureConfig pagoPaSignatureConfig; + @Inject + MailTemplatePlaceholdersConfig mailTemplatePlaceholdersConfig; + static final String PRODUCT_NAME_EXAMPLE = "product-name"; + static final String LOGO_PATH = "logo-path"; static final String PDF_FORMAT_FILENAME = "%s_accordo_adesione.pdf"; @BeforeEach void setup(){ padesSignService = mock(PadesSignService.class); - contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, "logo- path", true); + contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, mailTemplatePlaceholdersConfig, LOGO_PATH, true); } @@ -186,6 +193,25 @@ void createContractPDFForECAndProdPagoPA() { assertNotNull(contractService.createContractPDF(contractFilepath, onboarding, manager, List.of(), PRODUCT_NAME_EXAMPLE, PDF_FORMAT_FILENAME)); } + @ParameterizedTest + @ValueSource(strings = {"prod-io", "prod-io-sign"}) + void createContractPDFForProdIo(String productId) { + final String contractFilepath = "contract"; + final String contractHtml = "contract"; + + Onboarding onboarding = createOnboarding(); + User userManager = onboarding.getUsers().get(0); + UserResource manager = createDummyUserResource(userManager.getId(), userManager.getUserMailUuid()); + onboarding.getInstitution().setInstitutionType(InstitutionType.PA); + onboarding.setProductId(productId); + + Mockito.when(azureBlobClient.getFileAsText(contractFilepath)).thenReturn(contractHtml); + + Mockito.when(azureBlobClient.uploadFile(any(),any(),any())).thenReturn(contractHtml); + + assertNotNull(contractService.createContractPDF(contractFilepath, onboarding, manager, List.of(), PRODUCT_NAME_EXAMPLE, PDF_FORMAT_FILENAME)); + } + @Test void createContractPDFAndSigned() { final String contractFilepath = "contract"; @@ -197,7 +223,7 @@ void createContractPDFAndSigned() { pagoPaSignatureConfig = Mockito.spy(this.pagoPaSignatureConfig); when(pagoPaSignatureConfig.source()).thenReturn("local"); - contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, "logo-path", true); + contractService = new ContractServiceDefault(azureStorageConfig, azureBlobClient, padesSignService, pagoPaSignatureConfig, mailTemplatePlaceholdersConfig ,"logo-path", true); Mockito.when(azureBlobClient.getFileAsText(contractFilepath)).thenReturn(contractHtml); From 8259679f8f977a77c53767978854a632e5a9d1e5 Mon Sep 17 00:00:00 2001 From: empassaro <113031808+empassaro@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:02:18 +0200 Subject: [PATCH 11/27] [SELC-5332] feat: added infra to create onboarding notification dashboard (#504) Co-authored-by: andrea putzu --- infra/dashboards/env/dev/backend.ini | 1 + infra/dashboards/env/dev/backend.tfvars | 4 + infra/dashboards/env/dev/terraform.tfvars | 13 + infra/dashboards/env/prod/backend.ini | 1 + infra/dashboards/env/prod/backend.tfvars | 4 + infra/dashboards/env/prod/terraform.tfvars | 13 + infra/dashboards/env/uat/backend.ini | 1 + infra/dashboards/env/uat/backend.tfvars | 4 + infra/dashboards/env/uat/terraform.tfvars | 13 + infra/dashboards/locals.tf | 4 + infra/dashboards/main.tf | 33 + infra/dashboards/monitor.tf | 19 + infra/dashboards/monitoring.json | 895 +++++++++++++++++++++ infra/dashboards/terraform.sh | 69 ++ infra/dashboards/variables.tf | 43 + 15 files changed, 1117 insertions(+) create mode 100644 infra/dashboards/env/dev/backend.ini create mode 100644 infra/dashboards/env/dev/backend.tfvars create mode 100644 infra/dashboards/env/dev/terraform.tfvars create mode 100644 infra/dashboards/env/prod/backend.ini create mode 100644 infra/dashboards/env/prod/backend.tfvars create mode 100644 infra/dashboards/env/prod/terraform.tfvars create mode 100644 infra/dashboards/env/uat/backend.ini create mode 100644 infra/dashboards/env/uat/backend.tfvars create mode 100644 infra/dashboards/env/uat/terraform.tfvars create mode 100644 infra/dashboards/locals.tf create mode 100644 infra/dashboards/main.tf create mode 100644 infra/dashboards/monitor.tf create mode 100644 infra/dashboards/monitoring.json create mode 100755 infra/dashboards/terraform.sh create mode 100644 infra/dashboards/variables.tf diff --git a/infra/dashboards/env/dev/backend.ini b/infra/dashboards/env/dev/backend.ini new file mode 100644 index 000000000..73ee9c6b7 --- /dev/null +++ b/infra/dashboards/env/dev/backend.ini @@ -0,0 +1 @@ +subscription=DEV-SelfCare \ No newline at end of file diff --git a/infra/dashboards/env/dev/backend.tfvars b/infra/dashboards/env/dev/backend.tfvars new file mode 100644 index 000000000..89d9eb889 --- /dev/null +++ b/infra/dashboards/env/dev/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "terraform-state-rg" +storage_account_name = "tfappdevselfcare" +container_name = "terraform-state" +key = "selfcare-onboarding.dashboards.tfstate" \ No newline at end of file diff --git a/infra/dashboards/env/dev/terraform.tfvars b/infra/dashboards/env/dev/terraform.tfvars new file mode 100644 index 000000000..c03dfde15 --- /dev/null +++ b/infra/dashboards/env/dev/terraform.tfvars @@ -0,0 +1,13 @@ +prefix = "selc" +env_short = "d" +location = "westeurope" + +subscription = "1ab5e788-3b98-4c63-bd05-de0c7388c853" + +tags = { + CreatedBy = "Terraform" + Environment = "Dev" + Owner = "SelfCare" + Source = "https://github.com/pagopa/selfcare-onboarding" + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} diff --git a/infra/dashboards/env/prod/backend.ini b/infra/dashboards/env/prod/backend.ini new file mode 100644 index 000000000..0343b4a0d --- /dev/null +++ b/infra/dashboards/env/prod/backend.ini @@ -0,0 +1 @@ +subscription=PROD-SelfCare \ No newline at end of file diff --git a/infra/dashboards/env/prod/backend.tfvars b/infra/dashboards/env/prod/backend.tfvars new file mode 100644 index 000000000..9401301b3 --- /dev/null +++ b/infra/dashboards/env/prod/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "terraform-state-rg" +storage_account_name = "tfappprodselfcare" +container_name = "terraform-state" +key = "selfcare-onboarding.dashboards.tfstate" \ No newline at end of file diff --git a/infra/dashboards/env/prod/terraform.tfvars b/infra/dashboards/env/prod/terraform.tfvars new file mode 100644 index 000000000..41d61a833 --- /dev/null +++ b/infra/dashboards/env/prod/terraform.tfvars @@ -0,0 +1,13 @@ +prefix = "selc" +env_short = "p" +location = "westeurope" + +subscription = "813119d7-0943-46ed-8ebe-cebe24f9106c" + +tags = { + CreatedBy = "Terraform" + Environment = "Prod" + Owner = "SelfCare" + Source = "https://github.com/pagopa/selfcare-onboarding" + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} diff --git a/infra/dashboards/env/uat/backend.ini b/infra/dashboards/env/uat/backend.ini new file mode 100644 index 000000000..8cadfd658 --- /dev/null +++ b/infra/dashboards/env/uat/backend.ini @@ -0,0 +1 @@ +subscription=UAT-SelfCare \ No newline at end of file diff --git a/infra/dashboards/env/uat/backend.tfvars b/infra/dashboards/env/uat/backend.tfvars new file mode 100644 index 000000000..54196b241 --- /dev/null +++ b/infra/dashboards/env/uat/backend.tfvars @@ -0,0 +1,4 @@ +resource_group_name = "terraform-state-rg" +storage_account_name = "tfappuatselfcare" +container_name = "terraform-state" +key = "selfcare-onboarding.dashboards.tfstate" \ No newline at end of file diff --git a/infra/dashboards/env/uat/terraform.tfvars b/infra/dashboards/env/uat/terraform.tfvars new file mode 100644 index 000000000..7361726eb --- /dev/null +++ b/infra/dashboards/env/uat/terraform.tfvars @@ -0,0 +1,13 @@ +prefix = "selc" +env_short = "u" +location = "westeurope" + +subscription = "f47d50dc-b874-4e04-9d5c-c27f5053a651" + +tags = { + CreatedBy = "Terraform" + Environment = "Uat" + Owner = "SelfCare" + Source = "https://github.com/pagopa/selfcare-onboarding" + CostCenter = "TS310 - PAGAMENTI & SERVIZI" +} diff --git a/infra/dashboards/locals.tf b/infra/dashboards/locals.tf new file mode 100644 index 000000000..a650b9a4f --- /dev/null +++ b/infra/dashboards/locals.tf @@ -0,0 +1,4 @@ +locals { + pnpg_suffix = var.is_pnpg == true ? "-pnpg" : "" + project = "selc-${var.env_short}" +} \ No newline at end of file diff --git a/infra/dashboards/main.tf b/infra/dashboards/main.tf new file mode 100644 index 000000000..3c733d0f9 --- /dev/null +++ b/infra/dashboards/main.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">=1.6.0" + + required_providers { + azuread = { + source = "hashicorp/azuread" + version = "2.53.1" + } + azurerm = { + source = "hashicorp/azurerm" + version = "<= 4.3.0" + } + github = { + source = "integrations/github" + version = "5.18.3" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} + subscription_id = var.subscription +} + +provider "github" { + owner = "pagopa" +} + +data "azurerm_subscription" "current" {} + +data "azurerm_client_config" "current" {} \ No newline at end of file diff --git a/infra/dashboards/monitor.tf b/infra/dashboards/monitor.tf new file mode 100644 index 000000000..939bc76d1 --- /dev/null +++ b/infra/dashboards/monitor.tf @@ -0,0 +1,19 @@ +resource "azurerm_resource_group" "monitor_rg" { + name = "${local.project}-monitor-rg" + location = var.location + + tags = var.tags +} + +resource "azurerm_portal_dashboard" "monitoring_onboarding_event" { + name = "${local.project}-monitoring-onboarding-event" + resource_group_name = azurerm_resource_group.monitor_rg.name + location = azurerm_resource_group.monitor_rg.location + tags = var.tags + + dashboard_properties = templatefile("monitoring.json", + { + subscription_id = data.azurerm_subscription.current.subscription_id + prefix = "${var.prefix}-${var.env_short}" + }) +} \ No newline at end of file diff --git a/infra/dashboards/monitoring.json b/infra/dashboards/monitoring.json new file mode 100644 index 000000000..6fc16bcbd --- /dev/null +++ b/infra/dashboards/monitoring.json @@ -0,0 +1,895 @@ +{ +"lenses": { + "0": { + "order": 0, + "parts": { + "0": { + "position": { + "x": 0, + "y": 0, + "colSpan": 9, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "132be8c1-1242-42a1-a954-836f8a91ad0d", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-CDC\"\n| where customMeasurements contains \"OnboardingsUpdate_successes\"\n| where customDimensions contains \"_id\"\n| extend d=parse_json(customDimensions)\n| extend documentKey = d[\"documentKey\"]\n| project-rename onboardingId = documentKey\n| project timestamp, onboardingId\n| summarize Count = count() by bin(timestamp, 6h)\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "FrameControlChart", + "isOptional": true + }, + { + "name": "SpecificChart", + "value": "Line", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "value": { + "xAxis": { + "name": "timestamp", + "type": "datetime" + }, + "yAxis": [ + { + "name": "Count", + "type": "long" + } + ], + "splitBy": [], + "aggregation": "Sum" + }, + "isOptional": true + }, + { + "name": "LegendOptions", + "value": { + "isEnabled": true, + "position": "Bottom" + }, + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "PartTitle": "Count Notification invocations with success" + } + } + } + }, + "1": { + "position": { + "x": 9, + "y": 0, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "142201b2-14f6-41ea-a3d7-2863c2e13f52", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-CDC\"\n| where customMeasurements contains \"OnboardingsUpdate_successes\"\n| where customDimensions contains \"_id\"\n| extend d=parse_json(customDimensions)\n| extend documentKey = d[\"documentKey\"]\n| project-rename onboardingId = documentKey\n| project onboardingId\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "AnalyticsGrid", + "isOptional": true + }, + { + "name": "SpecificChart", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "isOptional": true + }, + { + "name": "LegendOptions", + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "GridColumnsWidth": { + "onboardingId": "473.993px" + }, + "PartTitle": "Onboarding id of successfull Notification invocations" + } + } + } + }, + "2": { + "position": { + "x": 0, + "y": 4, + "colSpan": 9, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "3cd8d57f-822a-4186-b0e4-490fe4b17a7d", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-CDC\"\n| where customMeasurements contains \"OnboardingsUpdate_failures\"\n| where customDimensions contains \"_id\"\n| extend d=parse_json(customDimensions)\n| extend documentKey = d[\"documentKey\"]\n| where documentKey contains \"_id\"\n| project-rename onboardingId = documentKey\n| project timestamp, onboardingId\n| summarize Count = count() by bin(timestamp, 6h)\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "FrameControlChart", + "isOptional": true + }, + { + "name": "SpecificChart", + "value": "Line", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "value": { + "xAxis": { + "name": "timestamp", + "type": "datetime" + }, + "yAxis": [ + { + "name": "Count", + "type": "long" + } + ], + "splitBy": [], + "aggregation": "Sum" + }, + "isOptional": true + }, + { + "name": "LegendOptions", + "value": { + "isEnabled": true, + "position": "Bottom" + }, + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "PartTitle": "Count Notification invocations with failure" + } + } + } + }, + "3": { + "position": { + "x": 9, + "y": 4, + "colSpan": 6, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "0720210f-9b58-4ec8-a73e-5847668a9298", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-CDC\"\n| where customMeasurements contains \"OnboardingsUpdate_failures\"\n| where customDimensions contains \"_id\"\n| extend d=parse_json(customDimensions)\n| extend documentKey = d[\"documentKey\"]\n| where documentKey contains \"_id\"\n| project-rename onboardingId = documentKey\n| project onboardingId\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "AnalyticsGrid", + "isOptional": true + }, + { + "name": "SpecificChart", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "isOptional": true + }, + { + "name": "LegendOptions", + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "GridColumnsWidth": { + "onboardingId": "506px" + }, + "PartTitle": "Onboarding id of failed Notification invocations" + } + } + } + }, + "4": { + "position": { + "x": 0, + "y": 8, + "colSpan": 7, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "81d9d129-c43b-4a75-a9a5-0f011489a1d4", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-FN\"\n| extend d=parse_json(customDimensions)\n| where d[\"topic\"] == \"SC-Contracts\"\n| order by timestamp desc\n| project timestamp\n| summarize Count = count() by bin(timestamp, 6h)\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "FrameControlChart", + "isOptional": true + }, + { + "name": "SpecificChart", + "value": "Line", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "value": { + "xAxis": { + "name": "timestamp", + "type": "datetime" + }, + "yAxis": [ + { + "name": "Count", + "type": "long" + } + ], + "splitBy": [], + "aggregation": "Sum" + }, + "isOptional": true + }, + { + "name": "LegendOptions", + "value": { + "isEnabled": true, + "position": "Bottom" + }, + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "PartTitle": "Count Notifications sent on SC-Contracts" + } + } + } + }, + "5": { + "position": { + "x": 7, + "y": 8, + "colSpan": 9, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "11ff3635-154f-4581-8e01-363be8dc88ad", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "P7D", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-FN\"\n| extend d=parse_json(customDimensions)\n| where d[\"topic\"] == \"SC-Contracts\"\n| order by timestamp desc\n| project timestamp, d\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "AnalyticsGrid", + "isOptional": true + }, + { + "name": "SpecificChart", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "isOptional": true + }, + { + "name": "LegendOptions", + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "GridColumnsWidth": { + "d": "595.998px" + }, + "PartTitle": "Notifications sent on SC-Contracts" + } + } + } + }, + "6": { + "position": { + "x": 0, + "y": 12, + "colSpan": 7, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "410407fc-0aa7-4ef1-9998-0136a1110502", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "2024-09-10T06:50:21.000Z/2024-10-04T06:50:21.381Z", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-FN\"\n| extend d=parse_json(customDimensions)\n| where d[\"topic\"] == \"SC-Contracts-SAP\"\n| order by timestamp desc\n| project timestamp\n| summarize Count = count() by bin(timestamp, 6h)\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "FrameControlChart", + "isOptional": true + }, + { + "name": "SpecificChart", + "value": "Line", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "value": { + "xAxis": { + "name": "timestamp", + "type": "datetime" + }, + "yAxis": [ + { + "name": "Count", + "type": "long" + } + ], + "splitBy": [], + "aggregation": "Sum" + }, + "isOptional": true + }, + { + "name": "LegendOptions", + "value": { + "isEnabled": true, + "position": "Bottom" + }, + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "PartTitle": "Count Notifications sent on SC-Contracts-SAP" + } + } + } + }, + "7": { + "position": { + "x": 7, + "y": 12, + "colSpan": 9, + "rowSpan": 4 + }, + "metadata": { + "inputs": [ + { + "name": "resourceTypeMode", + "isOptional": true + }, + { + "name": "ComponentId", + "isOptional": true + }, + { + "name": "Scope", + "value": { + "resourceIds": [ + "/subscriptions/${subscription_id}/resourceGroups/${prefix}-monitor-rg/providers/microsoft.insights/components/${prefix}-appinsights" + ] + }, + "isOptional": true + }, + { + "name": "PartId", + "value": "12f6ef02-2b87-4163-af10-695d5fc7d51f", + "isOptional": true + }, + { + "name": "Version", + "value": "2.0", + "isOptional": true + }, + { + "name": "TimeRange", + "value": "2024-09-10T06:50:21.000Z/2024-10-04T06:50:21.381Z", + "isOptional": true + }, + { + "name": "DashboardId", + "isOptional": true + }, + { + "name": "DraftRequestParameters", + "isOptional": true + }, + { + "name": "Query", + "value": "customEvents\n| where name contains \"ONBOARDING-FN\"\n| extend d=parse_json(customDimensions)\n| where d[\"topic\"] == \"SC-Contracts-SAP\"\n| order by timestamp desc\n| project timestamp, d\n", + "isOptional": true + }, + { + "name": "ControlType", + "value": "AnalyticsGrid", + "isOptional": true + }, + { + "name": "SpecificChart", + "isOptional": true + }, + { + "name": "PartTitle", + "value": "Analytics", + "isOptional": true + }, + { + "name": "PartSubTitle", + "value": "${prefix}-appinsights", + "isOptional": true + }, + { + "name": "Dimensions", + "isOptional": true + }, + { + "name": "LegendOptions", + "isOptional": true + }, + { + "name": "IsQueryContainTimeRange", + "value": false, + "isOptional": true + } + ], + "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart", + "settings": { + "content": { + "PartTitle": "Notifications sent on SC-Contracts-SAP" + } + } + } + } + } + } +}, +"metadata": { + "model": { + "timeRange": { + "value": { + "relative": { + "duration": 24, + "timeUnit": 1 + } + }, + "type": "MsPortalFx.Composition.Configuration.ValueTypes.TimeRange" + }, + "filterLocale": { + "value": "en-us" + }, + "filters": { + "value": { + "MsPortalFx_TimeRange": { + "model": { + "format": "utc", + "granularity": "auto", + "relative": "24h" + }, + "displayCache": { + "name": "UTC Time", + "value": "Past 24 hours" + }, + "filteredPartIds": [ + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc812f", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc817c", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc81a7", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc81dc", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc8219", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc82ae", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc82fd", + "StartboardPart-LogsDashboardPart-5b5cf61c-c51a-40ae-944f-f80f33cc8355" + ] + } + } + } + } +} +} \ No newline at end of file diff --git a/infra/dashboards/terraform.sh b/infra/dashboards/terraform.sh new file mode 100755 index 000000000..e8fe04251 --- /dev/null +++ b/infra/dashboards/terraform.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +set -e + +action=$1 +env=$2 +shift 2 +other=$@ +# must be subscription in lower case +subscription="" +BACKEND_CONFIG_PATH="./env/${ENV}/backend.tfvars" + +if [ -z "$action" ]; then + echo "Missed action: init, apply, plan" + exit 0 +fi + +if [ -z "$env" ]; then + echo "env should be: dev, uat or prod." + exit 0 +fi + +source "./env/$env/backend.ini" + +az account set -s "${subscription}" + +# if using cygwin, we have to transcode the WORKDIR +if [[ $WORKDIR == /cygdrive/* ]]; then + WORKDIR=$(cygpath -w $WORKDIR) +fi + +if [ "$action" = "force-unlock" ]; then + echo "🧭 terraform INIT in env: ${env}" + terraform init -reconfigure -backend-config="./env/$env/backend.tfvars" $other + warn_message="You are about to unlock Terraform's remote state. + This is a dangerous task you want to be aware of before going on. + This operation won't affect your infrastructure directly. + However, please note that you may lose pieces of information about partially-applied configurations. + + Please refer to the official Terraform documentation about the command: + https://developer.hashicorp.com/terraform/cli/commands/force-unlock" + printf "\n\e[33m%s\e[0m\n\n" "$warn_message" + + read -r -p "Please enter the LOCK ID: " lock_id + terraform force-unlock "$lock_id" + + exit 0 # this line prevents the script to go on +fi + +if echo "init plan apply refresh import output state taint destroy" | grep -w "$action" > /dev/null; then + if [ "$action" = "init" ]; then + echo "🧭 terraform INIT in env: ${env}" + terraform "$action" -reconfigure -backend-config="./env/$env/backend.tfvars" $other + elif [ "$action" = "output" ] || [ "$action" = "state" ] || [ "$action" = "taint" ]; then + # init terraform backend + echo "🧭 terraform (output|state|taint) launched with action: ${action} in env: ${env}" + terraform init -reconfigure -backend-config="./env/$env/backend.tfvars" + terraform "$action" $other + else + # init terraform backend + echo "🧭 terraform launched with action: ${action} in env: ${env}" + + terraform init -reconfigure -backend-config="./env/$env/backend.tfvars" + terraform "$action" -var-file="./env/$env/terraform.tfvars" $other + fi +else + echo "Action not allowed." + exit 1 +fi \ No newline at end of file diff --git a/infra/dashboards/variables.tf b/infra/dashboards/variables.tf new file mode 100644 index 000000000..c4a9b8ffa --- /dev/null +++ b/infra/dashboards/variables.tf @@ -0,0 +1,43 @@ +variable "is_pnpg" { + type = bool + default = false + description = "(Optional) True if you want to apply changes to PNPG environment" +} + +variable "prefix" { + description = "Domain prefix" + type = string + default = "selc" + validation { + condition = ( + length(var.prefix) <= 6 + ) + error_message = "Max length is 6 chars." + } +} + +variable "env_short" { + description = "Environment short name" + type = string + validation { + condition = ( + length(var.env_short) <= 1 + ) + error_message = "Max length is 1 chars." + } +} + +variable "tags" { + type = map(any) +} + + +variable "subscription" { + type = string +} + + +variable "location" { + type = string + default = "westeurope" +} From c892cf0196e0cc91d057f8a1e302918df338f539 Mon Sep 17 00:00:00 2001 From: andrea-putzu <106688558+andrea-putzu@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:12:30 +0200 Subject: [PATCH 12/27] [SELC-5332] chore: Add gh infra apply pipeline (#536) Co-authored-by: empassaro --- .../workflows/release_dashboard_events.yml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/release_dashboard_events.yml diff --git a/.github/workflows/release_dashboard_events.yml b/.github/workflows/release_dashboard_events.yml new file mode 100644 index 000000000..0c933aa8e --- /dev/null +++ b/.github/workflows/release_dashboard_events.yml @@ -0,0 +1,48 @@ +name: Deploy dashboard events infra + +on: + push: + branches: + - main + - releases/* + paths: + - './infra/dashboards' + + workflow_dispatch: + inputs: + env: + type: choice + description: Environment + options: + - dev + - uat + - prod + +jobs: + + release_dev: + uses: ./.github/workflows/call_release_infra.yml + name: '[Dev] Dashboard events Infra Release' + if: ${{ (startsWith(github.ref_name, 'releases/') != true && inputs.env == null) || inputs.env == 'dev' }} + secrets: inherit + with: + environment: dev + dir: ./infra/dashboards + + release_uat: + uses: ./.github/workflows/call_release_infra.yml + name: '[UAT] Dashboard events Infra Release' + if: ${{ (startsWith(github.ref_name, 'releases/') == true && inputs.env == null) || inputs.env == 'uat' }} + secrets: inherit + with: + environment: uat + dir: ./infra/dashboards + + release_prod: + uses: ./.github/workflows/call_release_infra.yml + name: '[Prod] Dashboard events Infra Release' + if: ${{ inputs.env == 'prod' }} + secrets: inherit + with: + environment: prod + dir: ./infra/dashboards \ No newline at end of file From 3a3414e418c61f139bc1fde873f1c765171884e8 Mon Sep 17 00:00:00 2001 From: Manuel Rafeli Date: Tue, 8 Oct 2024 16:49:34 +0200 Subject: [PATCH 13/27] [SELC-5629] fix: handle institutionType null on validRoles (#537) --- apps/onboarding-functions/pom.xml | 6 +++--- apps/onboarding-ms/pom.xml | 4 ++-- apps/pom.xml | 2 +- libs/onboarding-sdk-azure-storage/pom.xml | 2 +- libs/onboarding-sdk-common/pom.xml | 2 +- libs/onboarding-sdk-crypto/pom.xml | 2 +- libs/onboarding-sdk-pom/pom.xml | 2 +- libs/onboarding-sdk-product/pom.xml | 4 ++-- .../it/pagopa/selfcare/product/utils/ProductUtils.java | 7 ++++++- test-coverage/pom.xml | 8 ++++---- 10 files changed, 22 insertions(+), 17 deletions(-) diff --git a/apps/onboarding-functions/pom.xml b/apps/onboarding-functions/pom.xml index 4d3f463bd..b3350a6b7 100644 --- a/apps/onboarding-functions/pom.xml +++ b/apps/onboarding-functions/pom.xml @@ -193,17 +193,17 @@ it.pagopa.selfcare onboarding-sdk-crypto - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-product - 0.3.1 + 0.3.2 org.apache.commons diff --git a/apps/onboarding-ms/pom.xml b/apps/onboarding-ms/pom.xml index 3b4a72ffc..2993ad38a 100644 --- a/apps/onboarding-ms/pom.xml +++ b/apps/onboarding-ms/pom.xml @@ -243,12 +243,12 @@ it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-product - 0.3.1 + 0.3.2 diff --git a/apps/pom.xml b/apps/pom.xml index ea291c017..560be3dce 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -16,7 +16,7 @@ it.pagopa.selfcare onboarding-sdk-common - 0.3.1 + 0.3.2 diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml index c79aed3d4..f6b8261a8 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.3.1 + 0.3.2 ../onboarding-sdk-pom diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml index 753a353b0..bc6bceae8 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.3.1 + 0.3.2 ../onboarding-sdk-pom onboarding-sdk-common diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml index 8152a65ba..9a90f9910 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.3.1 + 0.3.2 ../onboarding-sdk-pom onboarding-sdk-crypto diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml index 6f8f9a8c7..979c7a61f 100644 --- a/libs/onboarding-sdk-pom/pom.xml +++ b/libs/onboarding-sdk-pom/pom.xml @@ -6,7 +6,7 @@ onboarding-sdk-pom pom onboarding-sdk-pom - 0.3.1 + 0.3.2 17 diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index 6951051c1..7b0c46153 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.3.1 + 0.3.2 ../onboarding-sdk-pom onboarding-sdk-product onboarding-sdk-product - 0.3.1 + 0.3.2 2.15.2 diff --git a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/utils/ProductUtils.java b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/utils/ProductUtils.java index d262f0f30..8f109d988 100644 --- a/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/utils/ProductUtils.java +++ b/libs/onboarding-sdk-product/src/main/java/it/pagopa/selfcare/product/utils/ProductUtils.java @@ -50,7 +50,12 @@ private static List> validEntryRoles(Produ if (Objects.isNull(product)) { throw new IllegalArgumentException("Product must not be null!"); } - return Optional.ofNullable(product.getRoleMappings(institutionType.name())) + + String institutionTypeName = Optional.ofNullable(institutionType) + .map(InstitutionType::name) + .orElse(null); + + return Optional.ofNullable(product.getRoleMappings(institutionTypeName)) .orElse(Map.of()) .entrySet().stream() .filter(entry -> Objects.nonNull(entry.getValue().getPhasesAdditionAllowed()) && diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index 60e706314..b26b0b1bf 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -77,22 +77,22 @@ it.pagopa.selfcare onboarding-sdk-product - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-common - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.1 + 0.3.2 it.pagopa.selfcare onboarding-sdk-crypto - 0.3.1 + 0.3.2 From d6d35c260ab23eaa74a5f83960d5bc1f750ecb5b Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Wed, 9 Oct 2024 09:12:37 +0200 Subject: [PATCH 14/27] [SELC-5602] feat: Added setup google-java-format --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index e7790f99b..dcf994495 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,19 @@ and usage of a couple of lesser known command line switches. | Change version of `onboarding-sdk` | `.` | `mvn versions:set -DnewVersion=0.2.2 --projects :onboarding-sdk-pom ` | | Persist version of `onboarding-sdk` | `.` | `mvn versions:commit ` | +----- + +## Java formatter installation (Intellij) + +1. Open plugins window (CTRL+Shift+A or CMD+Shift+A) and type "plugins" +2. Click on browse repositories. +3. Search for google-java-format and install it +4. Restart the IDE. + +To enable the plugin executing the action (CTRL+Shift+A or CMD+Shift+A) ant type: Reformat with google-java-format + +Enable auto-format on save: + +1. File -> Settings -> Tools or CTRL+Alt+S/CMD+Alt+S -> Tools +2. Click on "Action on Save" +3. Enable: "Reformat Code" \ No newline at end of file From bdf506d30aeb920611323c4a09d3201e5df706e1 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:49:45 +0200 Subject: [PATCH 15/27] [SELC-5736] feat: populate aggregates csv placeholder for prod-pagopa in PRV contract (#539) --- .../selfcare/onboarding/service/ContractServiceDefault.java | 2 +- .../java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java index efc9587da..1ddf059bd 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -146,7 +146,7 @@ private File createPdfFileContract(String contractTemplatePath, Onboarding onboa setupPSPData(data, manager, onboarding); } else if (PROD_PAGOPA.getValue().equalsIgnoreCase(productId) && InstitutionType.PRV == institution.getInstitutionType()) { - setupPRVData(data, onboarding); + setupPRVData(data, onboarding, baseUrl.toString()); } else if (PROD_PAGOPA.getValue().equalsIgnoreCase(productId) && InstitutionType.PSP != institution.getInstitutionType() && InstitutionType.PT != institution.getInstitutionType()) { diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java index 05baa4822..ac6ac1d58 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/PdfMapper.java @@ -31,7 +31,7 @@ public class PdfMapper { public static final String INSTITUTION_REGISTER_LABEL_VALUE = "institutionRegisterLabelValue"; public static final String CSV_AGGREGATES_LABEL_VALUE = "aggregatesCsvLink"; public static final String ORIGIN_ID_LABEL = "
  • codice di iscrizione all’Indice delle Pubbliche Amministrazioni e dei gestori di pubblici servizi (I.P.A.) ${originId}
  • "; - public static final String CSV_AGGREGATES_LABEL = ""; + public static final String CSV_AGGREGATES_LABEL = " - Dati di Enti Aggregati"; public static final String INSTITUTION_RECIPIENT_CODE = "institutionRecipientCode"; private PdfMapper() { @@ -119,7 +119,6 @@ public static void setupPSPData(Map map, UserResource validManag .findFirst() .map(userMailUuid -> getMailManager(validManager, userMailUuid)) .ifPresent(mail -> map.put("managerPEC", mail)); - } public static void setECData(Map map, Onboarding onboarding) { @@ -129,7 +128,7 @@ public static void setECData(Map map, Onboarding onboarding) { map.put(INSTITUTION_BUSINESS_REGISTER_PLACE, Optional.ofNullable(institution.getBusinessRegisterPlace()).orElse(UNDERSCORE)); } - public static void setupPRVData(Map map, Onboarding onboarding) { + public static void setupPRVData(Map map, Onboarding onboarding, String baseUrl) { addInstitutionRegisterLabelValue(onboarding.getInstitution(), map); if (onboarding.getBilling() != null) { @@ -137,6 +136,7 @@ public static void setupPRVData(Map map, Onboarding onboarding) } setECData(map, onboarding); + addAggregatesCsvLink(onboarding, map, baseUrl); } public static void setupProdIOData(Onboarding onboarding, Map map, UserResource validManager) { From 60c57912324bb46cc7d72a1914b1f96b572a2e7d Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:56:17 +0200 Subject: [PATCH 16/27] [SELC-5733] feat: create aggregates csv for prod-pagopa (#538) --- .../entity/AggregateInstitution.java | 49 ++++++++++ .../service/ContractServiceDefault.java | 87 ++++++++++++----- .../onboarding/utils/GenericError.java | 5 +- .../service/ContractServiceDefaultTest.java | 94 +++++++++++++++++-- .../entity/AggregateInstitution.java | 1 - 5 files changed, 203 insertions(+), 33 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java index 4b7f0f9f4..88820735f 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java @@ -22,6 +22,12 @@ public class AggregateInstitution { private String originId; private Origin origin; private List users; + private String taxCodePT; + private String descriptionPT; + private String iban; + private String service; + private String syncAsyncMode; + private String recipientCode; public String getTaxCode() { return taxCode; @@ -119,5 +125,48 @@ public void setOriginId(String originId) { this.originId = originId; } + public String getTaxCodePT() { + return taxCodePT; + } + + public void setTaxCodePT(String taxCodePT) { + this.taxCodePT = taxCodePT; + } + + public String getDescriptionPT() { + return descriptionPT; + } + + public void setDescriptionPT(String descriptionPT) { this.descriptionPT = descriptionPT; } + + public String getIban() { + return iban; + } + + public void setIban(String iban) { + this.iban = iban; + } + + public String getService() { + return service; + } + + public void setService(String service) { this.service = service; } + + public String getSyncAsyncMode() { + return syncAsyncMode; + } + + public void setSyncAsyncMode(String syncAsyncMode) { + this.syncAsyncMode = syncAsyncMode; + } + + public String getRecipientCode() { + return recipientCode; + } + + public void setRecipientCode(String recipientCode) { + this.recipientCode = recipientCode; + } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java index 1ddf059bd..6b966c7e3 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -37,10 +37,10 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.function.Function; import static it.pagopa.selfcare.onboarding.common.ProductId.*; -import static it.pagopa.selfcare.onboarding.utils.GenericError.GENERIC_ERROR; -import static it.pagopa.selfcare.onboarding.utils.GenericError.UNABLE_TO_DOWNLOAD_FILE; +import static it.pagopa.selfcare.onboarding.utils.GenericError.*; import static it.pagopa.selfcare.onboarding.utils.PdfMapper.*; import static it.pagopa.selfcare.onboarding.utils.Utils.CONTRACT_FILENAME_FUNC; @@ -60,12 +60,45 @@ public class ContractServiceDefault implements ContractService { private final String logoPath; - private static final String[] CSV_HEADERS = { + private static final String[] CSV_HEADERS_IO = { "Ragione Sociale", "PEC", "Codice Fiscale", "P.IVA", "Sede legale - Indirizzo", "Sede legale - Citta'", "Sede legale - Provincia (Sigla)", "Codice IPA", "AOO/UO", "Codice Univoco" }; + private static final String[] CSV_HEADERS_PAGOPA = { + "Ragione Sociale", "PEC", "Codice Fiscale", "P.IVA", + "Sede legale - Indirizzo", "Sede legale - Citta'", "Sede legale - Provincia (Sigla)", + "Ragione Sociale Partener Tecnologico", "Codice Fiscale Partner Tecnologico", + "IBAN", "Servizio", "Modalità Sincrona/Asincrona" + }; + + private static final Function> IO_MAPPER = institution -> Arrays.asList( + institution.getDescription(), + institution.getDigitalAddress(), + institution.getTaxCode(), + institution.getVatNumber(), + institution.getAddress(), + institution.getCity(), + institution.getCounty(), + Optional.ofNullable(institution.getSubunitType()).map(originId -> "").orElse(institution.getOriginId()), + institution.getSubunitType(), + institution.getSubunitCode()); + + private static final Function> PAGOPA_MAPPER = institution -> Arrays.asList( + institution.getDescription(), + institution.getDigitalAddress(), + institution.getTaxCode(), + institution.getVatNumber(), + institution.getAddress(), + institution.getCity(), + institution.getCounty(), + institution.getDescriptionPT(), + institution.getTaxCodePT(), + institution.getIban(), + institution.getService(), + institution.getSyncAsyncMode()); + public ContractServiceDefault(AzureStorageConfig azureStorageConfig, AzureBlobClient azureBlobClient, PadesSignService padesSignService, @@ -271,23 +304,46 @@ public void uploadAggregatesCsv(OnboardingWorkflow onboardingWorkflow) { try { Onboarding onboarding = onboardingWorkflow.getOnboarding(); Path filePath = Files.createTempFile("tempfile", ".csv"); - File csv = generateCsv(onboarding.getAggregates(), filePath); + File csv = generateAggregatesCsv(onboarding.getProductId(), onboarding.getAggregates(), filePath); final String path = String.format("%s%s/%s", azureStorageConfig.aggregatesPath(), onboarding.getId(), onboarding.getProductId()); final String filename = "aggregates.csv"; azureBlobClient.uploadFile(path, filename, Files.readAllBytes(csv.toPath())); } catch (IOException e) { - throw new GenericOnboardingException(String.format("Can not load aggregates CSV, message: %s", e.getMessage())); + throw new GenericOnboardingException(String.format(LOAD_AGGREGATES_CSV_ERROR.getMessage(), e.getMessage())); } } - private File generateCsv(List institutions, Path filePath) { + private File generateAggregatesCsv(String productId, List institutions, Path filePath) { + String[] headers; + Function> mapper; + + // Determine headers and mapping logic based on productId + switch (productId) { + case "prod-io": + headers = CSV_HEADERS_IO; + mapper = IO_MAPPER; + break; + case "prod-pagopa": + headers = CSV_HEADERS_PAGOPA; + mapper = PAGOPA_MAPPER; + break; + case "prod-pn": + return new File(String.valueOf(filePath)); //prod-pn is available for aggregator's workflow but csv structure is still not defined. + default: + throw new IllegalArgumentException(String.format("Product %s is not available for aggregators", productId)); + } + + return createAggregatesCsv(institutions, filePath, headers, mapper); + } + + private File createAggregatesCsv(List institutions, Path filePath, String[] headers, Function> mapper) { File csvFile = filePath.toFile(); // Using the builder pattern to create the CSV format with headers CSVFormat csvFormat = CSVFormat.Builder.create(CSVFormat.DEFAULT) - .setHeader(CSV_HEADERS) + .setHeader(headers) .setDelimiter(';') .build(); @@ -296,24 +352,11 @@ private File generateCsv(List institutions, Path filePath) // Iterate over each AggregateInstitution object and write a row for each one for (AggregateInstitution institution : institutions) { - - // Write the row with the institution data - csvPrinter.printRecord( - institution.getDescription(), - institution.getDigitalAddress(), - institution.getTaxCode(), - institution.getVatNumber(), - institution.getAddress(), - institution.getCity(), - institution.getCounty(), - Optional.ofNullable(institution.getSubunitType()).map(originId -> "").orElse(institution.getOriginId()), - institution.getSubunitType(), - institution.getSubunitCode() - ); + csvPrinter.printRecord(mapper.apply(institution)); } } catch (IOException e) { - throw new GenericOnboardingException(String.format("Can not create aggregates CSV, message: %s", e.getMessage())); + throw new GenericOnboardingException(String.format(CREATE_AGGREGATES_CSV_ERROR.getMessage(), e.getMessage())); } return csvFile; } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java index 497a9a717..a52879b2c 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/GenericError.java @@ -57,7 +57,10 @@ public enum GenericError { GET_INSTITUTION_BY_PRODUCTID_ERROR("0053", "Error while searching institutions related to given productId"), VERIFY_USER_ERROR("0000", "Error while searching institutions related to given productId"), GET_USER_ERROR("0000", "Error while searching user given UserID"), - GENERIC_ERROR("0000", "Generic Error"); + GENERIC_ERROR("0000", "Generic Error"), + LOAD_AGGREGATES_CSV_ERROR("0000", "Can not load aggregates CSV, message: %s"), + CREATE_AGGREGATES_CSV_ERROR("0000", "Can not create aggregates CSV, message: %s"); + private final String code; private final String detail; diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java index 75381e1f1..d447c616a 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefaultTest.java @@ -10,6 +10,7 @@ import it.pagopa.selfcare.onboarding.crypto.PadesSignService; import it.pagopa.selfcare.onboarding.entity.*; import jakarta.inject.Inject; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -21,7 +22,6 @@ import org.openapi.quarkus.user_registry_json.model.WorkContactResource; import java.io.File; -import java.io.IOException; import java.util.*; import static org.junit.jupiter.api.Assertions.*; @@ -80,7 +80,7 @@ private Onboarding createOnboarding() { return onboarding; } - AggregateInstitution createAggregateInstitution(int number) { + AggregateInstitution createAggregateInstitutionIO(int number) { AggregateInstitution aggregateInstitution = new AggregateInstitution(); aggregateInstitution.setTaxCode(String.format("taxCode%s", number)); aggregateInstitution.setOriginId(String.format("originId%s", number)); @@ -93,24 +93,58 @@ AggregateInstitution createAggregateInstitution(int number) { return aggregateInstitution; } - AggregateInstitution createAggregateInstitutionAOO(int number) { - AggregateInstitution aggregateInstitution = createAggregateInstitution(number); + AggregateInstitution createAggregateInstitutionAOO_IO(int number) { + AggregateInstitution aggregateInstitution = createAggregateInstitutionIO(number); aggregateInstitution.setSubunitType("AOO"); aggregateInstitution.setSubunitCode(String.format("code%s", number)); return aggregateInstitution; } - OnboardingWorkflow createOnboardingWorkflow() { + AggregateInstitution createAggregateInstitutionPagoPa(int number) { + AggregateInstitution aggregateInstitution = new AggregateInstitution(); + aggregateInstitution.setTaxCode(String.format("taxCode%s", number)); + aggregateInstitution.setDescription(String.format("description%s", number)); + aggregateInstitution.setVatNumber(String.format("vatNumber%s", number)); + aggregateInstitution.setAddress(String.format("address%s", number)); + aggregateInstitution.setCity(String.format("city%s", number)); + aggregateInstitution.setCounty(String.format("county%s", number)); + aggregateInstitution.setDigitalAddress(String.format("pec%s", number)); + aggregateInstitution.setTaxCodePT(String.format("taxCodePT%s", number)); + aggregateInstitution.setDescriptionPT(String.format("descriptionPT%s", number)); + aggregateInstitution.setIban(String.format("iban%s", number)); + aggregateInstitution.setService(String.format("service%s", number)); + aggregateInstitution.setSyncAsyncMode(String.format("mode%s", number)); + return aggregateInstitution; + } + + OnboardingWorkflow createOnboardingWorkflowIO() { Onboarding onboarding = createOnboarding(); + onboarding.setProductId("prod-io"); List aggregateInstitutionList = new ArrayList<>(); for (int i = 1; i <= 5; i++) { - AggregateInstitution aggregateInstitution = createAggregateInstitution(i); + AggregateInstitution aggregateInstitution = createAggregateInstitutionIO(i); aggregateInstitutionList.add(aggregateInstitution); } for(int i = 6; i<= 10; i++) { - AggregateInstitution aggregateInstitution = createAggregateInstitutionAOO(i); + AggregateInstitution aggregateInstitution = createAggregateInstitutionAOO_IO(i); + aggregateInstitutionList.add(aggregateInstitution); + } + + onboarding.setAggregates(aggregateInstitutionList); + + return new OnboardingWorkflowAggregator(onboarding, "string"); + + } + + OnboardingWorkflow createOnboardingWorkflowPagoPa() { + Onboarding onboarding = createOnboarding(); + onboarding.setProductId("prod-pagopa"); + List aggregateInstitutionList = new ArrayList<>(); + + for (int i = 1; i <= 7; i++) { + AggregateInstitution aggregateInstitution = createAggregateInstitutionPagoPa(i); aggregateInstitutionList.add(aggregateInstitution); } @@ -284,10 +318,10 @@ void getLogoFile() { @Test - void uploadCsvAggregates() throws IOException { + void uploadCsvAggregatesIO() { final String contractHtml = "contract"; - OnboardingWorkflow onboardingWorkflow = createOnboardingWorkflow(); + OnboardingWorkflow onboardingWorkflow = createOnboardingWorkflowIO(); Mockito.when(azureBlobClient.uploadFile(any(), any(), any())).thenReturn(contractHtml); @@ -298,6 +332,48 @@ void uploadCsvAggregates() throws IOException { } + @Test + void uploadCsvAggregatesPagoPa() { + final String contractHtml = "contract"; + + OnboardingWorkflow onboardingWorkflow = createOnboardingWorkflowPagoPa(); + + Mockito.when(azureBlobClient.uploadFile(any(), any(), any())).thenReturn(contractHtml); + + contractService.uploadAggregatesCsv(onboardingWorkflow); + + Mockito.verify(azureBlobClient, times(1)) + .uploadFile(any(), any(), any()); + + } + + @Test + void uploadCsvAggregatesProdPn() { + final String contractHtml = "contract"; + + Onboarding onboarding = createOnboarding(); + onboarding.setProductId("prod-pn"); + OnboardingWorkflow onboardingWorkflow = new OnboardingWorkflowAggregator(onboarding, "string"); + + Mockito.when(azureBlobClient.uploadFile(any(), any(), any())).thenReturn(contractHtml); + + contractService.uploadAggregatesCsv(onboardingWorkflow); + + Mockito.verify(azureBlobClient, times(1)) + .uploadFile(any(), any(), any()); + + } + + @Test + void uploadCsvAggregatesProductNotValid() { + Onboarding onboarding = createOnboarding(); + onboarding.setProductId("prod-interop"); + OnboardingWorkflow onboardingWorkflow = new OnboardingWorkflowAggregator(onboarding, "string");; + + Assertions.assertThrows(IllegalArgumentException.class, () -> contractService.uploadAggregatesCsv(onboardingWorkflow)); + + } + @Test void createContractPRV() { // given diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java index 2b44ef696..560b642a3 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/AggregateInstitution.java @@ -20,7 +20,6 @@ public class AggregateInstitution { private Origin origin; private String vatNumber; private List users; - private String recipientCode; private String digitalAddress; private String city; From 9dccc15f3a9d2af037f8e4be98f7c99012707398 Mon Sep 17 00:00:00 2001 From: empassaro <113031808+empassaro@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:38:43 +0200 Subject: [PATCH 17/27] [PNPG-248] feat: added new workflow type and updated pom versions (#542) --- apps/onboarding-functions/pom.xml | 6 +++--- apps/onboarding-ms/pom.xml | 4 ++-- apps/pom.xml | 2 +- libs/onboarding-sdk-azure-storage/pom.xml | 2 +- libs/onboarding-sdk-common/pom.xml | 2 +- .../pagopa/selfcare/onboarding/common/WorkflowType.java | 3 ++- 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 | 8 ++++---- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/onboarding-functions/pom.xml b/apps/onboarding-functions/pom.xml index b3350a6b7..3784316f3 100644 --- a/apps/onboarding-functions/pom.xml +++ b/apps/onboarding-functions/pom.xml @@ -193,17 +193,17 @@ it.pagopa.selfcare onboarding-sdk-crypto - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-product - 0.3.2 + 0.3.3 org.apache.commons diff --git a/apps/onboarding-ms/pom.xml b/apps/onboarding-ms/pom.xml index 2993ad38a..f57d3779d 100644 --- a/apps/onboarding-ms/pom.xml +++ b/apps/onboarding-ms/pom.xml @@ -243,12 +243,12 @@ it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-product - 0.3.2 + 0.3.3 diff --git a/apps/pom.xml b/apps/pom.xml index 560be3dce..c308d6e0e 100644 --- a/apps/pom.xml +++ b/apps/pom.xml @@ -16,7 +16,7 @@ it.pagopa.selfcare onboarding-sdk-common - 0.3.2 + 0.3.3 diff --git a/libs/onboarding-sdk-azure-storage/pom.xml b/libs/onboarding-sdk-azure-storage/pom.xml index f6b8261a8..8514cd073 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.3.2 + 0.3.3 ../onboarding-sdk-pom diff --git a/libs/onboarding-sdk-common/pom.xml b/libs/onboarding-sdk-common/pom.xml index bc6bceae8..9d1301c53 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.3.2 + 0.3.3 ../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 3d1452094..33e084910 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 @@ -11,5 +11,6 @@ public enum WorkflowType { IMPORT,//INSTITUTION CONTRACT_REGISTRATION_AGGREGATOR,//AGGREGATION CONFIRMATION_AGGREGATE,//AGGREGATION - INCREMENT_REGISTRATION_AGGREGATOR //AGGREGATION + INCREMENT_REGISTRATION_AGGREGATOR,//AGGREGATION + USERS_PG//USER } diff --git a/libs/onboarding-sdk-crypto/pom.xml b/libs/onboarding-sdk-crypto/pom.xml index 9a90f9910..5ef0dc549 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.3.2 + 0.3.3 ../onboarding-sdk-pom onboarding-sdk-crypto diff --git a/libs/onboarding-sdk-pom/pom.xml b/libs/onboarding-sdk-pom/pom.xml index 979c7a61f..23310d811 100644 --- a/libs/onboarding-sdk-pom/pom.xml +++ b/libs/onboarding-sdk-pom/pom.xml @@ -6,7 +6,7 @@ onboarding-sdk-pom pom onboarding-sdk-pom - 0.3.2 + 0.3.3 17 diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index 7b0c46153..ce7bf49e2 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.3.2 + 0.3.3 ../onboarding-sdk-pom onboarding-sdk-product onboarding-sdk-product - 0.3.2 + 0.3.3 2.15.2 diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index b26b0b1bf..ebd4b2feb 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -77,22 +77,22 @@ it.pagopa.selfcare onboarding-sdk-product - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-common - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-azure-storage - 0.3.2 + 0.3.3 it.pagopa.selfcare onboarding-sdk-crypto - 0.3.2 + 0.3.3 From 8295e0ca0ead3c2e498cbd3f86f0018a42a9a8a5 Mon Sep 17 00:00:00 2001 From: empassaro <113031808+empassaro@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:18:34 +0200 Subject: [PATCH 18/27] [PNPG-248] fix: build cdc issue. Adding new workflowType in openapi (#546) --- apps/onboarding-cdc/src/main/openapi/onboarding_functions.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json b/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json index a136e5596..2175c0e20 100644 --- a/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json +++ b/apps/onboarding-cdc/src/main/openapi/onboarding_functions.json @@ -509,7 +509,8 @@ "USERS_IMPORT", "CONTRACT_REGISTRATION_AGGREGATOR", "CONFIRMATION_AGGREGATE", - "INCREMENT_REGISTRATION_AGGREGATOR" + "INCREMENT_REGISTRATION_AGGREGATOR", + "USERS_PG" ], "type": "string" }, From 5ac219cc28d41542064483dbc993d7a21df2997d Mon Sep 17 00:00:00 2001 From: Giampiero Ferrara Date: Mon, 14 Oct 2024 16:30:54 +0200 Subject: [PATCH 19/27] [SELC-5748] feat: Added new API for update recipient code --- apps/onboarding-ms/src/main/docs/openapi.json | 41 +++++++++++++++ apps/onboarding-ms/src/main/docs/openapi.yaml | 30 +++++++++++ .../controller/OnboardingController.java | 38 +++++++++++--- .../onboarding/entity/Onboarding.java | 8 ++- .../controller/OnboardingControllerTest.java | 52 +++++++++++++++---- 5 files changed, 147 insertions(+), 22 deletions(-) diff --git a/apps/onboarding-ms/src/main/docs/openapi.json b/apps/onboarding-ms/src/main/docs/openapi.json index ddb57d9e0..6379e97f6 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.json +++ b/apps/onboarding-ms/src/main/docs/openapi.json @@ -19,6 +19,8 @@ "name" : "Onboarding" }, { "name" : "Onboarding Controller" + }, { + "name" : "billing-portal" }, { "name" : "internal-v1" }, { @@ -1247,6 +1249,45 @@ } ] } }, + "/v1/onboarding/{onboardingId}/recipient-code" : { + "put" : { + "tags" : [ "billing-portal", "Onboarding" ], + "summary" : "Update recipient code", + "description" : "Update recipient code receiving onboarding id.", + "operationId" : "updateOnboardingRecipientIdUsingPUT", + "parameters" : [ { + "name" : "onboardingId", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "recipientCode", + "in" : "query", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "OK", + "content" : { + "application/json" : { } + } + }, + "401" : { + "description" : "Not Authorized" + }, + "403" : { + "description" : "Not Allowed" + } + }, + "security" : [ { + "SecurityScheme" : [ ] + } ] + } + }, "/v1/onboarding/{onboardingId}/reject" : { "put" : { "tags" : [ "Onboarding Controller" ], diff --git a/apps/onboarding-ms/src/main/docs/openapi.yaml b/apps/onboarding-ms/src/main/docs/openapi.yaml index 3bf30d9fc..99e073ec8 100644 --- a/apps/onboarding-ms/src/main/docs/openapi.yaml +++ b/apps/onboarding-ms/src/main/docs/openapi.yaml @@ -13,6 +13,7 @@ tags: - name: Notification Controller - name: Onboarding - name: Onboarding Controller +- name: billing-portal - name: internal-v1 - name: support paths: @@ -918,6 +919,35 @@ paths: description: Not Allowed security: - SecurityScheme: [] + /v1/onboarding/{onboardingId}/recipient-code: + put: + tags: + - billing-portal + - Onboarding + summary: Update recipient code + description: Update recipient code receiving onboarding id. + operationId: updateOnboardingRecipientIdUsingPUT + parameters: + - name: onboardingId + in: path + required: true + schema: + type: string + - name: recipientCode + in: query + schema: + type: string + responses: + "200": + description: OK + content: + application/json: {} + "401": + description: Not Authorized + "403": + description: Not Allowed + security: + - SecurityScheme: [] /v1/onboarding/{onboardingId}/reject: put: tags: 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 a02494986..a9736ebf4 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; @@ -10,6 +12,7 @@ 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.Onboarding; import it.pagopa.selfcare.onboarding.exception.ResourceNotFoundException; import it.pagopa.selfcare.onboarding.mapper.OnboardingMapper; @@ -24,7 +27,11 @@ 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; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.extensions.Extension; @@ -32,16 +39,11 @@ 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") @AllArgsConstructor +@Slf4j public class OnboardingController { private final OnboardingService onboardingService; @@ -419,6 +421,30 @@ public Uni update(@PathParam(value = "onboardingId") String onboarding .map(ignore -> Response.status(HttpStatus.SC_NO_CONTENT).build()); } + @Operation( + summary = "Update recipient code", + description = "Update recipient code receiving onboarding id.", + operationId = "updateOnboardingRecipientIdUsingPUT") + @PUT + @Tag(name = "billing-portal") + @Tag(name = "Onboarding") + @Consumes(MediaType.APPLICATION_JSON) + @Path("/{onboardingId}/recipient-code") + public Uni updateRecipientCodeByOnboardingId( + @PathParam(value = "onboardingId") String onboardingId, + @QueryParam(value = "recipientCode") String recipientCode) { + Onboarding onboarding = new Onboarding(); + Billing billing = new Billing(); + billing.setRecipientCode(recipientCode.trim()); + onboarding.setBilling(billing); + log.trace("update RecipientCode start"); + log.debug("Onboarding id {} and recipientCode {}", onboardingId, recipientCode.replace("\n", "").replace("\r", "")); + return onboardingService + .updateOnboarding(onboardingId, onboarding) + .map(ignore -> Response.status(HttpStatus.SC_NO_CONTENT).build()) + .log("update RecipientCode end"); + } + @Operation( summary = "Check if new manager matches the current manager.", description = "In the addition administrator flow, it checks " + diff --git a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java index 77e88421b..0ef8390c0 100644 --- a/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java +++ b/apps/onboarding-ms/src/main/java/it/pagopa/selfcare/onboarding/entity/Onboarding.java @@ -4,13 +4,11 @@ import io.quarkus.mongodb.panache.reactive.ReactivePanacheMongoEntityBase; import it.pagopa.selfcare.onboarding.common.OnboardingStatus; import it.pagopa.selfcare.onboarding.common.WorkflowType; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.FieldNameConstants; -import org.bson.codecs.pojo.annotations.BsonId; - import java.time.LocalDateTime; import java.util.List; +import lombok.*; +import lombok.experimental.FieldNameConstants; +import org.bson.codecs.pojo.annotations.BsonId; @EqualsAndHashCode(callSuper = true) @Data 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 c362c904a..4da9188a4 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 @@ -1,5 +1,10 @@ package it.pagopa.selfcare.onboarding.controller; +import static io.restassured.RestAssured.given; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + import io.quarkus.test.InjectMock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.common.http.TestHTTPEndpoint; @@ -24,22 +29,16 @@ import it.pagopa.selfcare.onboarding.model.OnboardingGetFilters; import it.pagopa.selfcare.onboarding.model.RecipientCodeStatus; import it.pagopa.selfcare.onboarding.service.OnboardingService; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static io.restassured.RestAssured.given; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; @QuarkusTest @TestHTTPEndpoint(OnboardingController.class) @@ -997,4 +996,35 @@ private Map getStringStringMapOnboardingStatusUpdate() { return queryParameterMap; } + @Test + @TestSecurity(user = "userJwt") + void updateRecipientCodeByOnboardingIdTest() { + // given + String fakeOnboardingId = "ASDF22234545"; + String fakeRecipientCode = "TEST_CODE2234"; + + Onboarding onboarding = new Onboarding(); + Billing billing = new Billing(); + billing.setRecipientCode(fakeRecipientCode); + onboarding.setBilling(billing); + + when(onboardingService.updateOnboarding(fakeOnboardingId, onboarding)) + .thenReturn(Uni.createFrom().item(1L)); + + // when + given() + .when() + .queryParam("recipientCode", fakeRecipientCode) + .pathParam("onboardingId", fakeOnboardingId) + .contentType(ContentType.JSON) + .put("/{onboardingId}/recipient-code") + .then() + .statusCode(204); + + // then + ArgumentCaptor captor = ArgumentCaptor.forClass(Onboarding.class); + Mockito.verify(onboardingService, times(1)).updateOnboarding(anyString(), captor.capture()); + assertEquals(captor.getValue().getBilling().getRecipientCode(), fakeRecipientCode); + } + } \ No newline at end of file From 714cac8af4bdea82de15d2d957ccdb96ce4e95b4 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:25:34 +0200 Subject: [PATCH 20/27] [SELC-5763] feat: update aggregates csv creation for IO (#547) --- .../service/ContractServiceDefault.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java index 6b966c7e3..7bcd4c7b6 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/ContractServiceDefault.java @@ -73,6 +73,13 @@ public class ContractServiceDefault implements ContractService { "IBAN", "Servizio", "Modalità Sincrona/Asincrona" }; + private static final String LEGAL_SENTENCE_IO = "*** Il presente file non può essere modificato se non unitamente al " + + "documento \"Allegato 3\" in cui è incoporato. Ogni modifica, alterazione e variazione dei dati e delle " + + "informazioni del presente file non accompagnata dall'invio e dalla firma digitale dell'intero documento " + + "\"Allegato 3\" è da considerarsi priva di ogni efficacia ai sensi di legge e ai fini del presente Accordo. " + + "In caso di discrepanza tra i dati contenuti nel presente file e i dati contenuti nell'Allegato 3, " + + "sarà data prevalenza a questi ultimi."; + private static final Function> IO_MAPPER = institution -> Arrays.asList( institution.getDescription(), institution.getDigitalAddress(), @@ -334,11 +341,11 @@ private File generateAggregatesCsv(String productId, List throw new IllegalArgumentException(String.format("Product %s is not available for aggregators", productId)); } - return createAggregatesCsv(institutions, filePath, headers, mapper); + return createAggregatesCsv(institutions, filePath, headers, mapper, productId); } - private File createAggregatesCsv(List institutions, Path filePath, String[] headers, Function> mapper) { + private File createAggregatesCsv(List institutions, Path filePath, String[] headers, Function> mapper, String productId) { File csvFile = filePath.toFile(); // Using the builder pattern to create the CSV format with headers @@ -355,6 +362,11 @@ private File createAggregatesCsv(List institutions, Path f csvPrinter.printRecord(mapper.apply(institution)); } + // If productType is PROD_IO, add the final legal sentence at the last row + if (PROD_IO.getValue().equals(productId)) { + csvPrinter.printRecord(LEGAL_SENTENCE_IO); + } + } catch (IOException e) { throw new GenericOnboardingException(String.format(CREATE_AGGREGATES_CSV_ERROR.getMessage(), e.getMessage())); } From 3861fdd2728c9f610300661431786f92752082cb Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 12:32:45 +0200 Subject: [PATCH 21/27] chore: Working on send user notification --- .../NotificationEventServiceDefault.java | 18 ++++++-- .../utils/NotificationUserBuilderFactory.java | 45 +++++++++++++++++++ .../utils/NotificationUserFDBuilder.java | 25 +++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index e6727ae16..b41fa8971 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -79,7 +79,7 @@ public void send(ExecutionContext context, Onboarding onboarding, QueueEvent que @Override public void send(ExecutionContext context, Onboarding onboarding, QueueEvent queueEvent, String notificationEventTraceId) { context.getLogger().info(() -> String.format("Starting send method for onboarding with ID %s", onboarding.getId())); - if(isNotInstitutionOnboarding(onboarding)) { + if (isNotInstitutionOnboarding(onboarding)) { context.getLogger().info(() -> String.format("Onboarding with ID %s doesn't refer to an institution onboarding, skipping send notification", onboarding.getId())); return; } @@ -91,7 +91,7 @@ public void send(ExecutionContext context, Onboarding onboarding, QueueEvent que return; } - if(Objects.isNull(queueEvent)) { + if (Objects.isNull(queueEvent)) { queueEvent = queueEventExaminer.determineEventType(onboarding); } @@ -103,6 +103,7 @@ public void send(ExecutionContext context, Onboarding onboarding, QueueEvent que for (String consumer : product.getConsumers()) { NotificationConfig.Consumer consumerConfig = notificationConfig.consumers().get(consumer.toLowerCase()); prepareAndSendNotification(context, product, consumerConfig, notificationsResources, notificationEventTraceId); + prepareAndSendUserNotification(context, product, consumerConfig, notificationsResources, notificationEventTraceId); } } @@ -117,6 +118,17 @@ private void prepareAndSendNotification(ExecutionContext context, Product produc } } + private void prepareAndSendUserNotification(ExecutionContext context, Product product, NotificationConfig.Consumer consumer, NotificationsResources notificationsResources, String notificationEventTraceId) { + NotificationBuilder notificationBuilder = notificationBuilderFactory.create(consumer); + if (notificationBuilder.shouldSendNotification(notificationsResources.getOnboarding(), notificationsResources.getInstitution())) { + NotificationToSend notificationToSend = notificationBuilder.buildNotificationToSend(notificationsResources.getOnboarding(), notificationsResources.getToken(), notificationsResources.getInstitution(), notificationsResources.getQueueEvent()); + sendNotification(context, consumer.topic(), notificationToSend, notificationEventTraceId); + sendTestEnvProductsNotification(context, product, consumer.topic(), notificationToSend, notificationEventTraceId); + } else { + context.getLogger().info(() -> String.format("It was not necessary to send a notification on the topic %s because the onboarding with ID %s did not pass filter verification", notificationsResources.getOnboarding().getId(), consumer.topic())); + } + } + private void sendNotification(ExecutionContext context, String topic, NotificationToSend notificationToSend, String notificationEventTraceId) { String message = null; try { @@ -129,7 +141,7 @@ private void sendNotification(ExecutionContext context, String topic, Notificati } eventHubRestClient.sendMessage(topic, message); - telemetryClient.trackEvent(EVENT_ONBOARDING_FN_NAME, notificationEventMap(notificationToSend, topic, notificationEventTraceId), Map.of(EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS, 1D)); + telemetryClient.trackEvent(EVENT_ONBOARDING_FN_NAME, notificationEventMap(notificationToSend, topic, notificationEventTraceId), Map.of(EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS, 1D)); } private void sendTestEnvProductsNotification(ExecutionContext context, Product product, String topic, NotificationToSend notificationToSend, String notificationEventTraceId) { diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java new file mode 100644 index 000000000..80f5bbf41 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java @@ -0,0 +1,45 @@ +package it.pagopa.selfcare.onboarding.utils; + +import it.pagopa.selfcare.onboarding.config.NotificationConfig; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.rest.client.inject.RestClient; +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 static it.pagopa.selfcare.onboarding.entity.Topic.*; + +@ApplicationScoped +public class NotificationUserBuilderFactory { + @Inject + @RestClient + InstitutionApi proxyRegistryInstitutionApi; + @Inject + @RestClient + GeographicTaxonomiesApi geographicTaxonomiesApi; + @Inject + @RestClient + UoApi proxyRegistryUoApi; + @Inject + @RestClient + AooApi proxyRegistryAooApi; + @Inject + @RestClient + org.openapi.quarkus.core_json.api.InstitutionApi coreInstitutionApi; + private final String alternativeEmail; + + public NotificationUserBuilderFactory(@ConfigProperty(name = "onboarding-functions.sender-mail") String alternativeEmail) { + this.alternativeEmail = alternativeEmail; + } + + public NotificationBuilder create(NotificationConfig.Consumer consumer) { + if (SC_CONTRACTS_FD.getValue().equalsIgnoreCase(consumer.topic())) { + return new FdNotificationBuilder(this.alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi); + } + return null; + } + +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java new file mode 100644 index 000000000..1f95657a1 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java @@ -0,0 +1,25 @@ +package it.pagopa.selfcare.onboarding.utils; + +import it.pagopa.selfcare.onboarding.dto.BillingToSend; +import it.pagopa.selfcare.onboarding.dto.InstitutionToNotify; +import it.pagopa.selfcare.onboarding.dto.NotificationToSend; +import it.pagopa.selfcare.onboarding.dto.QueueEvent; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import org.openapi.quarkus.core_json.model.InstitutionResponse; + +public interface NotificationUserFDBuilder { + NotificationToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, QueueEvent queueEvent); + +// default boolean shouldSendNotification(Onboarding onboarding, InstitutionResponse institution) { +// return true; +// } +// +// InstitutionToNotify retrieveInstitution(InstitutionResponse institution); +// +// void setTokenData(NotificationToSend notificationToSend, Token token); +// +// void retrieveAndSetGeographicData(InstitutionToNotify institution); +// +// BillingToSend retrieveBilling(Onboarding onboarding); +} From be860162020ae5453513a15be3eaa5b5df279a0b Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 17:01:02 +0200 Subject: [PATCH 22/27] chore: Working on send user notification --- .../dto/NotificationUserToSend.java | 195 ++++++++++++++++++ .../onboarding/dto/NotificationUserType.java | 25 +++ .../onboarding/dto/QueueUserEvent.java | 9 + .../selfcare/onboarding/dto/UserToNotify.java | 45 ++++ .../NotificationEventServiceDefault.java | 84 +++++++- .../onboarding/utils/CustomMetricsConst.java | 1 + .../utils/FdNotificationBuilder.java | 46 ++++- .../utils/NotificationUserBuilder.java | 19 ++ .../utils/NotificationUserBuilderFactory.java | 23 ++- .../utils/NotificationUserFDBuilder.java | 25 --- .../utils/SapNotificationBuilder.java | 16 +- .../utils/StandardNotificationBuilder.java | 12 +- libs/onboarding-sdk-product/pom.xml | 2 + 13 files changed, 455 insertions(+), 47 deletions(-) create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserType.java create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/QueueUserEvent.java create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/UserToNotify.java create mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilder.java delete mode 100644 apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java new file mode 100644 index 000000000..ce6a05152 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java @@ -0,0 +1,195 @@ +package it.pagopa.selfcare.onboarding.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import it.pagopa.selfcare.onboarding.utils.CustomOffsetDateTimeSerializer; + +import java.nio.file.Paths; +import java.time.OffsetDateTime; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class NotificationUserToSend { + + private String id; + private String institutionId; + private String product; + private String state; + private String filePath; + private String fileName; + private String contentType; + private String onboardingTokenId; + private String pricingPlan; + private BillingToSend billing; + @JsonSerialize(using = CustomOffsetDateTimeSerializer.class) + private OffsetDateTime createdAt; + @JsonSerialize(using = CustomOffsetDateTimeSerializer.class) + private OffsetDateTime closedAt; + @JsonSerialize(using = CustomOffsetDateTimeSerializer.class) + private OffsetDateTime updatedAt; + private QueueUserEvent notificationType; + private NotificationUserType type; + private UserToNotify user; + + + public String getInstitutionId() { + return institutionId; + } + + public void setInstitutionId(String institutionId) { + this.institutionId = institutionId; + } + + + public NotificationUserType getType() { + return type; + } + + public void setType(NotificationUserType type) { + this.type = type; + } + + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getContentType() { + return this.contentType; + } + + public void setContentType(String contractSigned) { + String contractFileName = Objects.isNull(contractSigned) ? "" : Paths.get(contractSigned).getFileName().toString(); + if (contractFileName.isEmpty()) { + this.contentType = ""; + } else if (contractFileName.endsWith(".p7m")) { + this.contentType = "application/pkcs7-mime"; + } else if (contractFileName.endsWith(".pdf")) { + this.contentType = "application/pdf"; + } else { + this.contentType = "application/octet-stream"; + } + } + + public String getOnboardingTokenId() { + return onboardingTokenId; + } + + public void setOnboardingTokenId(String onboardingTokenId) { + this.onboardingTokenId = onboardingTokenId; + } + + public OffsetDateTime getClosedAt() { + return closedAt; + } + + public void setClosedAt(OffsetDateTime closedAt) { + this.closedAt = closedAt; + } + + public QueueUserEvent getNotificationType() { + return notificationType; + } + + public void setNotificationType(QueueUserEvent notificationType) { + this.notificationType = notificationType; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getProduct() { + return product; + } + + public void setProduct(String product) { + this.product = product; + } + + public String getPricingPlan() { + return pricingPlan; + } + + public void setPricingPlan(String pricingPlan) { + this.pricingPlan = pricingPlan; + } + + public BillingToSend getBilling() { + return billing; + } + + public void setBilling(BillingToSend billing) { + this.billing = billing; + } + + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(OffsetDateTime createdAt) { + this.createdAt = createdAt; + } + + public OffsetDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(OffsetDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public UserToNotify getUser() { + return user; + } + + public void setUser(UserToNotify user) { + this.user = user; + } + + @Override + public String toString() { + return "NotificationToSend{" + + "id='" + id + '\'' + + ", istitutionID='" + institutionId + '\'' + + ", product='" + product + '\'' + + ", state='" + state + '\'' + + ", filePath='" + filePath + '\'' + + ", fileName='" + fileName + '\'' + + ", contentType='" + contentType + '\'' + + ", onboardingTokenId='" + onboardingTokenId + '\'' + + ", pricingPlan='" + pricingPlan + '\'' + + ", billing=" + billing + + ", createdAt=" + createdAt + + ", closedAt=" + closedAt + + ", updatedAt=" + updatedAt + + ", notificationType=" + notificationType + + ", userId=" + user.getUserId() + + '}'; + } + +} \ No newline at end of file diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserType.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserType.java new file mode 100644 index 000000000..6d7c90212 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserType.java @@ -0,0 +1,25 @@ +package it.pagopa.selfcare.onboarding.dto; + +public enum NotificationUserType { + ADD_INSTITUTE(QueueUserEvent.ADD_INSTITUTE), + UPDATE_INSTITUTION(QueueUserEvent.UPDATE_INSTITUTION), + ACTIVE_USER(QueueUserEvent.ACTIVE_USER), + SUSPEND_USER(QueueUserEvent.SUSPEND_USER), + DELETE_USER(QueueUserEvent.DELETE_USER); + + + private final QueueUserEvent queueUserEvent; + + NotificationUserType(QueueUserEvent queueUserEvent) { + this.queueUserEvent = queueUserEvent; + } + + public static NotificationUserType getNotificationTypeFromQueueEvent(QueueUserEvent queueEvent) { + for (NotificationUserType notificationType : NotificationUserType.values()) { + if (notificationType.queueUserEvent == queueEvent) { + return notificationType; + } + } + return null; // Return null if no matching NotificationType is found + } +} \ No newline at end of file diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/QueueUserEvent.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/QueueUserEvent.java new file mode 100644 index 000000000..a9cea7683 --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/QueueUserEvent.java @@ -0,0 +1,9 @@ +package it.pagopa.selfcare.onboarding.dto; + +public enum QueueUserEvent { + ADD_INSTITUTE, + UPDATE_INSTITUTION, + ACTIVE_USER, + SUSPEND_USER, + DELETE_USER +} \ No newline at end of file diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/UserToNotify.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/UserToNotify.java new file mode 100644 index 000000000..96f9354ea --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/UserToNotify.java @@ -0,0 +1,45 @@ +package it.pagopa.selfcare.onboarding.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import it.pagopa.selfcare.onboarding.common.PartyRole; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserToNotify { + + private String userId; + private String role; + private String productRole; + private String relationshipStatus; + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getProductRole() { + return productRole; + } + + public void setProductRole(String productRole) { + this.productRole = productRole; + } + + public String getRelationshipStatus() { + return relationshipStatus; + } + + public void setRelationshipStatus(String relationshipStatus) { + this.relationshipStatus = relationshipStatus; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index b41fa8971..491fee8bf 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -8,17 +8,18 @@ import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.azure.functions.ExecutionContext; import it.pagopa.selfcare.onboarding.client.eventhub.EventHubRestClient; +import it.pagopa.selfcare.onboarding.common.OnboardingStatus; +import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.config.NotificationConfig; import it.pagopa.selfcare.onboarding.dto.NotificationToSend; +import it.pagopa.selfcare.onboarding.dto.NotificationUserToSend; import it.pagopa.selfcare.onboarding.dto.NotificationsResources; import it.pagopa.selfcare.onboarding.dto.QueueEvent; import it.pagopa.selfcare.onboarding.entity.Onboarding; import it.pagopa.selfcare.onboarding.entity.Token; import it.pagopa.selfcare.onboarding.exception.NotificationException; import it.pagopa.selfcare.onboarding.repository.TokenRepository; -import it.pagopa.selfcare.onboarding.utils.NotificationBuilder; -import it.pagopa.selfcare.onboarding.utils.NotificationBuilderFactory; -import it.pagopa.selfcare.onboarding.utils.QueueEventExaminer; +import it.pagopa.selfcare.onboarding.utils.*; import it.pagopa.selfcare.product.entity.Product; import it.pagopa.selfcare.product.service.ProductService; import jakarta.enterprise.context.ApplicationScoped; @@ -28,6 +29,9 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; import org.openapi.quarkus.core_json.api.InstitutionApi; import org.openapi.quarkus.core_json.model.InstitutionResponse; +import org.openapi.quarkus.user_json.model.UserDataResponse; +import org.openapi.quarkus.user_json.model.UserInstitutionResponse; +import org.openapi.quarkus.user_registry_json.api.UserApi; import java.util.*; @@ -46,9 +50,14 @@ public class NotificationEventServiceDefault implements NotificationEventService @Inject InstitutionApi institutionApi; + @RestClient + @Inject + org.openapi.quarkus.user_json.api.UserApi userApi; + private final ProductService productService; private final NotificationConfig notificationConfig; private final NotificationBuilderFactory notificationBuilderFactory; + private final NotificationUserBuilderFactory notificationUserBuilderFactory; private final TokenRepository tokenRepository; private final ObjectMapper mapper; private final QueueEventExaminer queueEventExaminer; @@ -56,12 +65,14 @@ public class NotificationEventServiceDefault implements NotificationEventService public NotificationEventServiceDefault(ProductService productService, NotificationConfig notificationConfig, NotificationBuilderFactory notificationBuilderFactory, + NotificationUserBuilderFactory notificationUserBuilderFactory, TokenRepository tokenRepository, QueueEventExaminer queueEventExaminer, @Context @ConfigProperty(name = "onboarding-functions.appinsights.connection-string") String appInsightsConnectionString) { this.productService = productService; this.notificationConfig = notificationConfig; this.notificationBuilderFactory = notificationBuilderFactory; + this.notificationUserBuilderFactory = notificationUserBuilderFactory; this.tokenRepository = tokenRepository; this.queueEventExaminer = queueEventExaminer; TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.createDefault(); @@ -119,11 +130,29 @@ private void prepareAndSendNotification(ExecutionContext context, Product produc } private void prepareAndSendUserNotification(ExecutionContext context, Product product, NotificationConfig.Consumer consumer, NotificationsResources notificationsResources, String notificationEventTraceId) { - NotificationBuilder notificationBuilder = notificationBuilderFactory.create(consumer); - if (notificationBuilder.shouldSendNotification(notificationsResources.getOnboarding(), notificationsResources.getInstitution())) { - NotificationToSend notificationToSend = notificationBuilder.buildNotificationToSend(notificationsResources.getOnboarding(), notificationsResources.getToken(), notificationsResources.getInstitution(), notificationsResources.getQueueEvent()); - sendNotification(context, consumer.topic(), notificationToSend, notificationEventTraceId); - sendTestEnvProductsNotification(context, product, consumer.topic(), notificationToSend, notificationEventTraceId); + NotificationUserBuilder notificationUserBuilder = notificationUserBuilderFactory.create(consumer); + if (notificationUserBuilder.shouldSendUserNotification(notificationsResources.getOnboarding(), notificationsResources.getInstitution())) { + List users = userApi.usersUserIdInstitutionInstitutionIdGet(notificationsResources.getOnboarding().getInstitution().getId(), null, null, null, null, null, null); + users.forEach(userDataResponse -> { + userDataResponse.getProducts().stream().filter(onboardedProductResponse -> { + if (onboardedProductResponse.getProductId().equals(product.getId())) { + NotificationUserToSend notificationUserToSend = notificationUserBuilder.buildUserNotificationToSend( + notificationsResources.getOnboarding(), + notificationsResources.getToken(), + notificationsResources.getInstitution(), + onboardedProductResponse.getCreatedAt(), + onboardedProductResponse.getUpdatedAt(), + onboardedProductResponse.getStatus().toString(), userDataResponse.getUserId(), onboardedProductResponse.getRole(), + onboardedProductResponse.getProductRole()); + sendUserNotification(context, consumer.topic(), notificationUserToSend, notificationEventTraceId); + } + return false; + }); + + + }); + + } else { context.getLogger().info(() -> String.format("It was not necessary to send a notification on the topic %s because the onboarding with ID %s did not pass filter verification", notificationsResources.getOnboarding().getId(), consumer.topic())); } @@ -144,6 +173,21 @@ private void sendNotification(ExecutionContext context, String topic, Notificati telemetryClient.trackEvent(EVENT_ONBOARDING_FN_NAME, notificationEventMap(notificationToSend, topic, notificationEventTraceId), Map.of(EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS, 1D)); } + private void sendUserNotification(ExecutionContext context, String topic, NotificationUserToSend notificationUserToSend, String notificationEventTraceId) { + String message = null; + try { + message = mapper.writeValueAsString(notificationUserToSend); + } catch (JsonProcessingException e) { + throw new NotificationException("Notification User cannot be serialized"); + } finally { + String finalMessage = message; + context.getLogger().info(() -> String.format("Sending notification user on topic: %s with message: %s", topic, finalMessage)); + } + + eventHubRestClient.sendMessage(topic, message); + telemetryClient.trackEvent(EVENT_ONBOARDING_FN_NAME, notificationUserEventMap(notificationUserToSend, topic, notificationEventTraceId), Map.of(EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS, 1D)); + } + private void sendTestEnvProductsNotification(ExecutionContext context, Product product, String topic, NotificationToSend notificationToSend, String notificationEventTraceId) { context.getLogger().info(() -> String.format("Starting sendTestEnvProductsNotification with testEnv %s", product.getTestEnvProductIds())); if (product.getTestEnvProductIds() != null) { @@ -219,4 +263,28 @@ public static Map notificationEventMap(NotificationToSend notifi return propertiesMap; } + + public static Map notificationUserEventMap(NotificationUserToSend notificationUserToSend, String topic, String notificationEventTraceId) { + Map propertiesMap = new HashMap<>(); + Optional.ofNullable(topic).ifPresent(value -> propertiesMap.put("topic", value)); + Optional.ofNullable(notificationEventTraceId).ifPresent(value -> propertiesMap.put("notificationEventTraceId", value)); + Optional.ofNullable(notificationUserToSend.getId()).ifPresent(value -> propertiesMap.put("id", value)); + Optional.ofNullable(notificationUserToSend.getInstitutionId()).ifPresent(value -> propertiesMap.put("institutionId", value)); + Optional.ofNullable(notificationUserToSend.getProduct()).ifPresent(value -> propertiesMap.put("product", value)); + Optional.ofNullable(notificationUserToSend.getState()).ifPresent(value -> propertiesMap.put("state", value)); + Optional.ofNullable(notificationUserToSend.getFilePath()).ifPresent(value -> propertiesMap.put("filePath", value)); + Optional.ofNullable(notificationUserToSend.getFileName()).ifPresent(value -> propertiesMap.put("fileName", value)); + Optional.ofNullable(notificationUserToSend.getContentType()).ifPresent(value -> propertiesMap.put("contentType", value)); + Optional.ofNullable(notificationUserToSend.getOnboardingTokenId()).ifPresent(value -> propertiesMap.put("onboardingTokenId", value)); + Optional.ofNullable(notificationUserToSend.getPricingPlan()).ifPresent(value -> propertiesMap.put("pricingPlan", value)); + + if (Optional.ofNullable(notificationUserToSend.getUser()).isPresent()) { + + Optional.ofNullable(notificationUserToSend.getUser().getUserId()).ifPresent(value -> propertiesMap.put("userId", value)); + Optional.ofNullable(notificationUserToSend.getUser().getRole()).ifPresent(value -> propertiesMap.put("role", value)); + Optional.ofNullable(notificationUserToSend.getUser().getRelationshipStatus()).ifPresent(value -> propertiesMap.put("relationshipStatus()", value)); + Optional.ofNullable(notificationUserToSend.getUser().getProductRole()).ifPresent(value -> propertiesMap.put("productRole()", value)); + } + return propertiesMap; + } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java index 270082f3a..3b7448263 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/CustomMetricsConst.java @@ -7,5 +7,6 @@ private CustomMetricsConst() { public static final String EVENT_ONBOARDING_FN_NAME = "ONBOARDING-FN"; public static final String EVENT_ONBOARDING_INSTTITUTION_FN_FAILURE = "EventsOnboardingInstitution_failures"; public static final String EVENT_ONBOARDING_INSTTITUTION_FN_SUCCESS = "EventsOnboardingInstitution_success"; + public static final String EVENT_ONBOARDING_USER_FN_SUCCESS = "EventsOnboardingUser_success"; } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilder.java index 0714a7ae2..8c232a1ea 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilder.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilder.java @@ -1,5 +1,6 @@ package it.pagopa.selfcare.onboarding.utils; +import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.config.NotificationConfig; import it.pagopa.selfcare.onboarding.dto.*; import it.pagopa.selfcare.onboarding.entity.Onboarding; @@ -8,10 +9,11 @@ import org.openapi.quarkus.party_registry_proxy_json.api.GeographicTaxonomiesApi; import org.openapi.quarkus.party_registry_proxy_json.api.InstitutionApi; +import java.time.OffsetDateTime; import java.util.Objects; import java.util.UUID; -public class FdNotificationBuilder extends BaseNotificationBuilder { +public class FdNotificationBuilder extends BaseNotificationBuilder implements NotificationUserBuilder { public FdNotificationBuilder( String alternativeEmail, NotificationConfig.Consumer consumer, @@ -44,7 +46,7 @@ public InstitutionToNotify retrieveInstitution(InstitutionResponse institution) @Override public BillingToSend retrieveBilling(Onboarding onboarding) { - if(Objects.isNull(onboarding.getBilling())) { + if (Objects.isNull(onboarding.getBilling())) { return null; } @@ -52,4 +54,44 @@ public BillingToSend retrieveBilling(Onboarding onboarding) { billing.setPublicService(onboarding.getBilling().isPublicServices()); return billing; } + + @Override + public NotificationUserToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, + OffsetDateTime createdAt, OffsetDateTime updatedAt, String status, + String userId, String partyRole, String productRole) { + NotificationToSend notification = buildNotificationToSend(onboarding, token, institution, QueueEvent.UPDATE); + NotificationUserToSend notificationUserToSend = new NotificationUserToSend(); + notificationUserToSend.setId(notification.getId()); + notificationUserToSend.setInstitutionId(notification.getInstitutionId()); + notificationUserToSend.setProduct(notification.getProduct()); + notificationUserToSend.setState(notification.getState()); + notificationUserToSend.setFilePath(notification.getFilePath()); + notificationUserToSend.setFileName(notification.getFileName()); + notificationUserToSend.setContentType(notification.getContentType()); + notificationUserToSend.setOnboardingTokenId(notification.getOnboardingTokenId()); + notificationUserToSend.setPricingPlan(notification.getPricingPlan()); + notificationUserToSend.setBilling(notification.getBilling()); + notificationUserToSend.setCreatedAt(createdAt); + notificationUserToSend.setUpdatedAt(updatedAt); + QueueUserEvent queueUserEvent = switch (status) { + case "DELETE" -> QueueUserEvent.DELETE_USER; + case "SUSPEND" -> QueueUserEvent.SUSPEND_USER; + default -> QueueUserEvent.ACTIVE_USER; + }; + notificationUserToSend.setNotificationType(queueUserEvent); + notificationUserToSend.setType(NotificationUserType.getNotificationTypeFromQueueEvent(queueUserEvent)); + UserToNotify user = new UserToNotify(); + user.setUserId(userId); + user.setRole(partyRole); + user.setProductRole(productRole); + user.setRelationshipStatus(status); + notificationUserToSend.setUser(user); + + return notificationUserToSend; + } + + @Override + public boolean shouldSendUserNotification(Onboarding onboarding, InstitutionResponse institution) { + return true; + } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilder.java new file mode 100644 index 000000000..a9daaee7c --- /dev/null +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilder.java @@ -0,0 +1,19 @@ +package it.pagopa.selfcare.onboarding.utils; + +import it.pagopa.selfcare.onboarding.common.PartyRole; +import it.pagopa.selfcare.onboarding.dto.NotificationUserToSend; +import it.pagopa.selfcare.onboarding.entity.Onboarding; +import it.pagopa.selfcare.onboarding.entity.Token; +import org.openapi.quarkus.core_json.model.InstitutionResponse; + +import java.time.OffsetDateTime; + +public interface NotificationUserBuilder { + NotificationUserToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, + OffsetDateTime createdAt, OffsetDateTime updatedAt, String status, + String userId, String partyRole, String productRole); + + default boolean shouldSendUserNotification(Onboarding onboarding, InstitutionResponse institution) { + return false; + } +} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java index 80f5bbf41..b8a77a88e 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserBuilderFactory.java @@ -22,24 +22,33 @@ public class NotificationUserBuilderFactory { GeographicTaxonomiesApi geographicTaxonomiesApi; @Inject @RestClient - UoApi proxyRegistryUoApi; + org.openapi.quarkus.core_json.api.InstitutionApi coreInstitutionApi; + private final String alternativeEmail; @Inject @RestClient - AooApi proxyRegistryAooApi; + UoApi proxyRegistryUoApi; @Inject @RestClient - org.openapi.quarkus.core_json.api.InstitutionApi coreInstitutionApi; - private final String alternativeEmail; + AooApi proxyRegistryAooApi; public NotificationUserBuilderFactory(@ConfigProperty(name = "onboarding-functions.sender-mail") String alternativeEmail) { this.alternativeEmail = alternativeEmail; } - public NotificationBuilder create(NotificationConfig.Consumer consumer) { + public NotificationUserBuilder create(NotificationConfig.Consumer consumer) { + + NotificationUserBuilder notificationUserBuilder; if (SC_CONTRACTS_FD.getValue().equalsIgnoreCase(consumer.topic())) { - return new FdNotificationBuilder(this.alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi); + notificationUserBuilder = new FdNotificationBuilder(this.alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi); + } else if (SC_CONTRACTS_SAP.getValue().equalsIgnoreCase(consumer.topic())) { + notificationUserBuilder = new SapNotificationBuilder(this.alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi, proxyRegistryUoApi, proxyRegistryAooApi); + } else if (SC_CONTRACTS.getValue().equalsIgnoreCase(consumer.topic())) { + notificationUserBuilder = new StandardNotificationBuilder(this.alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi); + } else { + throw new IllegalArgumentException("Topic not supported"); } - return null; + + return notificationUserBuilder; } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java deleted file mode 100644 index 1f95657a1..000000000 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/NotificationUserFDBuilder.java +++ /dev/null @@ -1,25 +0,0 @@ -package it.pagopa.selfcare.onboarding.utils; - -import it.pagopa.selfcare.onboarding.dto.BillingToSend; -import it.pagopa.selfcare.onboarding.dto.InstitutionToNotify; -import it.pagopa.selfcare.onboarding.dto.NotificationToSend; -import it.pagopa.selfcare.onboarding.dto.QueueEvent; -import it.pagopa.selfcare.onboarding.entity.Onboarding; -import it.pagopa.selfcare.onboarding.entity.Token; -import org.openapi.quarkus.core_json.model.InstitutionResponse; - -public interface NotificationUserFDBuilder { - NotificationToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, QueueEvent queueEvent); - -// default boolean shouldSendNotification(Onboarding onboarding, InstitutionResponse institution) { -// return true; -// } -// -// InstitutionToNotify retrieveInstitution(InstitutionResponse institution); -// -// void setTokenData(NotificationToSend notificationToSend, Token token); -// -// void retrieveAndSetGeographicData(InstitutionToNotify institution); -// -// BillingToSend retrieveBilling(Onboarding onboarding); -} diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/SapNotificationBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/SapNotificationBuilder.java index e73d36383..2fe7f69b6 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/SapNotificationBuilder.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/SapNotificationBuilder.java @@ -1,5 +1,6 @@ package it.pagopa.selfcare.onboarding.utils; +import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.common.PricingPlan; import it.pagopa.selfcare.onboarding.common.ProductId; import it.pagopa.selfcare.onboarding.config.NotificationConfig; @@ -16,11 +17,12 @@ import org.openapi.quarkus.party_registry_proxy_json.model.InstitutionResource; import org.openapi.quarkus.party_registry_proxy_json.model.UOResource; +import java.time.OffsetDateTime; import java.util.Objects; import java.util.Set; import java.util.UUID; -public class SapNotificationBuilder extends BaseNotificationBuilder { +public class SapNotificationBuilder extends BaseNotificationBuilder implements NotificationUserBuilder { private final UoApi proxyRegistryUoApi; private final AooApi proxyRegistryAooApi; @@ -37,6 +39,7 @@ public SapNotificationBuilder( this.proxyRegistryUoApi = proxyRegistryUoApi; this.proxyRegistryAooApi = proxyRegistryAooApi; } + @Override public NotificationToSend buildNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, QueueEvent queueEvent) { NotificationToSend notificationToSend = super.buildNotificationToSend(onboarding, token, institution, queueEvent); @@ -60,9 +63,10 @@ private static void setNotificationToSendInstitutionDescription(NotificationToSe + " - " + notificationToSend.getInstitution().getDescription()); } } + @Override public BillingToSend retrieveBilling(Onboarding onboarding) { - if(Objects.isNull(onboarding.getBilling())) { + if (Objects.isNull(onboarding.getBilling())) { return null; } @@ -70,6 +74,7 @@ public BillingToSend retrieveBilling(Onboarding onboarding) { billing.setPublicService(onboarding.getBilling().isPublicServices()); return billing; } + @Override public InstitutionToNotify retrieveInstitution(InstitutionResponse institution) { InstitutionToNotify institutionToNotify = super.retrieveInstitution(institution); @@ -78,6 +83,7 @@ public InstitutionToNotify retrieveInstitution(InstitutionResponse institution) institutionToNotify.setCategory(null); return institutionToNotify; } + @Override public void retrieveAndSetGeographicData(InstitutionToNotify institutionToNotify) { GeographicTaxonomyResource geographicTaxonomies; @@ -111,6 +117,7 @@ public void retrieveAndSetGeographicData(InstitutionToNotify institutionToNotify institutionToNotify.setCity(geographicTaxonomies.getDesc().replace(DESCRIPTION_TO_REPLACE_REGEX, "")); } } + @Override public boolean shouldSendNotification(Onboarding onboarding, InstitutionResponse institution) { return isProductAllowed(onboarding) && isAllowedInstitutionType(institution) && isAllowedOrigin(institution.getOrigin()); @@ -133,4 +140,9 @@ private boolean isAllowedOrigin(String origin) { private boolean isNullOrEmpty(Set set) { return Objects.isNull(set) || set.isEmpty(); } + + @Override + public NotificationUserToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, OffsetDateTime createdAt, OffsetDateTime updatedAt, String status, String userId, String partyRole, String productRole) { + return null; + } } diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/StandardNotificationBuilder.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/StandardNotificationBuilder.java index 40d20c37a..2130c92db 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/StandardNotificationBuilder.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/utils/StandardNotificationBuilder.java @@ -1,5 +1,6 @@ package it.pagopa.selfcare.onboarding.utils; +import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.config.NotificationConfig; import it.pagopa.selfcare.onboarding.dto.*; import it.pagopa.selfcare.onboarding.entity.Onboarding; @@ -8,9 +9,10 @@ import org.openapi.quarkus.party_registry_proxy_json.api.GeographicTaxonomiesApi; import org.openapi.quarkus.party_registry_proxy_json.api.InstitutionApi; +import java.time.OffsetDateTime; import java.util.Objects; -public class StandardNotificationBuilder extends BaseNotificationBuilder { +public class StandardNotificationBuilder extends BaseNotificationBuilder implements NotificationUserBuilder { public StandardNotificationBuilder( String alternativeEmail, NotificationConfig.Consumer consumer, @@ -20,6 +22,7 @@ public StandardNotificationBuilder( ) { super(alternativeEmail, consumer, proxyRegistryInstitutionApi, geographicTaxonomiesApi, coreInstitutionApi); } + @Override public NotificationToSend buildNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, QueueEvent queueEvent) { NotificationToSend notificationToSend = super.buildNotificationToSend(onboarding, token, institution, queueEvent); @@ -31,7 +34,7 @@ public NotificationToSend buildNotificationToSend(Onboarding onboarding, Token t @Override public BillingToSend retrieveBilling(Onboarding onboarding) { - if(Objects.isNull(onboarding.getBilling())) { + if (Objects.isNull(onboarding.getBilling())) { return null; } @@ -61,5 +64,8 @@ private void retrieveAndSetAggregatorInfo(Onboarding onboarding, NotificationToS } } - + @Override + public NotificationUserToSend buildUserNotificationToSend(Onboarding onboarding, Token token, InstitutionResponse institution, OffsetDateTime createdAt, OffsetDateTime updatedAt, String status, String userId, String partyRole, String productRole) { + return null; + } } diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index ce7bf49e2..26ac23f8d 100644 --- a/libs/onboarding-sdk-product/pom.xml +++ b/libs/onboarding-sdk-product/pom.xml @@ -7,6 +7,7 @@ 0.3.3 ../onboarding-sdk-pom + onboarding-sdk-product onboarding-sdk-product 0.3.3 @@ -28,6 +29,7 @@ onboarding-sdk-azure-storage ${project.version} + w it.pagopa.selfcare From 2f33ea5ba532ba3accb1cc343916866bdd051e69 Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 18:03:39 +0200 Subject: [PATCH 23/27] chore: Working on send user notification --- .../NotificationEventServiceDefaultTest.java | 13 +++++++++++-- libs/onboarding-sdk-product/pom.xml | 2 -- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java index 6e70f01ea..17c635eee 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java @@ -24,7 +24,9 @@ import org.junit.jupiter.api.Test; import org.openapi.quarkus.core_json.api.InstitutionApi; import org.openapi.quarkus.core_json.model.InstitutionResponse; +import org.openapi.quarkus.user_json.model.UserDataResponse; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -52,6 +54,10 @@ public class NotificationEventServiceDefaultTest { @InjectMock TokenRepository tokenRepository; + @RestClient + @InjectMock + org.openapi.quarkus.user_json.api.UserApi userApi; + @RestClient @InjectMock InstitutionApi institutionApi; @@ -68,6 +74,9 @@ void sendMessage() { mockNotificationMapper(true); when(tokenRepository.findByOnboardingId(any())).thenReturn(Optional.of(new Token())); when(institutionApi.retrieveInstitutionByIdUsingGET(any())).thenReturn(new InstitutionResponse()); + List users = new ArrayList<>(); + when(userApi.usersUserIdInstitutionInstitutionIdGet(any(), any(), any(), any(), any(), any(), any())) + .thenReturn(users); ExecutionContext context = mock(ExecutionContext.class); doReturn(Logger.getGlobal()).when(context).getLogger(); doNothing().when(eventHubRestClient).sendMessage(anyString(), anyString()); @@ -195,7 +204,7 @@ void sendMessageWontProceedsWhenOnboardingIsNotReferredToInstitution() { @Test void notificationEventMapTest() { - NotificationToSend notificationToSend = new NotificationToSend(); + NotificationToSend notificationToSend = new NotificationToSend(); notificationToSend.setId("id"); notificationToSend.setInternalIstitutionID("internal"); notificationToSend.setProduct("prod"); @@ -236,7 +245,7 @@ void notificationEventMapTest() { @Test void notificationEventMapRootParentTest() { - NotificationToSend notificationToSend = new NotificationToSend(); + NotificationToSend notificationToSend = new NotificationToSend(); notificationToSend.setId("id"); notificationToSend.setInternalIstitutionID("internal"); notificationToSend.setProduct("prod"); diff --git a/libs/onboarding-sdk-product/pom.xml b/libs/onboarding-sdk-product/pom.xml index 26ac23f8d..ce7bf49e2 100644 --- a/libs/onboarding-sdk-product/pom.xml +++ b/libs/onboarding-sdk-product/pom.xml @@ -7,7 +7,6 @@ 0.3.3 ../onboarding-sdk-pom - onboarding-sdk-product onboarding-sdk-product 0.3.3 @@ -29,7 +28,6 @@ onboarding-sdk-azure-storage ${project.version} - w it.pagopa.selfcare From e4e53dabd357cc68c43b23ea3cd7f66b72128ef7 Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 18:45:33 +0200 Subject: [PATCH 24/27] chore: Adding Test --- .../NotificationEventServiceDefault.java | 4 +- .../utils/FdNotificationBuilderTest.java | 88 ++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index 491fee8bf..6edb12bd9 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -142,7 +142,9 @@ private void prepareAndSendUserNotification(ExecutionContext context, Product pr notificationsResources.getInstitution(), onboardedProductResponse.getCreatedAt(), onboardedProductResponse.getUpdatedAt(), - onboardedProductResponse.getStatus().toString(), userDataResponse.getUserId(), onboardedProductResponse.getRole(), + onboardedProductResponse.getStatus().toString(), + userDataResponse.getUserId(), + onboardedProductResponse.getRole(), onboardedProductResponse.getProductRole()); sendUserNotification(context, consumer.topic(), notificationUserToSend, notificationEventTraceId); } diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java index 9e51d7ce7..0c14c0056 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java @@ -4,8 +4,7 @@ import io.quarkus.test.junit.QuarkusTest; import it.pagopa.selfcare.onboarding.common.OnboardingStatus; import it.pagopa.selfcare.onboarding.config.NotificationConfig; -import it.pagopa.selfcare.onboarding.dto.NotificationToSend; -import it.pagopa.selfcare.onboarding.dto.NotificationType; +import it.pagopa.selfcare.onboarding.dto.*; import it.pagopa.selfcare.onboarding.dto.QueueEvent; import it.pagopa.selfcare.onboarding.entity.Billing; import it.pagopa.selfcare.onboarding.entity.Onboarding; @@ -16,8 +15,11 @@ import org.openapi.quarkus.core_json.model.InstitutionResponse; import org.openapi.quarkus.party_registry_proxy_json.api.GeographicTaxonomiesApi; import org.openapi.quarkus.party_registry_proxy_json.api.InstitutionApi; +import org.openapi.quarkus.user_json.model.*; import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; import static it.pagopa.selfcare.onboarding.entity.Topic.SC_CONTRACTS_FD; import static it.pagopa.selfcare.onboarding.utils.NotificationBuilderTestUtil.*; @@ -37,6 +39,9 @@ class FdNotificationBuilderTest { @InjectMock @RestClient org.openapi.quarkus.core_json.api.InstitutionApi coreInstitutionApi; + @RestClient + @InjectMock + org.openapi.quarkus.user_json.api.UserApi userApi; FdNotificationBuilder fdNotificationBuilder; @@ -88,4 +93,83 @@ void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventAdd() { assertEquals(onboarding.getBilling().isPublicServices(), notification.getBilling().isPublicService()); assertNull(notification.getFilePath()); } + + @Test + void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventUserActive() { + + // Create Onboarding + Onboarding onboarding = createOnboarding( + OnboardingStatus.COMPLETED, + OffsetDateTime.parse("2020-11-01T10:00:00Z"), // createdAt + OffsetDateTime.parse("2020-11-02T10:02:00Z"), // activatedAt + OffsetDateTime.parse("2020-11-02T10:05:00Z"), // updatedAt + null // deletedAt + ); + + Billing billing = new Billing(); + billing.setTaxCodeInvoicing("taxCodeInvoicing"); + onboarding.setBilling(billing); + + // Create Institution + InstitutionResponse institution = createInstitution(); + // Create Token + Token token = createToken(); + + InstitutionResponse institutionParentResource = new InstitutionResponse(); + institutionParentResource.setOriginId("parentOriginId"); + when(coreInstitutionApi.retrieveInstitutionByIdUsingGET(any())) + .thenReturn(institutionParentResource); + + OnboardedProductResponse productResponse = new OnboardedProductResponse(); + productResponse.setProductId(productId); + productResponse.setStatus(OnboardedProductState.ACTIVE); + productResponse.setProductRole("security"); + productResponse.setRole("OPERATOR"); + productResponse.setEnv(Env.PROD); + productResponse.setCreatedAt(OffsetDateTime.now()); + productResponse.setUpdatedAt(OffsetDateTime.now()); + + UserResponse userResponse = new UserResponse(); + userResponse.id("userId1"); + + + List users = new ArrayList<>(); + UserDataResponse userDataResponse = new UserDataResponse(); + userDataResponse.setId("userDataId1"); + userDataResponse.setUserId("userId1"); + userDataResponse.setInstitutionId(institution.getId()); + userDataResponse.setInstitutionDescription(institution.getDescription()); + userDataResponse.setUserMailUuid("usermail1"); + userDataResponse.setRole("OPERATOR"); + userDataResponse.setStatus("ACTIVE"); + userDataResponse.setProducts(List.of(productResponse)); + userDataResponse.setUserResponse(userResponse); + + users.add(userDataResponse); + + + when(userApi.usersUserIdInstitutionInstitutionIdGet(any(), any(), any(), any(), any(), any(), any())) + .thenReturn(users); + + NotificationUserToSend notification = fdNotificationBuilder.buildUserNotificationToSend( + onboarding, + token, + institution, + productResponse.getCreatedAt(), + productResponse.getUpdatedAt(), + "ACTIVE", + userDataResponse.getUserId(), + productResponse.getRole(), + productResponse.getProductRole()); + + assertNotNull(notification); + assertNotEquals(onboarding.getId(), notification.getId()); + assertEquals("ACTIVE", notification.getState()); + assertEquals(tokenId, notification.getOnboardingTokenId()); + assertEquals(productResponse.getCreatedAt().toLocalDateTime(), notification.getCreatedAt().toLocalDateTime()); + assertEquals(productResponse.getUpdatedAt().toLocalDateTime(), notification.getUpdatedAt().toLocalDateTime()); + assertEquals(NotificationUserType.ACTIVE_USER, notification.getType()); + assertEquals(productResponse.getProductRole(), notification.getUser().getProductRole()); + assertEquals(productResponse.getRole(), notification.getUser().getRole()); + } } \ No newline at end of file From 584035044c3f52ba2e01cfb3a1c3744a4c1cf747 Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 20:43:09 +0200 Subject: [PATCH 25/27] chore: Adding Test --- .../NotificationEventServiceDefault.java | 4 --- ...cationEventResenderServiceDefaultTest.java | 28 ++++++++++++++++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index 6edb12bd9..cefbaeeef 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -8,8 +8,6 @@ import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.azure.functions.ExecutionContext; import it.pagopa.selfcare.onboarding.client.eventhub.EventHubRestClient; -import it.pagopa.selfcare.onboarding.common.OnboardingStatus; -import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.onboarding.config.NotificationConfig; import it.pagopa.selfcare.onboarding.dto.NotificationToSend; import it.pagopa.selfcare.onboarding.dto.NotificationUserToSend; @@ -30,8 +28,6 @@ import org.openapi.quarkus.core_json.api.InstitutionApi; import org.openapi.quarkus.core_json.model.InstitutionResponse; import org.openapi.quarkus.user_json.model.UserDataResponse; -import org.openapi.quarkus.user_json.model.UserInstitutionResponse; -import org.openapi.quarkus.user_registry_json.api.UserApi; import java.util.*; diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java index bdb5fe1a8..73047ddef 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventResenderServiceDefaultTest.java @@ -186,7 +186,7 @@ void resendNotificationsEndsWithMoreElementsToRetrieve() { private List getMockedList(int i) { List onboardings = new ArrayList<>(); - for(int j = 0; j < i; j++) { + for (int j = 0; j < i; j++) { Onboarding onboarding = new Onboarding(); onboarding.setId("id" + j); onboarding.setStatus(OnboardingStatus.COMPLETED); @@ -196,4 +196,30 @@ private List getMockedList(int i) { return onboardings; } + + @Test + void resendNotifications_withUserNotification() { + /* Test that the resendNotifications method works correctly when there are two onboardings 1 COMPLETED (which should produce one notification) and 1 DELETED (which should produce two notifications) and no range is specified */ + // Arrange + ResendNotificationsFilters filters = ResendNotificationsFilters.builder().onboardingId("test").build(); + ExecutionContext context = getMockedContext(); + + Onboarding onboarding = new Onboarding(); + onboarding.setId("id1"); + onboarding.setStatus(OnboardingStatus.COMPLETED); + onboarding.setProductId("prod-fd"); + onboarding.setActivatedAt(LocalDateTime.of(2023, 2, 1, 0, 0)); + + + when(onboardingService.getOnboardingsToResend(filters, 0, 100)).thenReturn(List.of(onboarding)); + doNothing().when(notificationEventService).send(any(), any(), any(), any()); + + // Act + ResendNotificationsFilters resendNotificationsFilters = notificationEventResenderServiceDefault.resendNotifications(filters, context); + + // Assert + verify(notificationEventService, times(1)).send(any(), any(), any(), any()); + verify(onboardingService).getOnboardingsToResend(filters, 0, 100); + assertNull(resendNotificationsFilters); + } } \ No newline at end of file From 85b15a0c2fe4053def46b82e49799531fd6e7be6 Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 21:15:16 +0200 Subject: [PATCH 26/27] chore: Adding Test --- .../NotificationEventServiceDefault.java | 32 ++++--- .../NotificationEventServiceDefaultTest.java | 90 ++++++++++++++----- .../utils/FdNotificationBuilderTest.java | 75 +++++++++------- 3 files changed, 128 insertions(+), 69 deletions(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java index cefbaeeef..d4d5ca62e 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefault.java @@ -27,6 +27,7 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; import org.openapi.quarkus.core_json.api.InstitutionApi; import org.openapi.quarkus.core_json.model.InstitutionResponse; +import org.openapi.quarkus.user_json.model.OnboardedProductResponse; import org.openapi.quarkus.user_json.model.UserDataResponse; import java.util.*; @@ -132,16 +133,7 @@ private void prepareAndSendUserNotification(ExecutionContext context, Product pr users.forEach(userDataResponse -> { userDataResponse.getProducts().stream().filter(onboardedProductResponse -> { if (onboardedProductResponse.getProductId().equals(product.getId())) { - NotificationUserToSend notificationUserToSend = notificationUserBuilder.buildUserNotificationToSend( - notificationsResources.getOnboarding(), - notificationsResources.getToken(), - notificationsResources.getInstitution(), - onboardedProductResponse.getCreatedAt(), - onboardedProductResponse.getUpdatedAt(), - onboardedProductResponse.getStatus().toString(), - userDataResponse.getUserId(), - onboardedProductResponse.getRole(), - onboardedProductResponse.getProductRole()); + NotificationUserToSend notificationUserToSend = getNotificationUserToSend(notificationsResources, userDataResponse, onboardedProductResponse, notificationUserBuilder); sendUserNotification(context, consumer.topic(), notificationUserToSend, notificationEventTraceId); } return false; @@ -156,6 +148,22 @@ private void prepareAndSendUserNotification(ExecutionContext context, Product pr } } + public static NotificationUserToSend getNotificationUserToSend(NotificationsResources notificationsResources, + UserDataResponse userDataResponse, + OnboardedProductResponse onboardedProductResponse, + NotificationUserBuilder notificationUserBuilder) { + return notificationUserBuilder.buildUserNotificationToSend( + notificationsResources.getOnboarding(), + notificationsResources.getToken(), + notificationsResources.getInstitution(), + onboardedProductResponse.getCreatedAt(), + onboardedProductResponse.getUpdatedAt(), + onboardedProductResponse.getStatus().toString(), + userDataResponse.getUserId(), + onboardedProductResponse.getRole(), + onboardedProductResponse.getProductRole()); + } + private void sendNotification(ExecutionContext context, String topic, NotificationToSend notificationToSend, String notificationEventTraceId) { String message = null; try { @@ -280,8 +288,8 @@ public static Map notificationUserEventMap(NotificationUserToSen Optional.ofNullable(notificationUserToSend.getUser().getUserId()).ifPresent(value -> propertiesMap.put("userId", value)); Optional.ofNullable(notificationUserToSend.getUser().getRole()).ifPresent(value -> propertiesMap.put("role", value)); - Optional.ofNullable(notificationUserToSend.getUser().getRelationshipStatus()).ifPresent(value -> propertiesMap.put("relationshipStatus()", value)); - Optional.ofNullable(notificationUserToSend.getUser().getProductRole()).ifPresent(value -> propertiesMap.put("productRole()", value)); + Optional.ofNullable(notificationUserToSend.getUser().getRelationshipStatus()).ifPresent(value -> propertiesMap.put("relationshipStatus", value)); + Optional.ofNullable(notificationUserToSend.getUser().getProductRole()).ifPresent(value -> propertiesMap.put("productRole", value)); } return propertiesMap; } diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java index 17c635eee..675ef4f53 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/service/NotificationEventServiceDefaultTest.java @@ -204,19 +204,9 @@ void sendMessageWontProceedsWhenOnboardingIsNotReferredToInstitution() { @Test void notificationEventMapTest() { - NotificationToSend notificationToSend = new NotificationToSend(); - notificationToSend.setId("id"); - notificationToSend.setInternalIstitutionID("internal"); - notificationToSend.setProduct("prod"); - notificationToSend.setState("state"); - notificationToSend.setFileName("fileName"); - notificationToSend.setFilePath("filePath"); - notificationToSend.setContentType("contentType"); + NotificationToSend notificationToSend = getNotificationBaseToSend(); - InstitutionToNotify institution = new InstitutionToNotify(); - institution.setDescription("description"); - institution.setInstitutionType(InstitutionType.SA); - institution.setDigitalAddress("mail"); + InstitutionToNotify institution = getInstitutionToNotify(); notificationToSend.setInstitution(institution); BillingToSend billing = new BillingToSend(); @@ -245,19 +235,9 @@ void notificationEventMapTest() { @Test void notificationEventMapRootParentTest() { - NotificationToSend notificationToSend = new NotificationToSend(); - notificationToSend.setId("id"); - notificationToSend.setInternalIstitutionID("internal"); - notificationToSend.setProduct("prod"); - notificationToSend.setState("state"); - notificationToSend.setFileName("fileName"); - notificationToSend.setFilePath("filePath"); - notificationToSend.setContentType("contentType"); + NotificationToSend notificationToSend = getNotificationBaseToSend(); - InstitutionToNotify institution = new InstitutionToNotify(); - institution.setDescription("description"); - institution.setInstitutionType(InstitutionType.SA); - institution.setDigitalAddress("mail"); + InstitutionToNotify institution = getInstitutionToNotify(); RootParent rootParent = new RootParent(); rootParent.setDescription("RootDescription"); rootParent.setId("RootId"); @@ -348,4 +328,66 @@ private Product createProduct() { return product; } + + @Test + void notificationEventUserMapTest() { + NotificationUserToSend notificationUserToSend = getNotificationUserBaseToSend(); + UserToNotify user = new UserToNotify(); + user.setUserId("userId"); + user.setRole("OPERATOR"); + user.setProductRole("api"); + user.setRelationshipStatus("ACTIVE"); + notificationUserToSend.setUser(user); + + + Map properties = NotificationEventServiceDefault.notificationUserEventMap(notificationUserToSend, "topic", "traceId"); + assertNotNull(properties); + assertEquals("traceId", properties.get("notificationEventTraceId")); + assertEquals("id", properties.get("id")); + assertEquals("internal", properties.get("institutionId")); + assertEquals("prod", properties.get("product")); + assertEquals("state", properties.get("state")); + assertEquals("fileName", properties.get("fileName")); + assertEquals(properties.get("filePath"), "filePath"); + assertEquals(properties.get("contentType"), "application/octet-stream"); + + + assertEquals("userId", properties.get("userId")); + assertEquals("OPERATOR", properties.get("role")); + assertEquals("ACTIVE", properties.get("relationshipStatus")); + assertEquals("api", properties.get("productRole")); + + } + + private static InstitutionToNotify getInstitutionToNotify() { + InstitutionToNotify institution = new InstitutionToNotify(); + institution.setDescription("description"); + institution.setInstitutionType(InstitutionType.SA); + institution.setDigitalAddress("mail"); + return institution; + } + + private static NotificationToSend getNotificationBaseToSend() { + NotificationToSend notificationToSend = new NotificationToSend(); + notificationToSend.setId("id"); + notificationToSend.setInternalIstitutionID("internal"); + notificationToSend.setProduct("prod"); + notificationToSend.setState("state"); + notificationToSend.setFileName("fileName"); + notificationToSend.setFilePath("filePath"); + notificationToSend.setContentType("contentType"); + return notificationToSend; + } + + private static NotificationUserToSend getNotificationUserBaseToSend() { + NotificationUserToSend notificationUserToSend = new NotificationUserToSend(); + notificationUserToSend.setId("id"); + notificationUserToSend.setInstitutionId("internal"); + notificationUserToSend.setProduct("prod"); + notificationUserToSend.setState("state"); + notificationUserToSend.setFileName("fileName"); + notificationUserToSend.setFilePath("filePath"); + notificationUserToSend.setContentType("contentType"); + return notificationUserToSend; + } } \ No newline at end of file diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java index 0c14c0056..17b02c129 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java @@ -56,13 +56,7 @@ public void setup() { void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventAdd() { // Create Onboarding - Onboarding onboarding = createOnboarding( - OnboardingStatus.COMPLETED, - OffsetDateTime.parse("2020-11-01T10:00:00Z"), // createdAt - OffsetDateTime.parse("2020-11-02T10:02:00Z"), // activatedAt - OffsetDateTime.parse("2020-11-02T10:05:00Z"), // updatedAt - null // deletedAt - ); + Onboarding onboarding = getOnboardingTest(); Billing billing = new Billing(); billing.setTaxCodeInvoicing("taxCodeInvoicing"); onboarding.setBilling(billing); @@ -98,13 +92,7 @@ void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventAdd() { void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventUserActive() { // Create Onboarding - Onboarding onboarding = createOnboarding( - OnboardingStatus.COMPLETED, - OffsetDateTime.parse("2020-11-01T10:00:00Z"), // createdAt - OffsetDateTime.parse("2020-11-02T10:02:00Z"), // activatedAt - OffsetDateTime.parse("2020-11-02T10:05:00Z"), // updatedAt - null // deletedAt - ); + Onboarding onboarding = getOnboardingTest(); Billing billing = new Billing(); billing.setTaxCodeInvoicing("taxCodeInvoicing"); @@ -120,31 +108,15 @@ void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventUserActive() { when(coreInstitutionApi.retrieveInstitutionByIdUsingGET(any())) .thenReturn(institutionParentResource); - OnboardedProductResponse productResponse = new OnboardedProductResponse(); - productResponse.setProductId(productId); - productResponse.setStatus(OnboardedProductState.ACTIVE); - productResponse.setProductRole("security"); - productResponse.setRole("OPERATOR"); - productResponse.setEnv(Env.PROD); - productResponse.setCreatedAt(OffsetDateTime.now()); - productResponse.setUpdatedAt(OffsetDateTime.now()); + OnboardedProductResponse productResponse = getOnboardedProductResponse(); UserResponse userResponse = new UserResponse(); userResponse.id("userId1"); - List users = new ArrayList<>(); - UserDataResponse userDataResponse = new UserDataResponse(); - userDataResponse.setId("userDataId1"); - userDataResponse.setUserId("userId1"); - userDataResponse.setInstitutionId(institution.getId()); - userDataResponse.setInstitutionDescription(institution.getDescription()); - userDataResponse.setUserMailUuid("usermail1"); - userDataResponse.setRole("OPERATOR"); - userDataResponse.setStatus("ACTIVE"); - userDataResponse.setProducts(List.of(productResponse)); - userDataResponse.setUserResponse(userResponse); + UserDataResponse userDataResponse = getUserDataResponse(institution, productResponse, userResponse); + List users = new ArrayList<>(); users.add(userDataResponse); @@ -172,4 +144,41 @@ void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventUserActive() { assertEquals(productResponse.getProductRole(), notification.getUser().getProductRole()); assertEquals(productResponse.getRole(), notification.getUser().getRole()); } + + private static UserDataResponse getUserDataResponse(InstitutionResponse institution, OnboardedProductResponse productResponse, UserResponse userResponse) { + UserDataResponse userDataResponse = new UserDataResponse(); + userDataResponse.setId("userDataId1"); + userDataResponse.setUserId("userId1"); + userDataResponse.setInstitutionId(institution.getId()); + userDataResponse.setInstitutionDescription(institution.getDescription()); + userDataResponse.setUserMailUuid("usermail1"); + userDataResponse.setRole("OPERATOR"); + userDataResponse.setStatus("ACTIVE"); + userDataResponse.setProducts(List.of(productResponse)); + userDataResponse.setUserResponse(userResponse); + return userDataResponse; + } + + private static OnboardedProductResponse getOnboardedProductResponse() { + OnboardedProductResponse productResponse = new OnboardedProductResponse(); + productResponse.setProductId(productId); + productResponse.setStatus(OnboardedProductState.ACTIVE); + productResponse.setProductRole("security"); + productResponse.setRole("OPERATOR"); + productResponse.setEnv(Env.PROD); + productResponse.setCreatedAt(OffsetDateTime.now()); + productResponse.setUpdatedAt(OffsetDateTime.now()); + return productResponse; + } + + private static Onboarding getOnboardingTest() { + Onboarding onboarding = createOnboarding( + OnboardingStatus.COMPLETED, + OffsetDateTime.parse("2020-11-01T10:00:00Z"), // createdAt + OffsetDateTime.parse("2020-11-02T10:02:00Z"), // activatedAt + OffsetDateTime.parse("2020-11-02T10:05:00Z"), // updatedAt + null // deletedAt + ); + return onboarding; + } } \ No newline at end of file From c8c2135622ad36311b39b34cfce16a6ff7fe121f Mon Sep 17 00:00:00 2001 From: andrea putzu Date: Tue, 15 Oct 2024 21:32:45 +0200 Subject: [PATCH 27/27] chore: Adding Test --- .../pagopa/selfcare/onboarding/dto/NotificationUserToSend.java | 2 +- .../selfcare/onboarding/utils/FdNotificationBuilderTest.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java index ce6a05152..ca7492867 100644 --- a/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java +++ b/apps/onboarding-functions/src/main/java/it/pagopa/selfcare/onboarding/dto/NotificationUserToSend.java @@ -175,7 +175,7 @@ public void setUser(UserToNotify user) { public String toString() { return "NotificationToSend{" + "id='" + id + '\'' + - ", istitutionID='" + institutionId + '\'' + + ", institutionId='" + institutionId + '\'' + ", product='" + product + '\'' + ", state='" + state + '\'' + ", filePath='" + filePath + '\'' + diff --git a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java index 17b02c129..7f245b87c 100644 --- a/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java +++ b/apps/onboarding-functions/src/test/java/it/pagopa/selfcare/onboarding/utils/FdNotificationBuilderTest.java @@ -143,6 +143,9 @@ void toNotificationToSendWhenOnboardingHasActivatedAtAndQueueEventUserActive() { assertEquals(NotificationUserType.ACTIVE_USER, notification.getType()); assertEquals(productResponse.getProductRole(), notification.getUser().getProductRole()); assertEquals(productResponse.getRole(), notification.getUser().getRole()); + + assertTrue(notification.toString().contains("institutionId='" + notification.getInstitutionId() + "'")); + } private static UserDataResponse getUserDataResponse(InstitutionResponse institution, OnboardedProductResponse productResponse, UserResponse userResponse) {