diff --git a/.env.sample b/.env.sample index c03b41f..773468e 100644 --- a/.env.sample +++ b/.env.sample @@ -9,4 +9,7 @@ NODO_HOST=http://localhost:8086/nodo-per-pa/v1 PAA_ID_INTERMEDIARIO=PAA_ID_INTERMEDIARIO PAA_STAZIONE_INT=PAA_STAZIONE_INT PAA_PASSWORD=PAA_PASSWORD -NCRON_SCHEDULE_BATCH=*/45 * * * * * \ No newline at end of file +NCRON_SCHEDULE_BATCH=*/45 * * * * * +GPD_BASE_PATH=https://api.dev.platform.pagopa.it/gpd/api/v2 +GPD_SUBKEY=GPD_SUBKEY +FDR_EVENTHUB_CONN_STRING=FDR_EVENTHUB_CONN_STRING \ No newline at end of file diff --git a/.identity/00_data.tf b/.identity/00_data.tf index 836e357..a39c99f 100644 --- a/.identity/00_data.tf +++ b/.identity/00_data.tf @@ -1,12 +1,3 @@ -data "azurerm_resource_group" "dashboards" { - name = "dashboards" -} - -data "azurerm_kubernetes_cluster" "aks" { - name = local.aks_cluster.name - resource_group_name = local.aks_cluster.resource_group_name -} - data "github_organization_teams" "all" { root_teams_only = true summary_only = true @@ -42,13 +33,13 @@ data "azurerm_key_vault_secret" "key_vault_integration_test_subkey" { key_vault_id = data.azurerm_key_vault.key_vault.id } -data "azurerm_key_vault_secret" "flow_sa_connection_string" { - name = "flows-sa-${var.env_short}-connection-string" - key_vault_id = data.azurerm_key_vault.domain_key_vault.id -} - - data "azurerm_user_assigned_identity" "identity_cd_01"{ name = "${local.prefix}-${var.env_short}-${local.domain}-01-github-cd-identity" resource_group_name = "${local.prefix}-${var.env_short}-identity-rg" -} \ No newline at end of file +} + + +data "azurerm_key_vault_secret" "gpd_subkey" { + name = "gpd-subkey-for-reporting" + key_vault_id = data.azurerm_key_vault.domain_key_vault.id +} diff --git a/.identity/03_github_environment.tf b/.identity/03_github_environment.tf index f4e2d1a..92720f7 100644 --- a/.identity/03_github_environment.tf +++ b/.identity/03_github_environment.tf @@ -25,15 +25,14 @@ locals { "TENANT_ID" : data.azurerm_client_config.current.tenant_id, "SUBSCRIPTION_ID" : data.azurerm_subscription.current.subscription_id, "API_SUBSCRIPTION_KEY" : data.azurerm_key_vault_secret.key_vault_integration_test_subkey.value, - "FLOW_SA_CONNECTION_STRING": data.azurerm_key_vault_secret.flow_sa_connection_string.value + "GPD_SUBKEY": data.azurerm_key_vault_secret.gpd_subkey.value } env_variables = { "CONTAINER_APP_ENVIRONMENT_NAME" : local.container_app_environment.name, "CONTAINER_APP_ENVIRONMENT_RESOURCE_GROUP_NAME" : local.container_app_environment.resource_group, "CLUSTER_NAME" : local.aks_cluster.name, "CLUSTER_RESOURCE_GROUP" : local.aks_cluster.resource_group_name, - "NAMESPACE" : local.domain, - "REPORTING_BATCH_QUEUE": "pagopa${var.env_short}flowsaqueueorg" + "NAMESPACE" : local.domain } repo_secrets = { "SONAR_TOKEN" : data.azurerm_key_vault_secret.key_vault_sonar.value, diff --git a/.identity/env/dev/terraform.tfvars b/.identity/env/dev/terraform.tfvars index c07a721..68c96d2 100644 --- a/.identity/env/dev/terraform.tfvars +++ b/.identity/env/dev/terraform.tfvars @@ -8,4 +8,4 @@ tags = { Owner = "pagoPA" Source = "https://github.com/pagopa/pagopa-gpd-reporting-analysis" CostCenter = "TS310 - PAGAMENTI & SERVIZI" -} +} \ No newline at end of file diff --git a/.identity/env/prod/terraform.tfvars b/.identity/env/prod/terraform.tfvars index 5b0baed..2cbc019 100644 --- a/.identity/env/prod/terraform.tfvars +++ b/.identity/env/prod/terraform.tfvars @@ -8,4 +8,4 @@ tags = { Owner = "pagoPA" Source = "https://github.com/pagopa/pagopa-gpd-reporting-analysis" CostCenter = "TS310 - PAGAMENTI & SERVIZI" -} +} \ No newline at end of file diff --git a/.identity/env/uat/terraform.tfvars b/.identity/env/uat/terraform.tfvars index f978523..7a31828 100644 --- a/.identity/env/uat/terraform.tfvars +++ b/.identity/env/uat/terraform.tfvars @@ -8,4 +8,4 @@ tags = { Owner = "pagoPA" Source = "https://github.com/pagopa/pagopa-gpd-reporting-analysis" CostCenter = "TS310 - PAGAMENTI & SERVIZI" -} +} \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0d2e1f8..878e02e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,8 +4,8 @@ # more info https://docs.gitguardian.com/internal-repositories-monitoring/integrations/git_hooks/pre_commit repos: - repo: https://github.com/gitguardian/ggshield - rev: v1.11.0 + rev: v1.40.0 hooks: - id: ggshield language_version: python3 - stages: [ commit ] + stages: [ pre-commit ] diff --git a/host.json b/host.json index 395f9a4..d688bdb 100644 --- a/host.json +++ b/host.json @@ -12,14 +12,9 @@ "logging": { "fileLoggingMode": "debugOnly", "logLevel": { - "default": "None", - "Host.Results": "Error", - "Function.GetFlow": "Warning", - "Function.GetFlowList": "Warning", - "Microsoft": "Information", - "Worker": "Information", - "Host.Aggregator": "Error", - "Host": "Error" + "Function.GetFlow": "Information", + "Function.GetFlowList": "Information", + "Function.GpdReportingSync": "Information" }, "applicationInsights": { "samplingSettings": { diff --git a/local.settings.json.example b/local.settings.json.example index ba7fc1c..e553a8c 100644 --- a/local.settings.json.example +++ b/local.settings.json.example @@ -13,6 +13,9 @@ "NODO_HOST": "http://localhost:8081/nodo-per-pa/v1", "PAA_ID_INTERMEDIARIO":"PAA_ID_INTERMEDIARIO", "PAA_STAZIONE_INT":"PAA_STAZIONE_INT", - "PAA_PASSWORD":"PAA_PASSWORD" + "PAA_PASSWORD":"PAA_PASSWORD", + "GPD_BASE_PATH":"https://api.dev.platform.pagopa.it/gpd/api/v2", + "GPD_SUBKEY": "GPD_SUBKEY", + "FDR_EVENTHUB_CONN_STRING": "FDR_EVENTHUB_CONN_STRING" } } diff --git a/pom.xml b/pom.xml index eddbed2..d126547 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,12 @@ 2.3.1 + + com.mashape.unirest + unirest-java + 1.4.9 + + org.jboss.resteasy diff --git a/src/main/java/it/gov/pagopa/reporting/GpdReportingSync.java b/src/main/java/it/gov/pagopa/reporting/GpdReportingSync.java new file mode 100644 index 0000000..705ac16 --- /dev/null +++ b/src/main/java/it/gov/pagopa/reporting/GpdReportingSync.java @@ -0,0 +1,76 @@ +package it.gov.pagopa.reporting; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.Unirest; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.annotation.Cardinality; +import com.microsoft.azure.functions.annotation.EventHubTrigger; +import com.microsoft.azure.functions.annotation.FunctionName; +import it.gov.pagopa.reporting.model.ReportedIUVEventModel; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Azure Functions with Azure Http trigger. + */ +public class GpdReportingSync { + + private String gpdBasePath = System.getenv("GPD_BASE_PATH"); + private String gpdSubeKey = System.getenv("GPD_SUBKEY"); + + + /** + * This function will be invoked by an incoming HTTP request + * + * @return + */ + @FunctionName("GpdReportingSync") + public void run( + @EventHubTrigger( + name = "GpdReportingSyncTrigger", + eventHubName = "", // blank because the value is included in the connection string + consumerGroup = "gpd-reporting-sync", + connection = "FDR_EVENTHUB_CONN_STRING", + cardinality = Cardinality.MANY) + List items, + final ExecutionContext context) { + + Logger logger = context.getLogger(); + logger.log(Level.FINE, () -> "[GpdReportingSync] function executed at: " + LocalDateTime.now()); + + ObjectMapper objectMapper = new ObjectMapper(); + + + for (String event : items) { + ReportedIUVEventModel reportedIUVEventModel; + try { + reportedIUVEventModel = objectMapper.readValue(event, ReportedIUVEventModel.class); + } catch (Exception e) { + logger.log(Level.WARNING, () -> "[GpdReportingSync] The message was ignored because it wasn't parsed correctly. msg=[" + event + "]"); + continue; + } + gpdReport(logger, reportedIUVEventModel.getDomainId(), reportedIUVEventModel.getIuv(), String.valueOf(reportedIUVEventModel.getIdTransfer())); + } + + } + + public void gpdReport(Logger logger, String organizationId, String iuv, String transferId) { + try { + HttpResponse response = Unirest.post(gpdBasePath + "/organizations/" + organizationId + "/paymentoptions/" + iuv + "/transfers/" + transferId + "/report") + .header("accept", "application/json") + .header("ocp-apim-subscription-key", gpdSubeKey) + .asString(); + if (response.getStatus() != 200) { + logger.log(Level.SEVERE, () -> "[GpdReportingSync] GPD client failed with status " + response.getStatus() + " body:" + response.getBody()); + } + } catch (Exception e) { + logger.log(Level.SEVERE, () -> "[GpdReportingSync] GPD client Exception: " + e.getLocalizedMessage()); + } + } + + +} diff --git a/src/main/java/it/gov/pagopa/reporting/model/ReportedIUVEventModel.java b/src/main/java/it/gov/pagopa/reporting/model/ReportedIUVEventModel.java new file mode 100644 index 0000000..97808de --- /dev/null +++ b/src/main/java/it/gov/pagopa/reporting/model/ReportedIUVEventModel.java @@ -0,0 +1,58 @@ +package it.gov.pagopa.reporting.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReportedIUVEventModel { + + @JsonProperty("IUV") + private String iuv; + + @JsonProperty("IUR") + private String iur; + + @JsonProperty("IMPORTO") + private BigDecimal amount; + + @JsonProperty("COD_ESITO") + private Integer outcomeCode; + + @JsonProperty("DATA_ESITO_SINGOLO_PAGAMENTO") + private String singlePaymentOutcomeDate; + + @JsonProperty("IDSP") + private String idsp; + + @JsonProperty("ID_FLUSSO") + private String flowId; + + @JsonProperty("DATA_ORA_FLUSSO") + private String flowDateTime; + + @JsonProperty("ID_DOMINIO") + private String domainId; + + @JsonProperty("PSP") + private String psp; + + @JsonProperty("INT_PSP") + private String intPsp; + + @JsonProperty("UNIQUE_ID") + private String uniqueId; + + @JsonProperty("INSERTED_TIMESTAMP") + private String insertedTimestamp; + + @JsonProperty("ID_TRANSFER") + private Long idTransfer; +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/reporting/service/FlowsService.java b/src/main/java/it/gov/pagopa/reporting/service/FlowsService.java index 2c7156f..9238a98 100644 --- a/src/main/java/it/gov/pagopa/reporting/service/FlowsService.java +++ b/src/main/java/it/gov/pagopa/reporting/service/FlowsService.java @@ -55,7 +55,12 @@ public class FlowsService { private final String fdr3BaseUrl = System.getenv("FDR3_BASE_URL"); private final String fdr1BaseUrl = System.getenv("FDR1_BASE_URL"); - private final int flowListDepth = Integer.parseInt(System.getenv("FDR3_FLOW_LIST_DEPTH")); + private final int flowListDepth = Integer.parseInt(deNull(System.getenv("FDR3_FLOW_LIST_DEPTH"))); + + private String deNull(String fdr3FlowListDepth) { + return fdr3FlowListDepth != null ? fdr3FlowListDepth : "0"; + } + private final String listEl4Page = System.getenv("FDR3_LIST_ELEMENTS_FOR_PAGE"); public FlowsService(String storageConnectionString, String flowsTable, String containerBlob, Logger logger) { diff --git a/src/test/java/it/gov/pagopa/reporting/GpdReportingSyncTest.java b/src/test/java/it/gov/pagopa/reporting/GpdReportingSyncTest.java new file mode 100644 index 0000000..946464d --- /dev/null +++ b/src/test/java/it/gov/pagopa/reporting/GpdReportingSyncTest.java @@ -0,0 +1,62 @@ +package it.gov.pagopa.reporting; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.azure.functions.ExecutionContext; +import com.microsoft.azure.functions.HttpStatus; +import it.gov.pagopa.reporting.model.ReportedIUVEventModel; +import it.gov.pagopa.reporting.service.FlowsService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.verification.VerificationMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class GpdReportingSyncTest { + + @Spy + GpdReportingSync function; + + @Mock + ExecutionContext context; + + + + @Test + void noMessage() { + Logger logger = Logger.getLogger("testlogging"); + when(context.getLogger()).thenReturn(logger); + + List messages = new ArrayList<>(); + + function.run(messages, context); + + Mockito.verify(function, never()).gpdReport(any(), any(), any(), any()); + } + + @Test + void oneMessage() throws JsonProcessingException { + Logger logger = Logger.getLogger("testlogging"); + when(context.getLogger()).thenReturn(logger); + + List messages = new ArrayList<>(); + ReportedIUVEventModel msg = new ReportedIUVEventModel(); + var mapper = new ObjectMapper(); + messages.add(mapper.writeValueAsString(msg)); + + function.run(messages, context); + + Mockito.verify(function, times(1)).gpdReport(any(), any(), any(), any()); + } +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/reporting/service/FlowServiceIntegrationTest.java b/src/test/java/it/gov/pagopa/reporting/service/FlowServiceIntegrationTest.java index 8149807..9e30fab 100644 --- a/src/test/java/it/gov/pagopa/reporting/service/FlowServiceIntegrationTest.java +++ b/src/test/java/it/gov/pagopa/reporting/service/FlowServiceIntegrationTest.java @@ -51,7 +51,7 @@ class FlowServiceIntegrationTest { @Test void getByOrganization_noFlowDate() { flowsService = spy(new FlowsService(storageConnectionString, flowsTable, containerBlob, logger)); - String organizationId = "90000000000"; + String organizationId = "90000000000"; List flows = null; try { createTable(); @@ -65,7 +65,7 @@ void getByOrganization_noFlowDate() { @Test void getByOrganization_withFlowDate() { flowsService = spy(new FlowsService(storageConnectionString, flowsTable, containerBlob, logger)); - String organizationId = "90000000000"; + String organizationId = "90000000000"; List flows = null; try { createTable(); @@ -80,7 +80,7 @@ void getByOrganization_withFlowDate() { void getByFlow() throws Exception { flowsService = spy(new FlowsService(storageConnectionString, flowsTable, containerBlob, logger)); - String organizationId = "idPa"; + String organizationId = "idPa"; String flowId = "idFlow"; String flowDate = "dataOra"; String data = null; @@ -106,7 +106,7 @@ void getByFlow() throws Exception { void getByFlow_KO() { flowsService = spy(new FlowsService(storageConnectionString, flowsTable, containerBlob, logger)); - String organizationId = "idPa"; + String organizationId = "idPa"; String flowId = "idFlowKO"; String flowDate = "dataOra"; String data = null; @@ -123,7 +123,7 @@ void getByFlow_KO() { try { data = flowsService.getByFlow(organizationId, flowId, flowDate); assertNull(data); - } catch(Exception e) { + } catch (Exception e) { assertNull(data); } finally { blobServiceClient.deleteBlobContainer(containerBlob);