diff --git a/.github/workflows/release_deploy.yml b/.github/workflows/release_deploy.yml
index 882f1742..1a563409 100644
--- a/.github/workflows/release_deploy.yml
+++ b/.github/workflows/release_deploy.yml
@@ -21,9 +21,8 @@ on:
type: choice
description: Select the version
options:
- - ''
- - skip
- - promote
+ - patch
+ - skip_or_promote
- new_release
- breaking_change
@@ -73,7 +72,7 @@ jobs:
- if: ${{ github.ref_name != 'main' }}
run: echo "SEMVER=buildNumber" >> $GITHUB_ENV
- - if: ${{ inputs.version == 'skip' || inputs.version == 'promote' }}
+ - if: ${{ inputs.version == 'skip_or_promote' }}
run: echo "SEMVER=skip" >> $GITHUB_ENV
- id: get_semver
diff --git a/Dockerfile b/Dockerfile
index a35f12cc..0cb58758 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,11 +15,17 @@ RUN java -Djarmode=layertools -jar application.jar extract
FROM ghcr.io/pagopa/docker-base-springboot-openjdk17:v1.1.0@sha256:6fa320d452fa22066441f1ef292d15eb06f944bc8bca293e1a91ea460d30a613
+#ADD --chown=spring:spring https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.25.1/opentelemetry-javaagent.jar .
+
COPY --chown=spring:spring --from=builder dependencies/ ./
COPY --chown=spring:spring --from=builder snapshot-dependencies/ ./
+COPY --chown=spring:spring docker/applicationinsights.json ./applicationinsights.json
+
# https://github.com/moby/moby/issues/37965#issuecomment-426853382
RUN true
COPY --chown=spring:spring --from=builder spring-boot-loader/ ./
COPY --chown=spring:spring --from=builder application/ ./
EXPOSE 8080
+
+#ENTRYPOINT ["java","-javaagent:opentelemetry-javaagent.jar","--enable-preview","org.springframework.boot.loader.JarLauncher"]
\ No newline at end of file
diff --git a/docker/applicationinsights.json b/docker/applicationinsights.json
new file mode 100644
index 00000000..312fe75f
--- /dev/null
+++ b/docker/applicationinsights.json
@@ -0,0 +1,19 @@
+{
+ "selfDiagnostics": {
+ "destination": "console",
+ "level": "INFO"
+ },
+ "sampling": {
+ "requestsPerSecond": 5
+ },
+ "preview": {
+ "sampling": {
+ "overrides": [
+ {
+ "telemetryKind": "exception",
+ "percentage": 100
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/docker/run_docker.sh b/docker/run_docker.sh
index b5833247..b1e69d52 100755
--- a/docker/run_docker.sh
+++ b/docker/run_docker.sh
@@ -26,16 +26,20 @@ if test -f "$FILE"; then
rm .env
fi
config=$(yq -r '."microservice-chart".envConfig' ../helm/values-$ENV.yaml)
-for line in $(echo $config | jq -r '. | to_entries[] | select(.key) | "\(.key)=\(.value)"'); do
- echo $line >> .env
+IFS=$'\n'
+for line in $(echo "$config" | yq -r '. | to_entries[] | select(.key) | "\(.key)=\(.value)"'); do
+ echo "$line" >> .env
done
keyvault=$(yq -r '."microservice-chart".keyvault.name' ../helm/values-$ENV.yaml)
secret=$(yq -r '."microservice-chart".envSecret' ../helm/values-$ENV.yaml)
-for line in $(echo $secret | jq -r '. | to_entries[] | select(.key) | "\(.key)=\(.value)"'); do
+for line in $(echo "$secret" | yq -r '. | to_entries[] | select(.key) | "\(.key)=\(.value)"'); do
IFS='=' read -r -a array <<< "$line"
response=$(az keyvault secret show --vault-name $keyvault --name "${array[1]}")
- value=$(echo $response | jq -r '.value')
+ response=$(echo "$response" | tr -d '\n')
+ value=$(echo "$response" | yq -r '.value')
+ value=$(echo "$value" | sed 's/\$/\$\$/g')
+ value=$(echo "$value" | tr -d '\n')
echo "${array[0]}=$value" >> .env
done
@@ -43,7 +47,6 @@ done
stack_name=$(cd .. && basename "$PWD")
docker compose -p "${stack_name}" up -d --remove-orphans --force-recreate --build
-
# waiting the containers
printf 'Waiting for the service'
attempt_counter=0
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
index 33028628..22ec339c 100644
--- a/helm/Chart.yaml
+++ b/helm/Chart.yaml
@@ -2,8 +2,8 @@ apiVersion: v2
name: pagopa-gpd-payments
description: Microservice that exposes API for payment receipts retrieving and other operations
type: application
-version: 0.102.0
-appVersion: 0.12.28
+version: 0.112.0
+appVersion: 0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log
dependencies:
- name: microservice-chart
version: 2.4.0
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index 6e20efb8..18f39728 100644
--- a/helm/values-dev.yaml
+++ b/helm/values-dev.yaml
@@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-gpd-payments
- tag: "0.12.28"
+ tag: "0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log"
pullPolicy: Always
livenessProbe:
httpGet:
@@ -62,6 +62,7 @@ microservice-chart:
type: Utilization # Allowed types are 'Utilization' or 'AverageValue'
value: "75"
envConfig:
+ ENV: 'dev'
WEBSITE_SITE_NAME: 'pagopa-d-gpd-payments-service'
PAA_ID_INTERMEDIARIO: "15376371009"
PAA_STAZIONE_INT: "15376371009_01"
@@ -83,6 +84,11 @@ microservice-chart:
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
+ OTEL_SERVICE_NAME: "pagopa-gpd-payments"
+ OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=dev"
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.elastic-system.svc:4317"
+ OTEL_LOGS_EXPORTER: none
+ OTEL_TRACES_SAMPLER: "always_on"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string'
@@ -91,6 +97,7 @@ microservice-chart:
GPS_SUBSCRIPTION_KEY: "gpd-d-gps-subscription-key"
AZURE_TABLES_CONNECTION_STRING: "gpd-payments-d-cosmos-connection-string"
QUEUE_CONNECTION_STRING: "gpd-payments-d-queue-connection-string"
+ OTEL_EXPORTER_OTLP_HEADERS: elastic-apm-secret-token
keyvault:
name: "pagopa-d-gps-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml
index f5ec1431..152b7a3c 100644
--- a/helm/values-prod.yaml
+++ b/helm/values-prod.yaml
@@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-gpd-payments
- tag: "0.12.28"
+ tag: "0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log"
pullPolicy: Always
livenessProbe:
httpGet:
@@ -62,6 +62,7 @@ microservice-chart:
type: Utilization # Allowed types are 'Utilization' or 'AverageValue'
value: "75"
envConfig:
+ ENV: 'prod'
WEBSITE_SITE_NAME: 'pagopa-p-gpd-payments-service'
PAA_ID_INTERMEDIARIO: "15376371009"
PAA_STAZIONE_INT: "15376371009_01"
@@ -83,6 +84,11 @@ microservice-chart:
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
+ OTEL_SERVICE_NAME: "pagopa-gpd-payments"
+ OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=uat"
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.elastic-system.svc:4317"
+ OTEL_LOGS_EXPORTER: none
+ OTEL_TRACES_SAMPLER: "always_on"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-p-connection-string'
@@ -91,6 +97,7 @@ microservice-chart:
GPS_SUBSCRIPTION_KEY: "gpd-p-gps-subscription-key"
AZURE_TABLES_CONNECTION_STRING: "gpd-payments-p-cosmos-connection-string"
QUEUE_CONNECTION_STRING: "gpd-payments-p-queue-connection-string"
+ OTEL_EXPORTER_OTLP_HEADERS: elastic-apm-secret-token
keyvault:
name: "pagopa-p-gps-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index 96768bba..daa4fddb 100644
--- a/helm/values-uat.yaml
+++ b/helm/values-uat.yaml
@@ -4,7 +4,7 @@ microservice-chart:
fullnameOverride: ""
image:
repository: ghcr.io/pagopa/pagopa-gpd-payments
- tag: "0.12.28"
+ tag: "0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log"
pullPolicy: Always
livenessProbe:
httpGet:
@@ -62,6 +62,7 @@ microservice-chart:
type: Utilization # Allowed types are 'Utilization' or 'AverageValue'
value: "75"
envConfig:
+ ENV: 'uat'
WEBSITE_SITE_NAME: 'pagopa-u-gpd-payments-service'
PAA_ID_INTERMEDIARIO: "15376371009"
PAA_STAZIONE_INT: "15376371009_01"
@@ -83,6 +84,11 @@ microservice-chart:
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
+ OTEL_SERVICE_NAME: "pagopa-gpd-payments"
+ OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=prod"
+ OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.elastic-system.svc:4317"
+ OTEL_LOGS_EXPORTER: none
+ OTEL_TRACES_SAMPLER: "always_on"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-u-connection-string'
@@ -91,6 +97,7 @@ microservice-chart:
GPS_SUBSCRIPTION_KEY: "gpd-u-gps-subscription-key"
AZURE_TABLES_CONNECTION_STRING: "gpd-payments-u-cosmos-connection-string"
QUEUE_CONNECTION_STRING: "gpd-payments-u-queue-connection-string"
+ OTEL_EXPORTER_OTLP_HEADERS: elastic-apm-secret-token
keyvault:
name: "pagopa-u-gps-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
diff --git a/openapi/openapi.json b/openapi/openapi.json
index 8cdeca4d..e8c0da74 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -1,554 +1,515 @@
{
- "openapi": "3.0.1",
- "info": {
- "title": "PagoPA API Payments",
- "description": "Payments",
- "termsOfService": "https://www.pagopa.gov.it/",
- "version": "0.12.28"
+ "openapi" : "3.0.1",
+ "info" : {
+ "title" : "PagoPA API Payments",
+ "description" : "Payments",
+ "termsOfService" : "https://www.pagopa.gov.it/",
+ "version" : "0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log"
},
- "servers": [
- {
- "url": "http://localhost",
- "description": "Generated server url"
- }
- ],
- "tags": [
- {
- "name": "Payments receipts API"
- }
- ],
- "paths": {
- "/info": {
- "get": {
- "tags": [
- "Home"
- ],
- "summary": "health check",
- "description": "Return OK if application is started",
- "operationId": "healthCheck",
- "responses": {
- "200": {
- "description": "OK",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "servers" : [ {
+ "url" : "http://localhost",
+ "description" : "Generated server url"
+ } ],
+ "tags" : [ {
+ "name" : "Payments receipts API"
+ } ],
+ "paths" : {
+ "/info" : {
+ "get" : {
+ "tags" : [ "Home" ],
+ "summary" : "health check",
+ "description" : "Return OK if application is started",
+ "operationId" : "healthCheck",
+ "responses" : {
+ "200" : {
+ "description" : "OK",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/AppInfo"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/AppInfo"
}
}
}
},
- "400": {
- "description": "Bad Request",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "400" : {
+ "description" : "Bad Request",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
- "401": {
- "description": "Unauthorized",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "401" : {
+ "description" : "Unauthorized",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "403": {
- "description": "Forbidden",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "403" : {
+ "description" : "Forbidden",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "429": {
- "description": "Too many requests",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "429" : {
+ "description" : "Too many requests",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "500": {
- "description": "Service unavailable",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "500" : {
+ "description" : "Service unavailable",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
}
},
- "security": [
- {
- "ApiKey": []
- },
- {
- "Authorization": []
- }
- ]
+ "security" : [ {
+ "ApiKey" : [ ]
+ }, {
+ "Authorization" : [ ]
+ } ]
},
- "parameters": [
- {
- "name": "X-Request-Id",
- "in": "header",
- "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
- "schema": {
- "type": "string"
- }
+ "parameters" : [ {
+ "name" : "X-Request-Id",
+ "in" : "header",
+ "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
+ "schema" : {
+ "type" : "string"
}
- ]
+ } ]
},
- "/payments/{organizationfiscalcode}/receipts": {
- "get": {
- "tags": [
- "Payments receipts API"
- ],
- "summary": "Return the list of the organization receipts.",
- "operationId": "getOrganizationReceipts",
- "parameters": [
- {
- "name": "organizationfiscalcode",
- "in": "path",
- "description": "Organization fiscal code, the fiscal code of the Organization.",
- "required": true,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "pageNum",
- "in": "query",
- "description": "Page number, starts from 0",
- "required": false,
- "schema": {
- "minimum": 0,
- "type": "integer",
- "format": "int32",
- "default": 0
- }
- },
- {
- "name": "pageSize",
- "in": "query",
- "description": "Number of elements per page. Default = 20",
- "required": false,
- "schema": {
- "maximum": 100,
- "type": "integer",
- "format": "int32",
- "default": 20
- }
- },
- {
- "name": "debtor",
- "in": "query",
- "description": "Filter by debtor",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "service",
- "in": "query",
- "description": "Filter by service",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "from",
- "in": "query",
- "description": "Filter by date, from this date",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "to",
- "in": "query",
- "description": "Filter by date, to this date",
- "required": false,
- "schema": {
- "type": "string"
- }
- },
- {
- "name": "segregationCodes",
- "in": "query",
- "description": "Segregation codes for which broker is authorized",
- "required": false,
- "schema": {
- "pattern": "\\d{2}(,\\d{2})*",
- "type": "string"
- }
- },
- {
- "name": "debtorOrIuv",
- "in": "query",
- "description": "Filter start of debtor or IUV",
- "required": false,
- "schema": {
- "type": "string"
- }
+ "/payments/{organizationfiscalcode}/receipts" : {
+ "get" : {
+ "tags" : [ "Payments receipts API" ],
+ "summary" : "Return the list of the organization receipts.",
+ "operationId" : "getOrganizationReceipts",
+ "parameters" : [ {
+ "name" : "organizationfiscalcode",
+ "in" : "path",
+ "description" : "Organization fiscal code, the fiscal code of the Organization.",
+ "required" : true,
+ "schema" : {
+ "type" : "string"
+ }
+ }, {
+ "name" : "pageNum",
+ "in" : "query",
+ "description" : "Page number, starts from 0",
+ "required" : false,
+ "schema" : {
+ "minimum" : 0,
+ "type" : "integer",
+ "format" : "int32",
+ "default" : 0
}
- ],
- "responses": {
- "200": {
- "description": "Obtained all organization payment positions.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ }, {
+ "name" : "pageSize",
+ "in" : "query",
+ "description" : "Number of elements per page. Default = 20",
+ "required" : false,
+ "schema" : {
+ "maximum" : 100,
+ "type" : "integer",
+ "format" : "int32",
+ "default" : 20
+ }
+ }, {
+ "name" : "debtor",
+ "in" : "query",
+ "description" : "Filter by debtor",
+ "required" : false,
+ "schema" : {
+ "type" : "string"
+ }
+ }, {
+ "name" : "service",
+ "in" : "query",
+ "description" : "Filter by service",
+ "required" : false,
+ "schema" : {
+ "type" : "string"
+ }
+ }, {
+ "name" : "from",
+ "in" : "query",
+ "description" : "Filter by date, from this date",
+ "required" : false,
+ "schema" : {
+ "type" : "string"
+ }
+ }, {
+ "name" : "to",
+ "in" : "query",
+ "description" : "Filter by date, to this date",
+ "required" : false,
+ "schema" : {
+ "type" : "string"
+ }
+ }, {
+ "name" : "segregationCodes",
+ "in" : "query",
+ "description" : "Segregation codes for which broker is authorized",
+ "required" : false,
+ "schema" : {
+ "pattern" : "\\d{2}(,\\d{2})*",
+ "type" : "string"
+ }
+ }, {
+ "name" : "debtorOrIuv",
+ "in" : "query",
+ "description" : "Filter start of debtor or IUV",
+ "required" : false,
+ "schema" : {
+ "type" : "string"
+ }
+ } ],
+ "responses" : {
+ "200" : {
+ "description" : "Obtained all organization payment positions.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/PaymentsResult"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/PaymentsResult"
}
}
}
},
- "401": {
- "description": "Wrong or missing function key.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "401" : {
+ "description" : "Wrong or missing function key.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "404": {
- "description": "No receipts found.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "404" : {
+ "description" : "No receipts found.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
- "500": {
- "description": "Service unavailable.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "500" : {
+ "description" : "Service unavailable.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
}
},
- "security": [
- {
- "ApiKey": []
- },
- {
- "Authorization": []
- }
- ]
+ "security" : [ {
+ "ApiKey" : [ ]
+ }, {
+ "Authorization" : [ ]
+ } ]
},
- "parameters": [
- {
- "name": "X-Request-Id",
- "in": "header",
- "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
- "schema": {
- "type": "string"
- }
+ "parameters" : [ {
+ "name" : "X-Request-Id",
+ "in" : "header",
+ "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
+ "schema" : {
+ "type" : "string"
}
- ]
+ } ]
},
- "/payments/{organizationfiscalcode}/receipts/{iuv}": {
- "get": {
- "tags": [
- "Payments receipts API"
- ],
- "summary": "Return the details of a specific receipt.",
- "operationId": "getReceiptByIUV",
- "parameters": [
- {
- "name": "organizationfiscalcode",
- "in": "path",
- "description": "Organization fiscal code, the fiscal code of the Organization.",
- "required": true,
- "schema": {
- "type": "string"
- },
- "example": 12345
- },
- {
- "name": "iuv",
- "in": "path",
- "description": "IUV (Unique Payment Identification). Alphanumeric code that uniquely associates and identifies three key elements of a payment: reason, payer, amount",
- "required": true,
- "schema": {
- "type": "string"
- },
- "example": "ABC123"
- },
- {
- "name": "segregationCodes",
- "in": "query",
- "description": "Segregation codes for which broker is authorized",
- "required": false,
- "schema": {
- "pattern": "\\d{2}(,\\d{2})*",
- "type": "string"
- }
+ "/payments/{organizationfiscalcode}/receipts/{iuv}" : {
+ "get" : {
+ "tags" : [ "Payments receipts API" ],
+ "summary" : "Return the details of a specific receipt.",
+ "operationId" : "getReceiptByIUV",
+ "parameters" : [ {
+ "name" : "organizationfiscalcode",
+ "in" : "path",
+ "description" : "Organization fiscal code, the fiscal code of the Organization.",
+ "required" : true,
+ "schema" : {
+ "type" : "string"
+ },
+ "example" : 12345
+ }, {
+ "name" : "iuv",
+ "in" : "path",
+ "description" : "IUV (Unique Payment Identification). Alphanumeric code that uniquely associates and identifies three key elements of a payment: reason, payer, amount",
+ "required" : true,
+ "schema" : {
+ "type" : "string"
+ },
+ "example" : "ABC123"
+ }, {
+ "name" : "segregationCodes",
+ "in" : "query",
+ "description" : "Segregation codes for which broker is authorized",
+ "required" : false,
+ "schema" : {
+ "pattern" : "\\d{2}(,\\d{2})*",
+ "type" : "string"
}
- ],
- "responses": {
- "200": {
- "description": "Obtained receipt details.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ } ],
+ "responses" : {
+ "200" : {
+ "description" : "Obtained receipt details.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/xml": {
- "schema": {
- "type": "string"
+ "content" : {
+ "application/xml" : {
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "401": {
- "description": "Wrong or missing function key.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "401" : {
+ "description" : "Wrong or missing function key.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
}
},
- "404": {
- "description": "No receipt found.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "404" : {
+ "description" : "No receipt found.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/xml": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/xml" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
},
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
- "422": {
- "description": "Unable to process the request.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "422" : {
+ "description" : "Unable to process the request.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/xml": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/xml" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
},
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
- "500": {
- "description": "Service unavailable.",
- "headers": {
- "X-Request-Id": {
- "description": "This header identifies the call",
- "schema": {
- "type": "string"
+ "500" : {
+ "description" : "Service unavailable.",
+ "headers" : {
+ "X-Request-Id" : {
+ "description" : "This header identifies the call",
+ "schema" : {
+ "type" : "string"
}
}
},
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/ProblemJson"
+ "content" : {
+ "application/json" : {
+ "schema" : {
+ "$ref" : "#/components/schemas/ProblemJson"
}
}
}
}
},
- "security": [
- {
- "ApiKey": []
- },
- {
- "Authorization": []
- }
- ]
+ "security" : [ {
+ "ApiKey" : [ ]
+ }, {
+ "Authorization" : [ ]
+ } ]
},
- "parameters": [
- {
- "name": "X-Request-Id",
- "in": "header",
- "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
- "schema": {
- "type": "string"
- }
+ "parameters" : [ {
+ "name" : "X-Request-Id",
+ "in" : "header",
+ "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
+ "schema" : {
+ "type" : "string"
}
- ]
+ } ]
}
},
- "components": {
- "schemas": {
- "ProblemJson": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string",
- "description": "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable"
- },
- "status": {
- "maximum": 600,
- "minimum": 100,
- "type": "integer",
- "description": "The HTTP status code generated by the origin server for this occurrence of the problem.",
- "format": "int32",
- "example": 200
- },
- "detail": {
- "type": "string",
- "description": "A human readable explanation specific to this occurrence of the problem.",
- "example": "There was an error processing the request"
+ "components" : {
+ "schemas" : {
+ "ProblemJson" : {
+ "type" : "object",
+ "properties" : {
+ "title" : {
+ "type" : "string",
+ "description" : "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable"
+ },
+ "status" : {
+ "maximum" : 600,
+ "minimum" : 100,
+ "type" : "integer",
+ "description" : "The HTTP status code generated by the origin server for this occurrence of the problem.",
+ "format" : "int32",
+ "example" : 200
+ },
+ "detail" : {
+ "type" : "string",
+ "description" : "A human readable explanation specific to this occurrence of the problem.",
+ "example" : "There was an error processing the request"
}
}
},
- "PaymentsResult": {
- "type": "object",
- "properties": {
- "currentPageNumber": {
- "type": "integer",
- "format": "int32"
- },
- "length": {
- "type": "integer",
- "format": "int32"
- },
- "totalPages": {
- "type": "integer",
- "format": "int32"
- },
- "results": {
- "type": "array",
- "items": {
- "type": "object"
+ "PaymentsResult" : {
+ "type" : "object",
+ "properties" : {
+ "currentPageNumber" : {
+ "type" : "integer",
+ "format" : "int32"
+ },
+ "length" : {
+ "type" : "integer",
+ "format" : "int32"
+ },
+ "totalPages" : {
+ "type" : "integer",
+ "format" : "int32"
+ },
+ "results" : {
+ "type" : "array",
+ "items" : {
+ "type" : "object"
}
}
}
},
- "AppInfo": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
+ "AppInfo" : {
+ "type" : "object",
+ "properties" : {
+ "name" : {
+ "type" : "string"
},
- "version": {
- "type": "string"
+ "version" : {
+ "type" : "string"
},
- "environment": {
- "type": "string"
+ "environment" : {
+ "type" : "string"
}
}
}
},
- "securitySchemes": {
- "ApiKey": {
- "type": "apiKey",
- "description": "The API key to access this function app.",
- "name": "Ocp-Apim-Subscription-Key",
- "in": "header"
+ "securitySchemes" : {
+ "ApiKey" : {
+ "type" : "apiKey",
+ "description" : "The API key to access this function app.",
+ "name" : "Ocp-Apim-Subscription-Key",
+ "in" : "header"
},
- "Authorization": {
- "type": "http",
- "description": "JWT token get after Azure Login",
- "scheme": "bearer",
- "bearerFormat": "JWT"
+ "Authorization" : {
+ "type" : "http",
+ "description" : "JWT token get after Azure Login",
+ "scheme" : "bearer",
+ "bearerFormat" : "JWT"
}
}
}
-}
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 72f7da40..6f16894b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
it.gov.pagopa
payments
- 0.12.28
+ 0.12.28-10-PAGOPA-2178-gpd-debito-tecnico-ottimizzazione-dei-log
Payments
Payments
@@ -146,6 +146,12 @@
+
+
+ co.elastic.logging
+ logback-ecs-encoder
+ 1.6.0
+
diff --git a/src/main/java/it/gov/pagopa/payments/config/LoggingAspect.java b/src/main/java/it/gov/pagopa/payments/config/LoggingAspect.java
index b53627fc..646e4b88 100644
--- a/src/main/java/it/gov/pagopa/payments/config/LoggingAspect.java
+++ b/src/main/java/it/gov/pagopa/payments/config/LoggingAspect.java
@@ -1,95 +1,179 @@
package it.gov.pagopa.payments.config;
+import static it.gov.pagopa.payments.utils.CommonUtil.deNull;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import it.gov.pagopa.payments.exception.AppError;
+import it.gov.pagopa.payments.model.ProblemJson;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.bind.JAXBElement;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.event.ContextRefreshedEvent;
-import org.springframework.context.event.EventListener;
-import org.springframework.core.env.AbstractEnvironment;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.Environment;
-import org.springframework.core.env.MutablePropertySources;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
-import javax.annotation.PostConstruct;
-import java.util.Arrays;
-import java.util.stream.StreamSupport;
-
@Aspect
@Component
@Slf4j
public class LoggingAspect {
- @Value("${application.name}")
- private String name;
+ public static final String START_TIME = "startTime";
+ public static final String METHOD = "method";
+ public static final String STATUS = "status";
+ public static final String CODE = "httpCode";
+ public static final String RESPONSE_TIME = "responseTime";
+ public static final String FAULT_CODE = "faultCode";
+ public static final String FAULT_DETAIL = "faultDetail";
+ public static final String REQUEST_ID = "requestId";
+ public static final String OPERATION_ID = "operationId";
+ public static final String ARGS = "args";
- @Value("${application.version}")
- private String version;
+ final HttpServletRequest httRequest;
- @Value("${properties.environment}")
- private String environment;
+ final HttpServletResponse httpResponse;
- /**
- * Log essential info of application during the startup.
- */
- @PostConstruct
- public void logStartup() {
- log.info("-> Starting {} version {} - environment {}", name, version, environment);
- }
+ @Value("${info.application.name}")
+ private String name;
- /**
- * If DEBUG log-level is enabled prints the env variables and the application properties.
- *
- * @param event Context of application
- */
- @EventListener
- public void handleContextRefresh(ContextRefreshedEvent event) {
- final Environment env = event.getApplicationContext().getEnvironment();
- log.debug("Active profiles: {}", Arrays.toString(env.getActiveProfiles()));
- final MutablePropertySources sources = ((AbstractEnvironment) env).getPropertySources();
- StreamSupport.stream(sources.spliterator(), false)
- .filter(EnumerablePropertySource.class::isInstance)
- .map(ps -> ((EnumerablePropertySource>) ps).getPropertyNames())
- .flatMap(Arrays::stream)
- .distinct()
- .filter(
- prop ->
- !(prop.toLowerCase().contains("credentials")
- || prop.toLowerCase().contains("password")
- || prop.toLowerCase().contains("pass")
- || prop.toLowerCase().contains("pwd")))
- .forEach(prop -> log.debug("{}: {}", prop, env.getProperty(prop)));
- }
+ @Value("${info.application.version}")
+ private String version;
+ @Value("${info.properties.environment}")
+ private String environment;
- @AfterReturning(value = "execution(* it.gov.pagopa.payments.controller..*.*(..)) || execution(* it.gov.pagopa.payments.endpoints..*.*(..))", returning = "result")
- public void returnApiInvocation(JoinPoint joinPoint, Object result) {
- log.debug("Successful API operation {} - result: {}", joinPoint.getSignature().getName(), result);
- }
+ public LoggingAspect(HttpServletRequest httRequest, HttpServletResponse httpResponse) {
+ this.httRequest = httRequest;
+ this.httpResponse = httpResponse;
+ }
+
+ private static String getDetail(ResponseEntity result) {
+ if (result != null && result.getBody() != null && result.getBody().getDetail() != null) {
+ return result.getBody().getDetail();
+ } else return AppError.UNKNOWN.getDetails();
+ }
- @AfterReturning(
- value = "execution(* it.gov.pagopa.payments.exception.ErrorHandler.*(..))",
- returning = "result")
- public void trowingApiInvocation(JoinPoint joinPoint, Object result) {
- log.info("Failed API operation {} - error: {}", joinPoint.getSignature().getName(), result);
+ private static String getTitle(ResponseEntity result) {
+ if (result != null && result.getBody() != null && result.getBody().getTitle() != null) {
+ return result.getBody().getTitle();
+ } else return AppError.UNKNOWN.getTitle();
+ }
+
+ public static String getExecutionTime() {
+ String startTime = MDC.get(START_TIME);
+ if (startTime != null) {
+ long endTime = System.currentTimeMillis();
+ long executionTime = endTime - Long.parseLong(startTime);
+ return String.valueOf(executionTime);
}
+ return "-";
+ }
- @Around(value = "execution(* it.gov.pagopa.payments.service..*.*(..))")
- public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
- long startTime = System.currentTimeMillis();
- Object result = joinPoint.proceed();
- long endTime = System.currentTimeMillis();
- log.debug("Time taken for Execution of {} is: {}ms", joinPoint.getSignature().toShortString(), (endTime - startTime));
- return result;
+ private static Map getParams(ProceedingJoinPoint joinPoint) {
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+ Method method = signature.getMethod();
+ Map params = new HashMap<>();
+ int i = 0;
+ for (var parameter : method.getParameters()) {
+ var paramName = parameter.getName();
+ var arg = joinPoint.getArgs()[i++];
+ if (arg instanceof JAXBElement>) {
+ try {
+ arg = new ObjectMapper().writer().writeValueAsString(arg);
+ } catch (JsonProcessingException e) {
+ arg = "unreadable!";
+ }
+ }
+ params.put(paramName, deNull(arg));
}
+ return params;
+ }
+
+ @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
+ public void restController() {
+ // all rest controllers
+ }
- @Before(value = "execution(* it.gov.pagopa.payments..*.*(..))")
- public void logTrace(JoinPoint joinPoint) {
- log.trace("Trace method {} - args: {}", joinPoint.getSignature().toShortString(), joinPoint.getArgs());
+ @Pointcut("@within(org.springframework.ws.server.endpoint.annotation.Endpoint)")
+ public void endpointClass() {
+ // all rest controllers
+ }
+
+ @Pointcut("@within(org.springframework.stereotype.Repository)")
+ public void repository() {
+ // all repository methods
+ }
+
+ @Pointcut("@within(org.springframework.stereotype.Service)")
+ public void service() {
+ // all service methods
+ }
+
+ /** Log essential info of application during the startup. */
+ @PostConstruct
+ public void logStartup() {
+ log.info("-> Starting {} version {} - environment {}", name, version, environment);
+ }
+
+ @Around(value = "restController() || endpointClass()")
+ public Object logApiInvocation(ProceedingJoinPoint joinPoint) throws Throwable {
+ MDC.put(METHOD, joinPoint.getSignature().getName());
+ MDC.put(START_TIME, String.valueOf(System.currentTimeMillis()));
+ MDC.put(OPERATION_ID, UUID.randomUUID().toString());
+ if (MDC.get(REQUEST_ID) == null) {
+ var requestId = UUID.randomUUID().toString();
+ MDC.put(REQUEST_ID, requestId);
}
+ Map params = getParams(joinPoint);
+ MDC.put(ARGS, params.toString());
+
+ log.info("Invoking API operation {} - args: {}", joinPoint.getSignature().getName(), params);
+
+ Object result = joinPoint.proceed();
+
+ MDC.put(STATUS, "OK");
+ MDC.put(CODE, String.valueOf(httpResponse.getStatus()));
+ MDC.put(RESPONSE_TIME, getExecutionTime());
+ log.info(
+ "Successful API operation {} - result: {}", joinPoint.getSignature().getName(), result);
+ MDC.remove(STATUS);
+ MDC.remove(CODE);
+ MDC.remove(RESPONSE_TIME);
+ MDC.remove(START_TIME);
+ return result;
+ }
+
+ @AfterReturning(value = "execution(* *..exception.ErrorHandler.*(..))", returning = "result")
+ public void trowingApiInvocation(JoinPoint joinPoint, ResponseEntity result) {
+ MDC.put(STATUS, "KO");
+ MDC.put(CODE, String.valueOf(result.getStatusCode().value()));
+ MDC.put(RESPONSE_TIME, getExecutionTime());
+ MDC.put(FAULT_CODE, getTitle(result));
+ MDC.put(FAULT_DETAIL, getDetail(result));
+ log.info("Failed API operation {} - error: {}", MDC.get(METHOD), result);
+ MDC.clear();
+ }
+
+ @Around(value = "repository() || service()")
+ public Object logTrace(ProceedingJoinPoint joinPoint) throws Throwable {
+ Map params = getParams(joinPoint);
+ log.debug("Call method {} - args: {}", joinPoint.getSignature().toShortString(), params);
+ Object result = joinPoint.proceed();
+ log.debug("Return method {} - result: {}", joinPoint.getSignature().toShortString(), result);
+ return result;
+ }
}
diff --git a/src/main/java/it/gov/pagopa/payments/config/SwaggerConfig.java b/src/main/java/it/gov/pagopa/payments/config/SwaggerConfig.java
index ab7f8dd7..8af9069b 100644
--- a/src/main/java/it/gov/pagopa/payments/config/SwaggerConfig.java
+++ b/src/main/java/it/gov/pagopa/payments/config/SwaggerConfig.java
@@ -22,8 +22,8 @@ public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI(
- @Value("${application.description}") String appDescription,
- @Value("${application.version}") String appVersion) {
+ @Value("${info.application.description}") String appDescription,
+ @Value("${info.application.version}") String appVersion) {
return new OpenAPI()
.components(
new Components()
@@ -55,7 +55,10 @@ public OpenAPI customOpenAPI(
public OpenApiCustomiser sortOperationsAlphabetically() {
return openApi -> {
Paths paths =
- openApi.getPaths().entrySet().stream()
+ openApi
+ .getPaths()
+ .entrySet()
+ .stream()
.sorted(Map.Entry.comparingByKey())
.collect(
Paths::new,
@@ -68,7 +71,10 @@ public OpenApiCustomiser sortOperationsAlphabetically() {
.forEach(
operation -> {
var responses =
- operation.getResponses().entrySet().stream()
+ operation
+ .getResponses()
+ .entrySet()
+ .stream()
.sorted(Map.Entry.comparingByKey())
.collect(
ApiResponses::new,
diff --git a/src/main/java/it/gov/pagopa/payments/controller/BaseController.java b/src/main/java/it/gov/pagopa/payments/controller/BaseController.java
index d918ac23..3e5c4306 100644
--- a/src/main/java/it/gov/pagopa/payments/controller/BaseController.java
+++ b/src/main/java/it/gov/pagopa/payments/controller/BaseController.java
@@ -20,13 +20,13 @@
@RestController()
public class BaseController {
- @Value("${application.name}")
+ @Value("${info.application.name}")
private String name;
- @Value("${application.version}")
+ @Value("${info.application.version}")
private String version;
- @Value("${properties.environment}")
+ @Value("${info.properties.environment}")
private String environment;
@Value("${server.servlet.context-path:/}")
@@ -47,50 +47,64 @@ public RedirectView home() {
}
@Operation(
- summary = "health check",
- description = "Return OK if application is started",
- security = {
- @SecurityRequirement(name = "ApiKey"),
- @SecurityRequirement(name = "Authorization")
- },
- tags = {"Home"})
+ summary = "health check",
+ description = "Return OK if application is started",
+ security = {
+ @SecurityRequirement(name = "ApiKey"),
+ @SecurityRequirement(name = "Authorization")
+ },
+ tags = {"Home"}
+ )
@ApiResponses(
- value = {
- @ApiResponse(
- responseCode = "200",
- description = "OK",
- content =
- @Content(
- mediaType = MediaType.APPLICATION_JSON_VALUE,
- schema = @Schema(implementation = AppInfo.class))),
- @ApiResponse(
- responseCode = "400",
- description = "Bad Request",
- content =
- @Content(
- mediaType = MediaType.APPLICATION_JSON_VALUE,
- schema = @Schema(implementation = ProblemJson.class))),
- @ApiResponse(
- responseCode = "401",
- description = "Unauthorized",
- content = @Content(schema = @Schema())),
- @ApiResponse(
- responseCode = "403",
- description = "Forbidden",
- content = @Content(schema = @Schema())),
- @ApiResponse(
- responseCode = "429",
- description = "Too many requests",
- content = @Content(schema = @Schema())),
- @ApiResponse(
- responseCode = "500",
- description = "Service unavailable",
- content =
- @Content(
- mediaType = MediaType.APPLICATION_JSON_VALUE,
- schema = @Schema(implementation = ProblemJson.class)))
- })
- @GetMapping(value = "/info", produces = {MediaType.APPLICATION_JSON_VALUE})
+ value = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "OK",
+ content =
+ @Content(
+ mediaType = MediaType.APPLICATION_JSON_VALUE,
+ schema = @Schema(implementation = AppInfo.class)
+ )
+ ),
+ @ApiResponse(
+ responseCode = "400",
+ description = "Bad Request",
+ content =
+ @Content(
+ mediaType = MediaType.APPLICATION_JSON_VALUE,
+ schema = @Schema(implementation = ProblemJson.class)
+ )
+ ),
+ @ApiResponse(
+ responseCode = "401",
+ description = "Unauthorized",
+ content = @Content(schema = @Schema())
+ ),
+ @ApiResponse(
+ responseCode = "403",
+ description = "Forbidden",
+ content = @Content(schema = @Schema())
+ ),
+ @ApiResponse(
+ responseCode = "429",
+ description = "Too many requests",
+ content = @Content(schema = @Schema())
+ ),
+ @ApiResponse(
+ responseCode = "500",
+ description = "Service unavailable",
+ content =
+ @Content(
+ mediaType = MediaType.APPLICATION_JSON_VALUE,
+ schema = @Schema(implementation = ProblemJson.class)
+ )
+ )
+ }
+ )
+ @GetMapping(
+ value = "/info",
+ produces = {MediaType.APPLICATION_JSON_VALUE}
+ )
@ResponseStatus(HttpStatus.OK)
public ResponseEntity healthCheck() {
// Used just for health checking
diff --git a/src/main/java/it/gov/pagopa/payments/controller/receipt/impl/PaymentsController.java b/src/main/java/it/gov/pagopa/payments/controller/receipt/impl/PaymentsController.java
index 64436e8c..e202c975 100644
--- a/src/main/java/it/gov/pagopa/payments/controller/receipt/impl/PaymentsController.java
+++ b/src/main/java/it/gov/pagopa/payments/controller/receipt/impl/PaymentsController.java
@@ -1,14 +1,14 @@
package it.gov.pagopa.payments.controller.receipt.impl;
+import static it.gov.pagopa.payments.utils.CommonUtil.sanitizeInput;
+
import it.gov.pagopa.payments.controller.receipt.IPaymentsController;
import it.gov.pagopa.payments.entity.ReceiptEntity;
import it.gov.pagopa.payments.model.PaymentsResult;
import it.gov.pagopa.payments.model.ReceiptModelResponse;
import it.gov.pagopa.payments.service.PaymentsService;
-
import java.util.ArrayList;
import java.util.Arrays;
-
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,8 +17,6 @@
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
-import static it.gov.pagopa.payments.utils.CommonUtil.sanitizeInput;
-
@Controller
@Slf4j
@Validated
@@ -26,33 +24,80 @@ public class PaymentsController implements IPaymentsController {
private static final String LOG_BASE_HEADER_INFO =
"[RequestMethod: %s] - [ClassMethod: %s] - [MethodParamsToLog: %s]";
- private static final String LOG_BASE_PARAMS_DETAIL = "organizationFiscalCode= %s";
@Autowired private ModelMapper modelMapper;
@Autowired private PaymentsService paymentsService;
@Override
- public ResponseEntity getReceiptByIUV(String organizationFiscalCode, String iuv, String segregationCodes) {
- log.info(String.format(LOG_BASE_HEADER_INFO, "GET", "getReceiptByIUV", String.format(LOG_BASE_PARAMS_DETAIL, organizationFiscalCode) + "; iuv= " + iuv
- + "; validSegregationCodes= " + segregationCodes));
+ public ResponseEntity getReceiptByIUV(
+ String organizationFiscalCode, String iuv, String segregationCodes) {
+ String sanitizedOrganizationFiscalCode = sanitizeInput(organizationFiscalCode);
+ String sanitizedIuv = sanitizeInput(iuv);
+ String sanitizedSegregationCodes = sanitizeInput(segregationCodes);
+ log.debug(
+ String.format(
+ LOG_BASE_HEADER_INFO,
+ "GET",
+ "getReceiptByIUV",
+ "organizationFiscalCode="
+ + sanitizedOrganizationFiscalCode
+ + "; iuv= "
+ + sanitizedIuv
+ + "; validSegregationCodes= "
+ + sanitizedSegregationCodes));
- ArrayList segCodesList = segregationCodes != null ? new ArrayList<>(Arrays.asList(segregationCodes.split(","))) : null;
- ReceiptEntity receipt = paymentsService
- .getReceiptByOrganizationFCAndIUV(organizationFiscalCode, iuv, segCodesList);
+ ArrayList segCodesList =
+ segregationCodes != null
+ ? new ArrayList<>(Arrays.asList(segregationCodes.split(",")))
+ : null;
+ ReceiptEntity receipt =
+ paymentsService.getReceiptByOrganizationFCAndIUV(organizationFiscalCode, iuv, segCodesList);
return new ResponseEntity<>(receipt.getDocument(), HttpStatus.OK);
}
@Override
- public ResponseEntity> getOrganizationReceipts(String organizationFiscalCode, int pageNum, int pageSize, String debtor,
- String service, String from, String to, String segregationCodes, String debtorOrIuv) {
+ public ResponseEntity> getOrganizationReceipts(
+ String organizationFiscalCode,
+ int pageNum,
+ int pageSize,
+ String debtor,
+ String service,
+ String from,
+ String to,
+ String segregationCodes,
+ String debtorOrIuv) {
- log.info(String.format(LOG_BASE_HEADER_INFO, "GET", "getOrganizationReceipts", String.format(LOG_BASE_PARAMS_DETAIL, sanitizeInput(organizationFiscalCode)
- + "; debtor= " + sanitizeInput(debtor) + "; service= " + sanitizeInput(service) + "; validSegregationCodes= " + sanitizeInput(segregationCodes))));
+ String sanitizedSegregationCodes = sanitizeInput(segregationCodes);
+ log.debug(
+ String.format(
+ LOG_BASE_HEADER_INFO,
+ "GET",
+ "getOrganizationReceipts",
+ "organizationFiscalCode="
+ + sanitizeInput(organizationFiscalCode)
+ + "; debtor= "
+ + sanitizeInput(debtor)
+ + "; service= "
+ + sanitizeInput(service)
+ + "; validSegregationCodes= "
+ + sanitizedSegregationCodes));
- ArrayList segCodesList = segregationCodes != null ? new ArrayList<>(Arrays.asList(segregationCodes.split(","))) : null;
- PaymentsResult receipts = paymentsService
- .getOrganizationReceipts(organizationFiscalCode, debtor, service, from, to, pageNum, pageSize, segCodesList, debtorOrIuv);
+ ArrayList segCodesList =
+ segregationCodes != null
+ ? new ArrayList<>(Arrays.asList(segregationCodes.split(",")))
+ : null;
+ PaymentsResult receipts =
+ paymentsService.getOrganizationReceipts(
+ organizationFiscalCode,
+ debtor,
+ service,
+ from,
+ to,
+ pageNum,
+ pageSize,
+ segCodesList,
+ debtorOrIuv);
return new ResponseEntity<>(receipts, HttpStatus.OK);
}
}
diff --git a/src/main/java/it/gov/pagopa/payments/endpoints/PartnerEndpoint.java b/src/main/java/it/gov/pagopa/payments/endpoints/PartnerEndpoint.java
index 67d299db..6b239b7b 100644
--- a/src/main/java/it/gov/pagopa/payments/endpoints/PartnerEndpoint.java
+++ b/src/main/java/it/gov/pagopa/payments/endpoints/PartnerEndpoint.java
@@ -20,6 +20,7 @@
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
+
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
diff --git a/src/main/java/it/gov/pagopa/payments/entity/ReceiptEntity.java b/src/main/java/it/gov/pagopa/payments/entity/ReceiptEntity.java
index 4e2af9c0..cda021af 100644
--- a/src/main/java/it/gov/pagopa/payments/entity/ReceiptEntity.java
+++ b/src/main/java/it/gov/pagopa/payments/entity/ReceiptEntity.java
@@ -1,9 +1,6 @@
package it.gov.pagopa.payments.entity;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
+import lombok.*;
@Data
@NoArgsConstructor
diff --git a/src/main/java/it/gov/pagopa/payments/model/PaymentsModelResponse.java b/src/main/java/it/gov/pagopa/payments/model/PaymentsModelResponse.java
index d31092a0..eed7956d 100644
--- a/src/main/java/it/gov/pagopa/payments/model/PaymentsModelResponse.java
+++ b/src/main/java/it/gov/pagopa/payments/model/PaymentsModelResponse.java
@@ -3,6 +3,7 @@
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
+
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@@ -33,6 +34,7 @@ public class PaymentsModelResponse implements Serializable {
private PaymentOptionStatus status;
private Type type;
private String fiscalCode;
+ @ToString.Exclude
private String fullName;
private String streetName;
private String civicNumber;
@@ -41,7 +43,9 @@ public class PaymentsModelResponse implements Serializable {
private String province;
private String region;
private String country;
+ @ToString.Exclude
private String email;
+ @ToString.Exclude
private String phone;
private String companyName;
private String officeName;
diff --git a/src/main/java/it/gov/pagopa/payments/model/ReceiptModelResponse.java b/src/main/java/it/gov/pagopa/payments/model/ReceiptModelResponse.java
index 8b33e44a..c03f5931 100644
--- a/src/main/java/it/gov/pagopa/payments/model/ReceiptModelResponse.java
+++ b/src/main/java/it/gov/pagopa/payments/model/ReceiptModelResponse.java
@@ -3,6 +3,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import lombok.ToString;
import lombok.experimental.SuperBuilder;
@Getter
diff --git a/src/main/java/it/gov/pagopa/payments/model/spontaneous/DebtorModel.java b/src/main/java/it/gov/pagopa/payments/model/spontaneous/DebtorModel.java
index 70fd2d5a..1d5cb739 100644
--- a/src/main/java/it/gov/pagopa/payments/model/spontaneous/DebtorModel.java
+++ b/src/main/java/it/gov/pagopa/payments/model/spontaneous/DebtorModel.java
@@ -5,11 +5,8 @@
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+
+import lombok.*;
@Data
@NoArgsConstructor
@@ -24,6 +21,7 @@ public class DebtorModel implements Serializable {
private String fiscalCode;
@NotBlank(message = "full name is required")
+ @ToString.Exclude
private String fullName;
private String streetName;
@@ -41,7 +39,9 @@ public class DebtorModel implements Serializable {
private String country;
@Email(message = "Please provide a valid email address")
+ @ToString.Exclude
private String email;
+ @ToString.Exclude
private String phone;
}
diff --git a/src/main/java/it/gov/pagopa/payments/model/spontaneous/PaymentPositionModel.java b/src/main/java/it/gov/pagopa/payments/model/spontaneous/PaymentPositionModel.java
index 4d7da320..766f95cd 100644
--- a/src/main/java/it/gov/pagopa/payments/model/spontaneous/PaymentPositionModel.java
+++ b/src/main/java/it/gov/pagopa/payments/model/spontaneous/PaymentPositionModel.java
@@ -11,10 +11,8 @@
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+
+import lombok.*;
@Builder
@Data
@@ -32,6 +30,7 @@ public class PaymentPositionModel implements Serializable {
private String fiscalCode;
@NotBlank(message = "full name is required")
+ @ToString.Exclude
private String fullName;
private String streetName;
@@ -49,8 +48,10 @@ public class PaymentPositionModel implements Serializable {
private String country;
@Email(message = "Please provide a valid email address")
+ @ToString.Exclude
private String email;
+ @ToString.Exclude
private String phone;
@Schema(
diff --git a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
index fed08bfb..2eac6301 100644
--- a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -1,7 +1,9 @@
package it.gov.pagopa.payments.scheduler;
import it.gov.pagopa.payments.service.SchedulerService;
+import it.gov.pagopa.payments.utils.SchedulerUtils;
import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Async;
@@ -12,6 +14,8 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+import static it.gov.pagopa.payments.utils.SchedulerUtils.*;
+
@Component
@Slf4j
@EnableScheduling
@@ -28,9 +32,21 @@ public class Scheduler {
@Scheduled(cron = "${cron.job.schedule.expression.retry.trigger}")
@Async
public void retryPaSendRT() {
- log.info(String.format(LOG_BASE_HEADER_INFO, CRON_JOB, "retry sendRT", "Running at " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now())));
- schedulerService.retryFailedPaSendRT();
- this.threadOfExecution = Thread.currentThread();
+ try {
+ updateMDCForStartExecution("retryPaSendRT", "");
+ log.debug(String.format(LOG_BASE_HEADER_INFO, CRON_JOB, "retry sendRT", "Running at " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now())));
+ schedulerService.retryFailedPaSendRT();
+ this.threadOfExecution = Thread.currentThread();
+ updateMDCForEndExecution();
+ }
+ catch (Exception e){
+ updateMDCError(e, "retryPaSendRT");
+ throw e;
+ }
+ finally {
+ MDC.clear();
+ }
+
}
public Thread getThreadOfExecution() {
diff --git a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
index 25a46add..cabf8487 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -16,37 +16,33 @@
import it.gov.pagopa.payments.mapper.ConvertTableEntityToReceiptEntity;
import it.gov.pagopa.payments.model.*;
import it.gov.pagopa.payments.model.partner.*;
-import it.gov.pagopa.payments.model.partner.CtEntityUniqueIdentifier;
-import it.gov.pagopa.payments.model.partner.CtPaymentOptionDescriptionPA;
-import it.gov.pagopa.payments.model.partner.CtPaymentOptionsDescriptionListPA;
-import it.gov.pagopa.payments.model.partner.CtPaymentPA;
-import it.gov.pagopa.payments.model.partner.CtPaymentPAV2;
-import it.gov.pagopa.payments.model.partner.CtQrCode;
-import it.gov.pagopa.payments.model.partner.CtRichiestaMarcaDaBollo;
-import it.gov.pagopa.payments.model.partner.CtSubject;
-import it.gov.pagopa.payments.model.partner.CtTransferListPA;
-import it.gov.pagopa.payments.model.partner.CtTransferListPAV2;
-import it.gov.pagopa.payments.model.partner.CtTransferPA;
-import it.gov.pagopa.payments.model.partner.CtTransferPAV2;
-import it.gov.pagopa.payments.model.partner.PaDemandPaymentNoticeRequest;
-import it.gov.pagopa.payments.model.partner.PaDemandPaymentNoticeResponse;
-import it.gov.pagopa.payments.model.partner.PaGetPaymentReq;
-import it.gov.pagopa.payments.model.partner.PaGetPaymentRes;
-import it.gov.pagopa.payments.model.partner.PaGetPaymentV2Request;
-import it.gov.pagopa.payments.model.partner.PaGetPaymentV2Response;
-import it.gov.pagopa.payments.model.partner.PaSendRTReq;
-import it.gov.pagopa.payments.model.partner.PaSendRTRes;
-import it.gov.pagopa.payments.model.partner.PaSendRTV2Request;
-import it.gov.pagopa.payments.model.partner.PaSendRTV2Response;
-import it.gov.pagopa.payments.model.partner.PaVerifyPaymentNoticeRes;
-import it.gov.pagopa.payments.model.partner.StAmountOption;
-import it.gov.pagopa.payments.model.partner.StEntityUniqueIdentifierType;
-import it.gov.pagopa.payments.model.partner.StOutcome;
-import it.gov.pagopa.payments.model.partner.StTransferType;
import it.gov.pagopa.payments.model.spontaneous.*;
import it.gov.pagopa.payments.utils.CommonUtil;
import it.gov.pagopa.payments.utils.CustomizedMapper;
import it.gov.pagopa.payments.utils.Validator;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.xml.sax.SAXException;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeConstants;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
@@ -58,25 +54,6 @@
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import javax.xml.bind.*;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.datatype.DatatypeConstants;
-import javax.xml.datatype.DatatypeFactory;
-import javax.xml.datatype.XMLGregorianCalendar;
-import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.stream.XMLStreamException;
-import lombok.AllArgsConstructor;
-import lombok.NoArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.io.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.xml.sax.SAXException;
@Service
@Slf4j
@@ -84,930 +61,935 @@
@AllArgsConstructor
public class PartnerService {
- private static final String DEBT_POSITION_STATUS_ERROR =
- "[Check DP] Debt position status error: ";
- public static final String TEXT_XML_NODE = "#text";
+ private static final String DEBT_POSITION_STATUS_ERROR =
+ "[Check DP] Debt position status error: ";
+ public static final String TEXT_XML_NODE = "#text";
+
+ public static final String DEBTOR_PROPERTY = "debtor";
+
+ public static final String DOCUMENT_PROPERTY = "document";
+
+ public static final String STATUS_PROPERTY = "status";
+
+ public static final String PAYMENT_DATE_PROPERTY = "paymentDate";
+
+ public static final String IBAN_APPOGGIO_KEY = "IBANAPPOGGIO";
+
+ @Value(value = "${xsd.generic-service}")
+ private Resource xsdGenericService;
+
+ @Value(value = "${azure.queue.send.invisibilityTime}")
+ private Long queueSendInvisibilityTime;
+
+ @Autowired
+ private ObjectFactory factory;
+
+ @Autowired
+ private GpdClient gpdClient;
+
+ @Autowired
+ private GpsClient gpsClient;
+
+ @Autowired
+ private TableClient tableClient;
+
+ @Autowired
+ private QueueClient queueClient;
+
+ @Autowired
+ private CustomizedMapper customizedModelMapper;
+
+ private static final String DBERROR = "Error in organization table connection";
+
+ @Transactional(readOnly = true)
+ public PaVerifyPaymentNoticeRes paVerifyPaymentNotice(PaVerifyPaymentNoticeReq request)
+ throws DatatypeConfigurationException, PartnerValidationException {
+
+ log.debug(
+ "[paVerifyPaymentNotice] get payment option [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber());
+ PaymentsModelResponse paymentOption = null;
+
+ try {
+ paymentOption =
+ gpdClient.getPaymentOption(request.getIdPA(), request.getQrCode().getNoticeNumber());
+ } catch (FeignException.NotFound e) {
+ log.error(
+ "[paVerifyPaymentNotice] GPD Error not found [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
+ } catch (Exception e) {
+ log.error(
+ "[paVerifyPaymentNotice] GPD Generic Error [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+
+ checkDebtPositionStatus(paymentOption);
+
+ PaVerifyPaymentNoticeRes result;
+ log.debug("[paVerifyPaymentNotice] Response OK generation [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber());
+ try {
+ result = this.generatePaVerifyPaymentNoticeResponse(paymentOption);
+ } catch (Exception e) {
+ log.error("[paVerifyPaymentNotice] paymentOption {}", paymentOption, e);
+ throw e;
+ }
+ return result;
+ }
+
+ @Transactional(readOnly = true)
+ public PaGetPaymentRes paGetPayment(PaGetPaymentReq request)
+ throws DatatypeConfigurationException, PartnerValidationException {
+ log.debug(
+ "[paGetPayment] method call [noticeNumber={}]", request.getQrCode().getNoticeNumber());
+ PaymentsModelResponse paymentOption =
+ this.manageGetPaymentRequest(request.getIdPA(), request.getQrCode());
+ log.debug(
+ "[paGetPayment] Response OK generation [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber());
+ return this.generatePaGetPaymentResponse(paymentOption, request);
+ }
+
+ @Transactional(readOnly = true)
+ public PaGetPaymentV2Response paGetPaymentV2(PaGetPaymentV2Request request)
+ throws DatatypeConfigurationException, PartnerValidationException {
+ log.debug(
+ "[paGetPaymentV2] method call [noticeNumber={}]", request.getQrCode().getNoticeNumber());
+ PaymentsModelResponse paymentOption =
+ this.manageGetPaymentRequest(request.getIdPA(), request.getQrCode());
+ log.debug(
+ "[paGetPaymentV2] Response OK generation [noticeNumber={}]",
+ request.getQrCode().getNoticeNumber());
+ return this.generatePaGetPaymentResponse(paymentOption, request);
+ }
- public static final String DEBTOR_PROPERTY = "debtor";
+ @Transactional
+ public PaSendRTRes paSendRT(PaSendRTReq request) {
- public static final String DOCUMENT_PROPERTY = "document";
+ PaymentOptionModelResponse paymentOption = managePaSendRtRequest(request);
- public static final String STATUS_PROPERTY = "status";
+ if (!PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
+ log.error(
+ "[paSendRT] Payment Option [statusError: {}] [noticeNumber={}]",
+ paymentOption.getStatus(),
+ request.getReceipt().getNoticeNumber());
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ }
+
+ log.debug(
+ "[paSendRT] Generate Response [noticeNumber={}]", request.getReceipt().getNoticeNumber());
+ // status is always equals to PO_PAID
+ return generatePaSendRTResponse();
+ }
+
+ @Transactional
+ public PaSendRTV2Response paSendRTV2(PaSendRTV2Request request) {
+
+ PaymentOptionModelResponse paymentOption = managePaSendRtRequest(request);
+
+ if (!PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
+ log.error(
+ "[paSendRTV2] Payment Option [statusError: {}] [noticeNumber={}]",
+ paymentOption.getStatus(),
+ request.getReceipt().getNoticeNumber());
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ }
+
+ log.debug(
+ "[paSendRTV2] Generate Response [noticeNumber={}]", request.getReceipt().getNoticeNumber());
+ // status is always equals to PO_PAID
+ return generatePaSendRTV2Response();
+ }
- public static final String PAYMENT_DATE_PROPERTY = "paymentDate";
-
- public static final String IBAN_APPOGGIO_KEY = "IBANAPPOGGIO";
+ @Transactional
+ public PaDemandPaymentNoticeResponse paDemandPaymentNotice(PaDemandPaymentNoticeRequest request)
+ throws DatatypeConfigurationException, ParserConfigurationException, IOException,
+ SAXException, XMLStreamException {
+
+ List attributes = mapDatiSpecificiServizio(request);
+
+ SpontaneousPaymentModel spontaneousPayment =
+ SpontaneousPaymentModel.builder()
+ .service(
+ ServiceModel.builder().id(request.getIdServizio()).properties(attributes).build())
+ .debtor(
+ DebtorModel.builder() // TODO: take the info from the request
+ .type(Type.F)
+ .fiscalCode("ANONIMO")
+ .fullName("ANONIMO")
+ .build())
+ .build();
+
+ PaymentPositionModel gpsResponse;
+ try {
+ log.debug("[paDemandPaymentNotice] call GPS");
+ gpsResponse = gpsClient.createSpontaneousPayments(request.getIdPA(), spontaneousPayment);
+ } catch (FeignException.NotFound e) {
+ log.error("[paDemandPaymentNotice] GPS Error not found", e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
+ } catch (Exception e) {
+ log.error("[paDemandPaymentNotice] GPS Generic Error", e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+ return createPaDemandPaymentNoticeResponse(gpsResponse);
+ }
- @Value(value = "${xsd.generic-service}")
- private Resource xsdGenericService;
+ private List mapDatiSpecificiServizio(PaDemandPaymentNoticeRequest request)
+ throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
+ CommonUtil.syntacticValidationXml(
+ request.getDatiSpecificiServizioRequest(), xsdGenericService.getFile());
+
+ // parse XML into Document
+ DocumentBuilderFactory xmlFactory = DocumentBuilderFactory.newInstance();
+ xmlFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ DocumentBuilder builder = xmlFactory.newDocumentBuilder();
+ var document =
+ builder.parse(new ByteArrayInputStream(request.getDatiSpecificiServizioRequest()));
+
+ // map XML tags into list of ServicePropertyModel
+ var nodes = document.getElementsByTagName("service").item(0).getChildNodes();
+ List attributes = new ArrayList<>(nodes.getLength());
+ for (int i = 0; i < nodes.getLength(); i++) {
+ var node = nodes.item(i);
+ if (!TEXT_XML_NODE.equals(node.getNodeName())) {
+ var name = node.getNodeName();
+ var value = node.getTextContent();
+ attributes.add(ServicePropertyModel.builder().name(name).value(value).build());
+ }
+ }
+ return attributes;
+ }
- @Value(value = "${azure.queue.send.invisibilityTime}")
- private Long queueSendInvisibilityTime;
+ private PaDemandPaymentNoticeResponse createPaDemandPaymentNoticeResponse(
+ PaymentPositionModel gpsResponse) throws DatatypeConfigurationException {
+ var result = factory.createPaDemandPaymentNoticeResponse();
+ result.setOutcome(StOutcome.OK);
+ result.setFiscalCodePA(gpsResponse.getFiscalCode());
+
+ CtQrCode ctQrCode = factory.createCtQrCode();
+ ctQrCode.setFiscalCode(gpsResponse.getFiscalCode());
+ ctQrCode.setNoticeNumber(gpsResponse.getPaymentOption().get(0).getIuv());
+ result.setQrCode(ctQrCode);
+
+ result.setCompanyName(Validator.validateCompanyName(gpsResponse.getCompanyName()));
+ result.setOfficeName(Validator.validateOfficeName(gpsResponse.getOfficeName()));
+ result.setPaymentDescription(
+ Validator.validatePaymentOptionDescription(
+ gpsResponse.getPaymentOption().get(0).getDescription()));
+ CtPaymentOptionsDescriptionListPA ctPaymentOptionsDescriptionListPA =
+ factory.createCtPaymentOptionsDescriptionListPA();
+
+ CtPaymentOptionDescriptionPA ctPaymentOptionDescriptionPA =
+ factory.createCtPaymentOptionDescriptionPA();
+
+ var ccp =
+ gpsResponse
+ .getPaymentOption()
+ .get(0)
+ .getTransfer()
+ .stream()
+ .noneMatch(elem -> elem.getPostalIban() == null || elem.getPostalIban().isBlank());
+ ctPaymentOptionDescriptionPA.setAllCCP(ccp);
+
+ ctPaymentOptionDescriptionPA.setAmount(
+ BigDecimal.valueOf(gpsResponse.getPaymentOption().get(0).getAmount()));
+
+ var date = gpsResponse.getPaymentOption().get(0).getDueDate();
+ ctPaymentOptionDescriptionPA.setDueDate(
+ DatatypeFactory.newInstance().newXMLGregorianCalendar(String.valueOf(date)));
+
+ ctPaymentOptionDescriptionPA.setOptions(StAmountOption.EQ);
+ ctPaymentOptionDescriptionPA.setDetailDescription(
+ Validator.validatePaymentOptionDescription(
+ gpsResponse.getPaymentOption().get(0).getDescription()));
+ ctPaymentOptionsDescriptionListPA.setPaymentOptionDescription(ctPaymentOptionDescriptionPA);
+ result.setPaymentList(ctPaymentOptionsDescriptionListPA);
+ return result;
+ }
- @Autowired private ObjectFactory factory;
+ /**
+ * Verify debt position status
+ *
+ * @param paymentOption {@link PaymentsModelResponse} response from GPD
+ */
+ private void checkDebtPositionStatus(PaymentsModelResponse paymentOption) {
+ String iuvLog = " [iuv=" + paymentOption.getIuv() + ", nav=" + paymentOption.getNav() + "]";
+ if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.EXPIRED)) {
+ log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCADUTO);
+ } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.INVALID)) {
+ log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_ANNULLATO);
+ } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.DRAFT)
+ || paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.PUBLISHED)) {
+ log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
+ } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.PAID)
+ || paymentOption.getStatus().equals(PaymentOptionStatus.PO_PAID)
+ || paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.REPORTED)) {
+ log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_DUPLICATO);
+ }
+ }
- @Autowired private GpdClient gpdClient;
+ /**
+ * map the response of GPD in the XML model
+ *
+ * @param source {@link PaymentsModelResponse} response from GPD
+ * @param request SOAP input model
+ * @return XML model
+ * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
+ * instantiated.
+ */
+ private PaGetPaymentRes generatePaGetPaymentResponse(
+ PaymentsModelResponse source, PaGetPaymentReq request) throws DatatypeConfigurationException {
+
+ PaGetPaymentRes response = factory.createPaGetPaymentRes();
+ CtPaymentPA responseData = factory.createCtPaymentPA();
+ CtTransferListPA transferList = factory.createCtTransferListPA();
+
+ response.setOutcome(StOutcome.OK);
+
+ // general payment data
+ responseData.setCreditorReferenceId(source.getIuv());
+ responseData.setPaymentAmount(BigDecimal.valueOf(source.getAmount()));
+
+ DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
+ XMLGregorianCalendar dueDateXMLGregorian =
+ datatypeFactory.newXMLGregorianCalendar(
+ CommonUtil.convertToGregorianCalendar(source.getDueDate()));
+ responseData.setDueDate(dueDateXMLGregorian);
+
+ if (source.getRetentionDate() != null) {
+ XMLGregorianCalendar retentionDateXMLGregorian =
+ datatypeFactory.newXMLGregorianCalendar(
+ CommonUtil.convertToGregorianCalendar(source.getRetentionDate()));
+ retentionDateXMLGregorian.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
+ responseData.setRetentionDate(retentionDateXMLGregorian);
+ }
- @Autowired private GpsClient gpsClient;
+ responseData.setLastPayment(false); // de-scoping
+ responseData.setDescription(
+ Validator.validatePaymentOptionDescription(source.getDescription()));
+ responseData.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
+ responseData.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
- @Autowired private TableClient tableClient;
+ CtSubject debtor = this.getDebtor(source);
+ responseData.setDebtor(debtor);
- @Autowired private QueueClient queueClient;
+ // Transfer list
+ transferList
+ .getTransfer()
+ .addAll(
+ source
+ .getTransfer()
+ .stream()
+ .map(
+ paymentsTransferModelResponse ->
+ getTransferResponse(
+ paymentsTransferModelResponse, request.getTransferType()))
+ .collect(Collectors.toList()));
+
+ responseData.setTransferList(transferList);
+ response.setData(responseData);
+
+ return response;
+ }
- @Autowired private CustomizedMapper customizedModelMapper;
+ /**
+ * map the response of GPD in the XML V2 model
+ *
+ * @param source {@link PaymentsModelResponse} response from GPD
+ * @param request SOAP input model
+ * @return XML model
+ * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
+ * instantiated.
+ */
+ private PaGetPaymentV2Response generatePaGetPaymentResponse(
+ PaymentsModelResponse source, PaGetPaymentV2Request request)
+ throws DatatypeConfigurationException {
+
+ PaGetPaymentV2Response response = factory.createPaGetPaymentV2Response();
+ CtPaymentPAV2 responseData = factory.createCtPaymentPAV2();
+ CtTransferListPAV2 transferList = factory.createCtTransferListPAV2();
+
+ response.setOutcome(StOutcome.OK);
+
+ // general payment data
+ responseData.setCreditorReferenceId(source.getIuv());
+ responseData.setPaymentAmount(BigDecimal.valueOf(source.getAmount()));
+
+ DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
+ XMLGregorianCalendar dueDateXMLGregorian =
+ datatypeFactory.newXMLGregorianCalendar(
+ CommonUtil.convertToGregorianCalendar(source.getDueDate()));
+ responseData.setDueDate(dueDateXMLGregorian);
+
+ if (source.getRetentionDate() != null) {
+ XMLGregorianCalendar retentionDateXMLGregorian =
+ datatypeFactory.newXMLGregorianCalendar(
+ CommonUtil.convertToGregorianCalendar(source.getRetentionDate()));
+ retentionDateXMLGregorian.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
+ responseData.setRetentionDate(retentionDateXMLGregorian);
+ }
- private static final String DBERROR = "Error in organization table connection";
+ responseData.setLastPayment(false); // de-scoping
+ responseData.setDescription(
+ Validator.validatePaymentOptionDescription(source.getDescription()));
+ responseData.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
+ responseData.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
+
+ List paymentOptionMetadataModels =
+ source.getPaymentOptionMetadata();
+ if (paymentOptionMetadataModels != null && !paymentOptionMetadataModels.isEmpty()) {
+ CtMetadata paymentOptionMetadata = factory.createCtMetadata();
+ List poMapEntry = paymentOptionMetadata.getMapEntry();
+ for (PaymentOptionMetadataModel po : paymentOptionMetadataModels) {
+ poMapEntry.add(getPaymentOptionMetadata(po));
+ }
+ responseData.setMetadata(paymentOptionMetadata);
+ }
- @Transactional(readOnly = true)
- public PaVerifyPaymentNoticeRes paVerifyPaymentNotice(PaVerifyPaymentNoticeReq request)
- throws DatatypeConfigurationException, PartnerValidationException {
+ // debtor data
+ CtSubject debtor = this.getDebtor(source);
- log.debug(
- "[paVerifyPaymentNotice] get payment option [noticeNumber={}]",
- request.getQrCode().getNoticeNumber());
- PaymentsModelResponse paymentOption = null;
-
- try {
- paymentOption =
- gpdClient.getPaymentOption(request.getIdPA(), request.getQrCode().getNoticeNumber());
- } catch (FeignException.NotFound e) {
- log.error(
- "[paVerifyPaymentNotice] GPD Error not found [noticeNumber={}]",
- request.getQrCode().getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
- } catch (Exception e) {
- log.error(
- "[paVerifyPaymentNotice] GPD Generic Error [noticeNumber={}]",
- request.getQrCode().getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
-
- checkDebtPositionStatus(paymentOption);
-
- PaVerifyPaymentNoticeRes result;
- log.info(
- "[paVerifyPaymentNotice] Response OK generation [noticeNumber={}]",
- request.getQrCode().getNoticeNumber());
- try {
- result = this.generatePaVerifyPaymentNoticeResponse(paymentOption);
- } catch (Exception e) {
- log.error("[paVerifyPaymentNotice] paymentOption {}", paymentOption, e);
- throw e;
- }
- return result;
- }
-
- @Transactional(readOnly = true)
- public PaGetPaymentRes paGetPayment(PaGetPaymentReq request)
- throws DatatypeConfigurationException, PartnerValidationException {
- log.debug(
- "[paGetPayment] method call [noticeNumber={}]", request.getQrCode().getNoticeNumber());
- PaymentsModelResponse paymentOption =
- this.manageGetPaymentRequest(request.getIdPA(), request.getQrCode());
- log.info(
- "[paGetPayment] Response OK generation [noticeNumber={}]",
- request.getQrCode().getNoticeNumber());
- return this.generatePaGetPaymentResponse(paymentOption, request);
- }
-
- @Transactional(readOnly = true)
- public PaGetPaymentV2Response paGetPaymentV2(PaGetPaymentV2Request request)
- throws DatatypeConfigurationException, PartnerValidationException {
- log.debug(
- "[paGetPaymentV2] method call [noticeNumber={}]", request.getQrCode().getNoticeNumber());
- PaymentsModelResponse paymentOption =
- this.manageGetPaymentRequest(request.getIdPA(), request.getQrCode());
- log.info(
- "[paGetPaymentV2] Response OK generation [noticeNumber={}]",
- request.getQrCode().getNoticeNumber());
- return this.generatePaGetPaymentResponse(paymentOption, request);
- }
-
- @Transactional
- public PaSendRTRes paSendRT(PaSendRTReq request) {
-
- PaymentOptionModelResponse paymentOption = managePaSendRtRequest(request);
-
- if (!PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
- log.error(
- "[paSendRT] Payment Option [statusError: {}] [noticeNumber={}]",
- paymentOption.getStatus(),
- request.getReceipt().getNoticeNumber());
- throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
- }
-
- log.info(
- "[paSendRT] Generate Response [noticeNumber={}]", request.getReceipt().getNoticeNumber());
- // status is always equals to PO_PAID
- return generatePaSendRTResponse();
- }
-
- @Transactional
- public PaSendRTV2Response paSendRTV2(PaSendRTV2Request request) {
-
- PaymentOptionModelResponse paymentOption = managePaSendRtRequest(request);
-
- if (!PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
- log.error(
- "[paSendRTV2] Payment Option [statusError: {}] [noticeNumber={}]",
- paymentOption.getStatus(),
- request.getReceipt().getNoticeNumber());
- throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
- }
-
- log.info(
- "[paSendRTV2] Generate Response [noticeNumber={}]", request.getReceipt().getNoticeNumber());
- // status is always equals to PO_PAID
- return generatePaSendRTV2Response();
- }
-
- @Transactional
- public PaDemandPaymentNoticeResponse paDemandPaymentNotice(PaDemandPaymentNoticeRequest request)
- throws DatatypeConfigurationException, ParserConfigurationException, IOException,
- SAXException, XMLStreamException {
-
- List attributes = mapDatiSpecificiServizio(request);
-
- SpontaneousPaymentModel spontaneousPayment =
- SpontaneousPaymentModel.builder()
- .service(
- ServiceModel.builder().id(request.getIdServizio()).properties(attributes).build())
- .debtor(
- DebtorModel.builder() // TODO: take the info from the request
- .type(Type.F)
- .fiscalCode("ANONIMO")
- .fullName("ANONIMO")
- .build())
- .build();
-
- PaymentPositionModel gpsResponse;
- try {
- log.debug("[paDemandPaymentNotice] call GPS");
- gpsResponse = gpsClient.createSpontaneousPayments(request.getIdPA(), spontaneousPayment);
- } catch (FeignException.NotFound e) {
- log.error("[paDemandPaymentNotice] GPS Error not found", e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
- } catch (Exception e) {
- log.error("[paDemandPaymentNotice] GPS Generic Error", e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
- return createPaDemandPaymentNoticeResponse(gpsResponse);
- }
-
- private List mapDatiSpecificiServizio(PaDemandPaymentNoticeRequest request)
- throws ParserConfigurationException, SAXException, IOException, XMLStreamException {
- CommonUtil.syntacticValidationXml(
- request.getDatiSpecificiServizioRequest(), xsdGenericService.getFile());
-
- // parse XML into Document
- DocumentBuilderFactory xmlFactory = DocumentBuilderFactory.newInstance();
- xmlFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
- DocumentBuilder builder = xmlFactory.newDocumentBuilder();
- var document =
- builder.parse(new ByteArrayInputStream(request.getDatiSpecificiServizioRequest()));
-
- // map XML tags into list of ServicePropertyModel
- var nodes = document.getElementsByTagName("service").item(0).getChildNodes();
- List attributes = new ArrayList<>(nodes.getLength());
- for (int i = 0; i < nodes.getLength(); i++) {
- var node = nodes.item(i);
- if (!TEXT_XML_NODE.equals(node.getNodeName())) {
- var name = node.getNodeName();
- var value = node.getTextContent();
- attributes.add(ServicePropertyModel.builder().name(name).value(value).build());
- }
- }
- return attributes;
- }
-
- private PaDemandPaymentNoticeResponse createPaDemandPaymentNoticeResponse(
- PaymentPositionModel gpsResponse) throws DatatypeConfigurationException {
- var result = factory.createPaDemandPaymentNoticeResponse();
- result.setOutcome(StOutcome.OK);
- result.setFiscalCodePA(gpsResponse.getFiscalCode());
-
- CtQrCode ctQrCode = factory.createCtQrCode();
- ctQrCode.setFiscalCode(gpsResponse.getFiscalCode());
- ctQrCode.setNoticeNumber(gpsResponse.getPaymentOption().get(0).getIuv());
- result.setQrCode(ctQrCode);
-
- result.setCompanyName(Validator.validateCompanyName(gpsResponse.getCompanyName()));
- result.setOfficeName(Validator.validateOfficeName(gpsResponse.getOfficeName()));
- result.setPaymentDescription(
- Validator.validatePaymentOptionDescription(
- gpsResponse.getPaymentOption().get(0).getDescription()));
- CtPaymentOptionsDescriptionListPA ctPaymentOptionsDescriptionListPA =
- factory.createCtPaymentOptionsDescriptionListPA();
-
- CtPaymentOptionDescriptionPA ctPaymentOptionDescriptionPA =
- factory.createCtPaymentOptionDescriptionPA();
-
- var ccp =
- gpsResponse
- .getPaymentOption()
- .get(0)
- .getTransfer()
- .stream()
- .noneMatch(elem -> elem.getPostalIban() == null || elem.getPostalIban().isBlank());
- ctPaymentOptionDescriptionPA.setAllCCP(ccp);
-
- ctPaymentOptionDescriptionPA.setAmount(
- BigDecimal.valueOf(gpsResponse.getPaymentOption().get(0).getAmount()));
-
- var date = gpsResponse.getPaymentOption().get(0).getDueDate();
- ctPaymentOptionDescriptionPA.setDueDate(
- DatatypeFactory.newInstance().newXMLGregorianCalendar(String.valueOf(date)));
-
- ctPaymentOptionDescriptionPA.setOptions(StAmountOption.EQ);
- ctPaymentOptionDescriptionPA.setDetailDescription(
- Validator.validatePaymentOptionDescription(
- gpsResponse.getPaymentOption().get(0).getDescription()));
- ctPaymentOptionsDescriptionListPA.setPaymentOptionDescription(ctPaymentOptionDescriptionPA);
- result.setPaymentList(ctPaymentOptionsDescriptionListPA);
- return result;
- }
-
- /**
- * Verify debt position status
- *
- * @param paymentOption {@link PaymentsModelResponse} response from GPD
- */
- private void checkDebtPositionStatus(PaymentsModelResponse paymentOption) {
- String iuvLog = " [iuv=" + paymentOption.getIuv() + ", nav=" + paymentOption.getNav() + "]";
- if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.EXPIRED)) {
- log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCADUTO);
- } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.INVALID)) {
- log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_ANNULLATO);
- } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.DRAFT)
- || paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.PUBLISHED)) {
- log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
- } else if (paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.PAID)
- || paymentOption.getStatus().equals(PaymentOptionStatus.PO_PAID)
- || paymentOption.getDebtPositionStatus().equals(DebtPositionStatus.REPORTED)) {
- log.error(DEBT_POSITION_STATUS_ERROR + paymentOption.getDebtPositionStatus() + iuvLog);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_DUPLICATO);
- }
- }
-
- /**
- * map the response of GPD in the XML model
- *
- * @param source {@link PaymentsModelResponse} response from GPD
- * @param request SOAP input model
- * @return XML model
- * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
- * instantiated.
- */
- private PaGetPaymentRes generatePaGetPaymentResponse(
- PaymentsModelResponse source, PaGetPaymentReq request) throws DatatypeConfigurationException {
-
- PaGetPaymentRes response = factory.createPaGetPaymentRes();
- CtPaymentPA responseData = factory.createCtPaymentPA();
- CtTransferListPA transferList = factory.createCtTransferListPA();
-
- response.setOutcome(StOutcome.OK);
-
- // general payment data
- responseData.setCreditorReferenceId(source.getIuv());
- responseData.setPaymentAmount(BigDecimal.valueOf(source.getAmount()));
-
- DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
- XMLGregorianCalendar dueDateXMLGregorian =
- datatypeFactory.newXMLGregorianCalendar(
- CommonUtil.convertToGregorianCalendar(source.getDueDate()));
- responseData.setDueDate(dueDateXMLGregorian);
-
- if (source.getRetentionDate() != null) {
- XMLGregorianCalendar retentionDateXMLGregorian =
- datatypeFactory.newXMLGregorianCalendar(
- CommonUtil.convertToGregorianCalendar(source.getRetentionDate()));
- retentionDateXMLGregorian.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
- responseData.setRetentionDate(retentionDateXMLGregorian);
- }
-
- responseData.setLastPayment(false); // de-scoping
- responseData.setDescription(
- Validator.validatePaymentOptionDescription(source.getDescription()));
- responseData.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
- responseData.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
-
- CtSubject debtor = this.getDebtor(source);
- responseData.setDebtor(debtor);
-
- // Transfer list
- transferList
- .getTransfer()
- .addAll(
- source
+ // Transfer list
+ transferList
.getTransfer()
- .stream()
- .map(
- paymentsTransferModelResponse ->
- getTransferResponse(
- paymentsTransferModelResponse, request.getTransferType()))
- .collect(Collectors.toList()));
-
- responseData.setTransferList(transferList);
- response.setData(responseData);
-
- return response;
- }
-
- /**
- * map the response of GPD in the XML V2 model
- *
- * @param source {@link PaymentsModelResponse} response from GPD
- * @param request SOAP input model
- * @return XML model
- * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
- * instantiated.
- */
- private PaGetPaymentV2Response generatePaGetPaymentResponse(
- PaymentsModelResponse source, PaGetPaymentV2Request request)
- throws DatatypeConfigurationException {
-
- PaGetPaymentV2Response response = factory.createPaGetPaymentV2Response();
- CtPaymentPAV2 responseData = factory.createCtPaymentPAV2();
- CtTransferListPAV2 transferList = factory.createCtTransferListPAV2();
-
- response.setOutcome(StOutcome.OK);
-
- // general payment data
- responseData.setCreditorReferenceId(source.getIuv());
- responseData.setPaymentAmount(BigDecimal.valueOf(source.getAmount()));
-
- DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
- XMLGregorianCalendar dueDateXMLGregorian =
- datatypeFactory.newXMLGregorianCalendar(
- CommonUtil.convertToGregorianCalendar(source.getDueDate()));
- responseData.setDueDate(dueDateXMLGregorian);
-
- if (source.getRetentionDate() != null) {
- XMLGregorianCalendar retentionDateXMLGregorian =
- datatypeFactory.newXMLGregorianCalendar(
- CommonUtil.convertToGregorianCalendar(source.getRetentionDate()));
- retentionDateXMLGregorian.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
- responseData.setRetentionDate(retentionDateXMLGregorian);
- }
-
- responseData.setLastPayment(false); // de-scoping
- responseData.setDescription(
- Validator.validatePaymentOptionDescription(source.getDescription()));
- responseData.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
- responseData.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
-
- List paymentOptionMetadataModels =
- source.getPaymentOptionMetadata();
- if (paymentOptionMetadataModels != null && !paymentOptionMetadataModels.isEmpty()) {
- CtMetadata paymentOptionMetadata = factory.createCtMetadata();
- List poMapEntry = paymentOptionMetadata.getMapEntry();
- for (PaymentOptionMetadataModel po : paymentOptionMetadataModels) {
- poMapEntry.add(getPaymentOptionMetadata(po));
- }
- responseData.setMetadata(paymentOptionMetadata);
- }
-
- // debtor data
- CtSubject debtor = this.getDebtor(source);
-
- // Transfer list
- transferList
- .getTransfer()
- .addAll(
+ .addAll(
+ source
+ .getTransfer()
+ .stream()
+ .map(
+ paymentsTransferModelResponse ->
+ getTransferResponseV2(
+ paymentsTransferModelResponse, request.getTransferType())).toList());
+
+ responseData.setTransferList(transferList);
+ responseData.setDebtor(debtor);
+ response.setData(responseData);
+
+ return response;
+ }
+
+ /**
+ * map the response of GPD in the XML model
+ *
+ * @param source {@link PaymentsModelResponse} response from GPD
+ * @return XML model
+ * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
+ * instantiated.
+ */
+ private PaVerifyPaymentNoticeRes generatePaVerifyPaymentNoticeResponse(
+ PaymentsModelResponse source) throws DatatypeConfigurationException {
+
+ PaVerifyPaymentNoticeRes result = factory.createPaVerifyPaymentNoticeRes();
+ CtPaymentOptionsDescriptionListPA paymentList =
+ factory.createCtPaymentOptionsDescriptionListPA();
+ CtPaymentOptionDescriptionPA paymentOption = factory.createCtPaymentOptionDescriptionPA();
+ // generare una paVerifyPaymentNoticeRes positiva
+ result.setOutcome(StOutcome.OK);
+ // paymentList
+ paymentOption.setAmount(BigDecimal.valueOf(source.getAmount()));
+ paymentOption.setOptions(StAmountOption.EQ); // de-scoping
+ paymentOption.setDueDate(
+ DatatypeFactory.newInstance()
+ .newXMLGregorianCalendar(CommonUtil.convertToGregorianCalendar(source.getDueDate())));
+ paymentOption.setDetailDescription(
+ Validator.validatePaymentOptionDescription(source.getDescription()));
+ var cpp =
source
.getTransfer()
.stream()
- .map(
- paymentsTransferModelResponse ->
- getTransferResponseV2(
- paymentsTransferModelResponse, request.getTransferType())).toList());
-
- responseData.setTransferList(transferList);
- responseData.setDebtor(debtor);
- response.setData(responseData);
-
- return response;
- }
-
- /**
- * map the response of GPD in the XML model
- *
- * @param source {@link PaymentsModelResponse} response from GPD
- * @return XML model
- * @throws DatatypeConfigurationException If the DatatypeFactory is not available or cannot be
- * instantiated.
- */
- private PaVerifyPaymentNoticeRes generatePaVerifyPaymentNoticeResponse(
- PaymentsModelResponse source) throws DatatypeConfigurationException {
-
- PaVerifyPaymentNoticeRes result = factory.createPaVerifyPaymentNoticeRes();
- CtPaymentOptionsDescriptionListPA paymentList =
- factory.createCtPaymentOptionsDescriptionListPA();
- CtPaymentOptionDescriptionPA paymentOption = factory.createCtPaymentOptionDescriptionPA();
- // generare una paVerifyPaymentNoticeRes positiva
- result.setOutcome(StOutcome.OK);
- // paymentList
- paymentOption.setAmount(BigDecimal.valueOf(source.getAmount()));
- paymentOption.setOptions(StAmountOption.EQ); // de-scoping
- paymentOption.setDueDate(
- DatatypeFactory.newInstance()
- .newXMLGregorianCalendar(CommonUtil.convertToGregorianCalendar(source.getDueDate())));
- paymentOption.setDetailDescription(
- Validator.validatePaymentOptionDescription(source.getDescription()));
- var cpp =
- source
- .getTransfer()
- .stream()
- .noneMatch(elem -> elem.getPostalIban() == null || elem.getPostalIban().isBlank());
- paymentOption.setAllCCP(cpp); // allCPP fa parte del modello del option
- paymentList.setPaymentOptionDescription(paymentOption);
-
- result.setPaymentList(paymentList);
- // general info
- result.setFiscalCodePA(source.getOrganizationFiscalCode());
- result.setPaymentDescription(
- Validator.validatePaymentOptionDescription(source.getDescription()));
- result.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
- result.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
- return result;
- }
-
- /**
- * @param transfer GPD response
- * @param transferType XML request
- * @return maps input into {@link CtTransferPA} model
- */
- private CtTransferPA getTransferResponse(
- PaymentsTransferModelResponse transfer, StTransferType transferType) {
- CtTransferPA transferPA = new CtTransferPA();
- transferPA.setFiscalCodePA(transfer.getOrganizationFiscalCode());
- transferPA.setIBAN(getIbanByTransferType(transferType, transfer));
- transferPA.setIdTransfer(Integer.parseInt(transfer.getIdTransfer()));
- transferPA.setRemittanceInformation(transfer.getRemittanceInformation());
- transferPA.setTransferAmount(BigDecimal.valueOf(transfer.getAmount()));
- transferPA.setTransferCategory(transfer.getCategory());
-
- return transferPA;
- }
-
- /**
- * @param transfer GPD response
- * @param transferType V2 XML request
- * @return maps input into {@link CtTransferPA} model
- */
- private CtTransferPAV2 getTransferResponseV2(
- PaymentsTransferModelResponse transfer, StTransferType transferType) {
- Stamp stamp = transfer.getStamp();
- CtRichiestaMarcaDaBollo richiestaMarcaDaBollo = null;
-
- if (stamp != null
- && stamp.getHashDocument() != null
- && stamp.getStampType() != null
- && stamp.getProvincialResidence() != null)
- richiestaMarcaDaBollo = customizedModelMapper.map(stamp, CtRichiestaMarcaDaBollo.class);
-
- CtTransferPAV2 transferPA = new CtTransferPAV2();
- transferPA.setFiscalCodePA(transfer.getOrganizationFiscalCode());
- transferPA.setCompanyName(" "); // stText140(1, 140) todo: to be filled in with the correct company name for the PO Nth transfer
- transferPA.setRichiestaMarcaDaBollo(richiestaMarcaDaBollo);
- transferPA.setIdTransfer(Integer.parseInt(transfer.getIdTransfer()));
- transferPA.setRemittanceInformation(transfer.getRemittanceInformation());
- transferPA.setTransferAmount(BigDecimal.valueOf(transfer.getAmount()));
- transferPA.setTransferCategory(transfer.getCategory());
-
- List transferMetadataModels = transfer.getTransferMetadata();
- if (transferMetadataModels != null && !transferMetadataModels.isEmpty()) {
- CtMetadata ctMetadata = new CtMetadata();
- List transferMapEntry = ctMetadata.getMapEntry();
- for (TransferMetadataModel transferMetadataModel : transferMetadataModels) {
- transferMapEntry.add(getTransferMetadata(transferMetadataModel));
- }
- transferPA.setMetadata(ctMetadata);
- }
-
- // PagoPA-1624: only two cases PAGOPA or POSTAL
- if (transferType != null && transferType.value().equals(StTransferType.PAGOPA.value())) {
- Optional.ofNullable(transfer.getPostalIban())
- .ifPresent(value -> createIbanAppoggioMetadata(transferPA, value));
- transferPA.setIBAN(transfer.getIban());
- } else {
- transferPA.setIBAN(getIbanByTransferType(transferType, transfer));
- }
-
- return transferPA;
- }
-
- private CtMapEntry getPaymentOptionMetadata(PaymentOptionMetadataModel metadataModel) {
- CtMapEntry ctMapEntry = new CtMapEntry();
- ctMapEntry.setKey(metadataModel.getKey());
- ctMapEntry.setValue(metadataModel.getValue());
- return ctMapEntry;
- }
-
- private CtMapEntry getTransferMetadata(TransferMetadataModel metadataModel) {
- CtMapEntry ctMapEntry = new CtMapEntry();
- ctMapEntry.setKey(metadataModel.getKey());
- ctMapEntry.setValue(metadataModel.getValue());
- return ctMapEntry;
- }
-
- /**
- * The method return iban given transferType and transfer, according to
- * https://pagopa.atlassian.net/wiki/spaces/PAG/pages/96403906/paGetPayment#trasferType
- */
- private String getIbanByTransferType(
- StTransferType transferType, PaymentsTransferModelResponse transfer) {
-
- String defaultIban =
- Optional.ofNullable(transfer.getIban())
- .orElseGet(() -> Optional.ofNullable(transfer.getPostalIban()).orElseGet(() -> null));
-
- return transferType != null
- && transferType.value().equals(StTransferType.POSTAL.value())
- && transfer.getPostalIban() != null
- ? transfer.getPostalIban()
- : defaultIban;
- }
-
- private void createIbanAppoggioMetadata(CtTransferPAV2 transferPA, String value) {
- CtMapEntry mapEntry = new CtMapEntry();
- mapEntry.setKey(IBAN_APPOGGIO_KEY);
- mapEntry.setValue(value);
- CtMetadata ctMetadata = Optional.ofNullable(transferPA.getMetadata()).orElse(new CtMetadata());
- ctMetadata.getMapEntry().add(mapEntry);
- transferPA.setMetadata(ctMetadata);
- }
-
- private PaSendRTRes generatePaSendRTResponse() {
- PaSendRTRes result = factory.createPaSendRTRes();
- result.setOutcome(StOutcome.OK);
- return result;
- }
-
- private PaSendRTV2Response generatePaSendRTV2Response() {
- PaSendRTV2Response result = factory.createPaSendRTV2Response();
- result.setOutcome(StOutcome.OK);
- return result;
- }
-
- private String marshal(PaSendRTReq paSendRTReq) throws JAXBException {
- StringWriter sw = new StringWriter();
- JAXBContext context = JAXBContext.newInstance(PaSendRTReq.class);
- Marshaller mar = context.createMarshaller();
- mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
- JAXBElement jaxbElement =
- new JAXBElement<>(new QName("", "paSendRTReq"), PaSendRTReq.class, paSendRTReq);
- mar.marshal(jaxbElement, sw);
- return sw.toString();
- }
-
- private String marshalV2(PaSendRTV2Request paSendRTV2Request) throws JAXBException {
- StringWriter sw = new StringWriter();
- JAXBContext context = JAXBContext.newInstance(PaSendRTV2Request.class);
- Marshaller mar = context.createMarshaller();
- mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
- JAXBElement jaxbElement =
- new JAXBElement<>(
- new QName("", "PaSendRTV2Request"), PaSendRTV2Request.class, paSendRTV2Request);
- mar.marshal(jaxbElement, sw);
- return sw.toString();
- }
-
- private void saveReceipt(ReceiptEntity receiptEntity)
- throws InvalidKeyException, URISyntaxException, StorageException {
- try {
- TableEntity tableEntity =
- new TableEntity(receiptEntity.getOrganizationFiscalCode(), receiptEntity.getIuv());
- Map properties = new HashMap<>();
- properties.put(DEBTOR_PROPERTY, receiptEntity.getDebtor());
- properties.put(DOCUMENT_PROPERTY, receiptEntity.getDocument());
- properties.put(STATUS_PROPERTY, receiptEntity.getStatus());
- properties.put(PAYMENT_DATE_PROPERTY, receiptEntity.getPaymentDateTime());
- tableEntity.setProperties(properties);
- tableClient.createEntity(tableEntity);
- } catch (TableServiceException e) {
- log.error(DBERROR, e);
- if (e.getValue().getErrorCode() == TableErrorCode.ENTITY_ALREADY_EXISTS) {
- throw new PartnerValidationException(PaaErrorEnum.PAA_RECEIPT_DUPLICATA);
- }
- throw new AppException(AppError.DB_ERROR);
- }
- }
-
- private ReceiptEntity getReceipt(String organizationFiscalCode, String iuv)
- throws InvalidKeyException, URISyntaxException, StorageException {
- try {
- TableEntity tableEntity = tableClient.getEntity(organizationFiscalCode, iuv);
- return ConvertTableEntityToReceiptEntity.mapTableEntityToReceiptEntity(tableEntity);
- } catch (TableServiceException e) {
- log.error(DBERROR, e);
- if (e.getValue().getErrorCode() == TableErrorCode.RESOURCE_NOT_FOUND) return null;
- else throw new AppException(AppError.DB_ERROR);
- }
- }
-
- public long getFeeInCent(BigDecimal fee) {
- long feeInCent = 0;
- if (null != fee) {
- feeInCent = fee.multiply(BigDecimal.valueOf(100)).longValue();
- }
- return feeInCent;
- }
-
- private CtSubject getDebtor(PaymentsModelResponse source) {
-
- CtEntityUniqueIdentifier uniqueIdentifier = factory.createCtEntityUniqueIdentifier();
- CtSubject debtor = factory.createCtSubject();
-
- uniqueIdentifier.setEntityUniqueIdentifierType(
- StEntityUniqueIdentifierType.fromValue(source.getType().name()));
- uniqueIdentifier.setEntityUniqueIdentifierValue(source.getFiscalCode());
-
- debtor.setUniqueIdentifier(uniqueIdentifier);
- debtor.setFullName(source.getFullName());
- // optional fields --> before the set it is checked that the field is not null and not empty
- Optional.ofNullable(source.getStreetName())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setStreetName);
- Optional.ofNullable(source.getCivicNumber())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setCivicNumber);
- Optional.ofNullable(source.getPostalCode())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setPostalCode);
- Optional.ofNullable(source.getCity())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setCity);
- Optional.ofNullable(source.getProvince())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setStateProvinceRegion);
- Optional.ofNullable(source.getCountry())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setCountry);
- Optional.ofNullable(source.getEmail())
- .filter(Predicate.not(String::isEmpty))
- .ifPresent(debtor::setEMail);
-
- return debtor;
- }
-
- private PaymentsModelResponse manageGetPaymentRequest(String idPa, CtQrCode qrCode) {
-
- log.debug(
- "[manageGetPaymentRequest] get payment option [noticeNumber={}]", qrCode.getNoticeNumber());
- PaymentsModelResponse paymentOption = null;
-
- try {
- paymentOption = gpdClient.getPaymentOption(idPa, qrCode.getNoticeNumber());
- } catch (FeignException.NotFound e) {
- log.error(
- "[manageGetPaymentRequest] GPD Error not found [noticeNumber={}]",
- qrCode.getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
- } catch (Exception e) {
- log.error(
- "[manageGetPaymentRequest] GPD Generic Error [noticeNumber={}]",
- qrCode.getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
- checkDebtPositionStatus(paymentOption);
- return paymentOption;
- }
-
- private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
- log.debug(
- "[managePaSendRtRequest] save receipt [noticeNumber={}]",
- request.getReceipt().getNoticeNumber());
-
- String debtorIdentifier =
- Optional.ofNullable(request.getReceipt().getDebtor())
- .map(CtSubject::getUniqueIdentifier)
- .map(CtEntityUniqueIdentifier::getEntityUniqueIdentifierValue)
- .orElse("");
- ReceiptEntity receiptEntity =
- this.getReceiptEntity(
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- debtorIdentifier,
- request.getReceipt().getPaymentDateTime().toString());
-
- try {
- receiptEntity.setDocument(this.marshal(request));
- } catch (JAXBException e) {
- log.error(
- "[managePaSendRtRequest] Error in receipt marshalling [noticeNumber={}]",
- request.getReceipt().getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
-
- LocalDateTime paymentDateTime =
- request.getReceipt().getPaymentDateTime() != null
- ? request
- .getReceipt()
- .getPaymentDateTime()
- .toGregorianCalendar()
- .toZonedDateTime()
- .toLocalDateTime()
- : null;
- PaymentOptionModel body =
- PaymentOptionModel.builder()
- .idReceipt(request.getReceipt().getReceiptId())
- .paymentDate(paymentDateTime)
- .pspCompany(request.getReceipt().getPSPCompanyName())
- .paymentMethod(request.getReceipt().getPaymentMethod())
- .fee(String.valueOf(this.getFeeInCent(request.getReceipt().getFee())))
- .build();
-
- return this.getReceiptExceptionHandling(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- body,
- receiptEntity);
- }
-
- private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request request) {
- log.debug(
- "[managePaSendRtRequest] save V2 receipt [noticeNumber={}]",
- request.getReceipt().getNoticeNumber());
-
- String debtorIdentifier =
- Optional.ofNullable(request.getReceipt().getDebtor())
- .map(CtSubject::getUniqueIdentifier)
- .map(CtEntityUniqueIdentifier::getEntityUniqueIdentifierValue)
- .orElse("");
- ReceiptEntity receiptEntity =
- this.getReceiptEntity(
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- debtorIdentifier,
- request.getReceipt().getPaymentDateTime().toString());
- try {
- receiptEntity.setDocument(this.marshalV2(request));
- } catch (JAXBException e) {
- log.error(
- "[managePaSendRtRequest] Error in receipt marshalling [noticeNumber={}]",
- request.getReceipt().getNoticeNumber(),
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
-
- LocalDateTime paymentDateTime =
- request.getReceipt().getPaymentDateTime() != null
- ? request
- .getReceipt()
- .getPaymentDateTime()
- .toGregorianCalendar()
- .toZonedDateTime()
- .toLocalDateTime()
- : null;
-
- PaymentOptionModel body =
- PaymentOptionModel.builder()
- .idReceipt(request.getReceipt().getReceiptId())
- .paymentDate(paymentDateTime)
- .pspCompany(request.getReceipt().getPSPCompanyName())
- .paymentMethod(request.getReceipt().getPaymentMethod())
- .fee(String.valueOf(this.getFeeInCent(request.getReceipt().getFee())))
- .build();
-
- return this.getReceiptExceptionHandling(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- body,
- receiptEntity);
- }
-
- private PaymentOptionModelResponse getReceiptExceptionHandling(
- String noticeNumber,
- String idPa,
- String creditorReferenceId,
- PaymentOptionModel body,
- ReceiptEntity receiptEntity) {
- try {
- return this.getReceiptPaymentOption(
- noticeNumber, idPa, creditorReferenceId, body, receiptEntity);
- } catch (RetryableException e) {
- log.error(
- "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: GPD Not Reachable [noticeNumber={}]",
- noticeNumber,
- e);
- queueClient.sendMessageWithResponse(
- receiptEntity.getDocument(),
- Duration.ofSeconds(queueSendInvisibilityTime),
- null,
- null,
- Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- } catch (FeignException e) {
- log.error(
- "[getReceiptPaymentOption] PAA_SEMANTICA: GPD Error Response [noticeNumber={}]",
- noticeNumber,
- e);
- queueClient.sendMessageWithResponse(
- receiptEntity.getDocument(),
- Duration.ofSeconds(queueSendInvisibilityTime),
- null,
- null,
- Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
- } catch (StorageException e) {
- log.error(
- "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: Storage exception [noticeNumber={}]",
- noticeNumber,
- e);
- queueClient.sendMessageWithResponse(
- receiptEntity.getDocument(),
- Duration.ofSeconds(queueSendInvisibilityTime),
- null,
- null,
- Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- } catch (PartnerValidationException e) {
- // { PAA_RECEIPT_DUPLICATA, PAA_PAGAMENTO_SCONOSCIUTO }
- throw e;
- } catch (Exception e) {
- // no retry because the long-term retry is enabled only when there is a gpd-core error
- // response or a storage communication failure
- log.error(
- "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: GPD Generic Error [noticeNumber={}]",
- noticeNumber,
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
- }
-
- private ReceiptEntity getReceiptEntity(
- String idPa, String creditorReferenceId, String debtor, String paymentDateTime) {
- ReceiptEntity receiptEntity = new ReceiptEntity(idPa, creditorReferenceId);
- receiptEntity.setDebtor(debtor);
- String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
- receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
- return receiptEntity;
- }
-
- private PaymentOptionModelResponse getReceiptPaymentOption(
- String noticeNumber,
- String idPa,
- String creditorReferenceId,
- PaymentOptionModel body,
- ReceiptEntity receiptEntity)
- throws FeignException, URISyntaxException, InvalidKeyException, StorageException {
- PaymentOptionModelResponse paymentOption = new PaymentOptionModelResponse();
- try {
- paymentOption = gpdClient.receiptPaymentOption(idPa, noticeNumber, body);
- // creates the PAID receipt
- if (PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
- this.saveReceipt(receiptEntity);
- }
- } catch (FeignException.Conflict e) {
- // if PO is already paid on GPD --> checks and in case creates the receipt in PAID status
- try {
- log.error(
- "[getReceiptPaymentOption] PAA_RECEIPT_DUPLICATA: GPD Conflict Error Response [noticeNumber={}]",
- noticeNumber,
- e);
- ReceiptEntity receiptEntityToCreate = this.getReceipt(idPa, creditorReferenceId);
- if (null == receiptEntityToCreate) {
- // if no receipt found --> save the with PAID receipt
- this.saveReceipt(receiptEntity);
+ .noneMatch(elem -> elem.getPostalIban() == null || elem.getPostalIban().isBlank());
+ paymentOption.setAllCCP(cpp); // allCPP fa parte del modello del option
+ paymentList.setPaymentOptionDescription(paymentOption);
+
+ result.setPaymentList(paymentList);
+ // general info
+ result.setFiscalCodePA(source.getOrganizationFiscalCode());
+ result.setPaymentDescription(
+ Validator.validatePaymentOptionDescription(source.getDescription()));
+ result.setCompanyName(Validator.validateCompanyName(source.getCompanyName()));
+ result.setOfficeName(Validator.validateOfficeName(source.getOfficeName()));
+ return result;
+ }
+
+ /**
+ * @param transfer GPD response
+ * @param transferType XML request
+ * @return maps input into {@link CtTransferPA} model
+ */
+ private CtTransferPA getTransferResponse(
+ PaymentsTransferModelResponse transfer, StTransferType transferType) {
+ CtTransferPA transferPA = new CtTransferPA();
+ transferPA.setFiscalCodePA(transfer.getOrganizationFiscalCode());
+ transferPA.setIBAN(getIbanByTransferType(transferType, transfer));
+ transferPA.setIdTransfer(Integer.parseInt(transfer.getIdTransfer()));
+ transferPA.setRemittanceInformation(transfer.getRemittanceInformation());
+ transferPA.setTransferAmount(BigDecimal.valueOf(transfer.getAmount()));
+ transferPA.setTransferCategory(transfer.getCategory());
+
+ return transferPA;
+ }
+
+ /**
+ * @param transfer GPD response
+ * @param transferType V2 XML request
+ * @return maps input into {@link CtTransferPA} model
+ */
+ private CtTransferPAV2 getTransferResponseV2(
+ PaymentsTransferModelResponse transfer, StTransferType transferType) {
+ Stamp stamp = transfer.getStamp();
+ CtRichiestaMarcaDaBollo richiestaMarcaDaBollo = null;
+
+ if (stamp != null
+ && stamp.getHashDocument() != null
+ && stamp.getStampType() != null
+ && stamp.getProvincialResidence() != null)
+ richiestaMarcaDaBollo = customizedModelMapper.map(stamp, CtRichiestaMarcaDaBollo.class);
+
+ CtTransferPAV2 transferPA = new CtTransferPAV2();
+ transferPA.setFiscalCodePA(transfer.getOrganizationFiscalCode());
+ transferPA.setCompanyName(" "); // stText140(1, 140) todo: to be filled in with the correct company name for the PO Nth transfer
+ transferPA.setRichiestaMarcaDaBollo(richiestaMarcaDaBollo);
+ transferPA.setIdTransfer(Integer.parseInt(transfer.getIdTransfer()));
+ transferPA.setRemittanceInformation(transfer.getRemittanceInformation());
+ transferPA.setTransferAmount(BigDecimal.valueOf(transfer.getAmount()));
+ transferPA.setTransferCategory(transfer.getCategory());
+
+ List transferMetadataModels = transfer.getTransferMetadata();
+ if (transferMetadataModels != null && !transferMetadataModels.isEmpty()) {
+ CtMetadata ctMetadata = new CtMetadata();
+ List transferMapEntry = ctMetadata.getMapEntry();
+ for (TransferMetadataModel transferMetadataModel : transferMetadataModels) {
+ transferMapEntry.add(getTransferMetadata(transferMetadataModel));
+ }
+ transferPA.setMetadata(ctMetadata);
+ }
+
+ // PagoPA-1624: only two cases PAGOPA or POSTAL
+ if (transferType != null && transferType.value().equals(StTransferType.PAGOPA.value())) {
+ Optional.ofNullable(transfer.getPostalIban())
+ .ifPresent(value -> createIbanAppoggioMetadata(transferPA, value));
+ transferPA.setIBAN(transfer.getIban());
+ } else {
+ transferPA.setIBAN(getIbanByTransferType(transferType, transfer));
+ }
+
+ return transferPA;
+ }
+
+ private CtMapEntry getPaymentOptionMetadata(PaymentOptionMetadataModel metadataModel) {
+ CtMapEntry ctMapEntry = new CtMapEntry();
+ ctMapEntry.setKey(metadataModel.getKey());
+ ctMapEntry.setValue(metadataModel.getValue());
+ return ctMapEntry;
+ }
+
+ private CtMapEntry getTransferMetadata(TransferMetadataModel metadataModel) {
+ CtMapEntry ctMapEntry = new CtMapEntry();
+ ctMapEntry.setKey(metadataModel.getKey());
+ ctMapEntry.setValue(metadataModel.getValue());
+ return ctMapEntry;
+ }
+
+ /**
+ * The method return iban given transferType and transfer, according to
+ * https://pagopa.atlassian.net/wiki/spaces/PAG/pages/96403906/paGetPayment#trasferType
+ */
+ private String getIbanByTransferType(
+ StTransferType transferType, PaymentsTransferModelResponse transfer) {
+
+ String defaultIban =
+ Optional.ofNullable(transfer.getIban())
+ .orElseGet(() -> Optional.ofNullable(transfer.getPostalIban()).orElseGet(() -> null));
+
+ return transferType != null
+ && transferType.value().equals(StTransferType.POSTAL.value())
+ && transfer.getPostalIban() != null
+ ? transfer.getPostalIban()
+ : defaultIban;
+ }
+
+ private void createIbanAppoggioMetadata(CtTransferPAV2 transferPA, String value) {
+ CtMapEntry mapEntry = new CtMapEntry();
+ mapEntry.setKey(IBAN_APPOGGIO_KEY);
+ mapEntry.setValue(value);
+ CtMetadata ctMetadata = Optional.ofNullable(transferPA.getMetadata()).orElse(new CtMetadata());
+ ctMetadata.getMapEntry().add(mapEntry);
+ transferPA.setMetadata(ctMetadata);
+ }
+
+ private PaSendRTRes generatePaSendRTResponse() {
+ PaSendRTRes result = factory.createPaSendRTRes();
+ result.setOutcome(StOutcome.OK);
+ return result;
+ }
+
+ private PaSendRTV2Response generatePaSendRTV2Response() {
+ PaSendRTV2Response result = factory.createPaSendRTV2Response();
+ result.setOutcome(StOutcome.OK);
+ return result;
+ }
+
+ private String marshal(PaSendRTReq paSendRTReq) throws JAXBException {
+ StringWriter sw = new StringWriter();
+ JAXBContext context = JAXBContext.newInstance(PaSendRTReq.class);
+ Marshaller mar = context.createMarshaller();
+ mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ JAXBElement jaxbElement =
+ new JAXBElement<>(new QName("", "paSendRTReq"), PaSendRTReq.class, paSendRTReq);
+ mar.marshal(jaxbElement, sw);
+ return sw.toString();
+ }
+
+ private String marshalV2(PaSendRTV2Request paSendRTV2Request) throws JAXBException {
+ StringWriter sw = new StringWriter();
+ JAXBContext context = JAXBContext.newInstance(PaSendRTV2Request.class);
+ Marshaller mar = context.createMarshaller();
+ mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ JAXBElement jaxbElement =
+ new JAXBElement<>(
+ new QName("", "PaSendRTV2Request"), PaSendRTV2Request.class, paSendRTV2Request);
+ mar.marshal(jaxbElement, sw);
+ return sw.toString();
+ }
+
+ private void saveReceipt(ReceiptEntity receiptEntity)
+ throws InvalidKeyException, URISyntaxException, StorageException {
+ try {
+ TableEntity tableEntity =
+ new TableEntity(receiptEntity.getOrganizationFiscalCode(), receiptEntity.getIuv());
+ Map properties = new HashMap<>();
+ properties.put(DEBTOR_PROPERTY, receiptEntity.getDebtor());
+ properties.put(DOCUMENT_PROPERTY, receiptEntity.getDocument());
+ properties.put(STATUS_PROPERTY, receiptEntity.getStatus());
+ properties.put(PAYMENT_DATE_PROPERTY, receiptEntity.getPaymentDateTime());
+ tableEntity.setProperties(properties);
+ tableClient.createEntity(tableEntity);
+ } catch (TableServiceException e) {
+ log.error(DBERROR, e);
+ if (e.getValue().getErrorCode() == TableErrorCode.ENTITY_ALREADY_EXISTS) {
+ throw new PartnerValidationException(PaaErrorEnum.PAA_RECEIPT_DUPLICATA);
+ }
+ throw new AppException(AppError.DB_ERROR);
+ }
+ }
+
+ private ReceiptEntity getReceipt(String organizationFiscalCode, String iuv)
+ throws InvalidKeyException, URISyntaxException, StorageException {
+ try {
+ TableEntity tableEntity = tableClient.getEntity(organizationFiscalCode, iuv);
+ return ConvertTableEntityToReceiptEntity.mapTableEntityToReceiptEntity(tableEntity);
+ } catch (TableServiceException e) {
+ log.error(DBERROR, e);
+ if (e.getValue().getErrorCode() == TableErrorCode.RESOURCE_NOT_FOUND) return null;
+ else throw new AppException(AppError.DB_ERROR);
+ }
+ }
+
+ public long getFeeInCent(BigDecimal fee) {
+ long feeInCent = 0;
+ if (null != fee) {
+ feeInCent = fee.multiply(BigDecimal.valueOf(100)).longValue();
+ }
+ return feeInCent;
+ }
+
+ private CtSubject getDebtor(PaymentsModelResponse source) {
+
+ CtEntityUniqueIdentifier uniqueIdentifier = factory.createCtEntityUniqueIdentifier();
+ CtSubject debtor = factory.createCtSubject();
+
+ uniqueIdentifier.setEntityUniqueIdentifierType(
+ StEntityUniqueIdentifierType.fromValue(source.getType().name()));
+ uniqueIdentifier.setEntityUniqueIdentifierValue(source.getFiscalCode());
+
+ debtor.setUniqueIdentifier(uniqueIdentifier);
+ debtor.setFullName(source.getFullName());
+ // optional fields --> before the set it is checked that the field is not null and not empty
+ Optional.ofNullable(source.getStreetName())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setStreetName);
+ Optional.ofNullable(source.getCivicNumber())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setCivicNumber);
+ Optional.ofNullable(source.getPostalCode())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setPostalCode);
+ Optional.ofNullable(source.getCity())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setCity);
+ Optional.ofNullable(source.getProvince())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setStateProvinceRegion);
+ Optional.ofNullable(source.getCountry())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setCountry);
+ Optional.ofNullable(source.getEmail())
+ .filter(Predicate.not(String::isEmpty))
+ .ifPresent(debtor::setEMail);
+
+ return debtor;
+ }
+
+ private PaymentsModelResponse manageGetPaymentRequest(String idPa, CtQrCode qrCode) {
+
+ log.debug(
+ "[manageGetPaymentRequest] get payment option [noticeNumber={}]", qrCode.getNoticeNumber());
+ PaymentsModelResponse paymentOption = null;
+
+ try {
+ paymentOption = gpdClient.getPaymentOption(idPa, qrCode.getNoticeNumber());
+ } catch (FeignException.NotFound e) {
+ log.error(
+ "[manageGetPaymentRequest] GPD Error not found [noticeNumber={}]",
+ qrCode.getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
+ } catch (Exception e) {
+ log.error(
+ "[manageGetPaymentRequest] GPD Generic Error [noticeNumber={}]",
+ qrCode.getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+ checkDebtPositionStatus(paymentOption);
+ return paymentOption;
+ }
+
+ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
+ log.debug(
+ "[managePaSendRtRequest] save receipt [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber());
+
+ String debtorIdentifier =
+ Optional.ofNullable(request.getReceipt().getDebtor())
+ .map(CtSubject::getUniqueIdentifier)
+ .map(CtEntityUniqueIdentifier::getEntityUniqueIdentifierValue)
+ .orElse("");
+ ReceiptEntity receiptEntity =
+ this.getReceiptEntity(
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ debtorIdentifier,
+ request.getReceipt().getPaymentDateTime().toString());
+
+ try {
+ receiptEntity.setDocument(this.marshal(request));
+ } catch (JAXBException e) {
+ log.error(
+ "[managePaSendRtRequest] Error in receipt marshalling [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+
+ LocalDateTime paymentDateTime =
+ request.getReceipt().getPaymentDateTime() != null
+ ? request
+ .getReceipt()
+ .getPaymentDateTime()
+ .toGregorianCalendar()
+ .toZonedDateTime()
+ .toLocalDateTime()
+ : null;
+ PaymentOptionModel body =
+ PaymentOptionModel.builder()
+ .idReceipt(request.getReceipt().getReceiptId())
+ .paymentDate(paymentDateTime)
+ .pspCompany(request.getReceipt().getPSPCompanyName())
+ .paymentMethod(request.getReceipt().getPaymentMethod())
+ .fee(String.valueOf(this.getFeeInCent(request.getReceipt().getFee())))
+ .build();
+
+ return this.getReceiptExceptionHandling(
+ request.getReceipt().getNoticeNumber(),
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ body,
+ receiptEntity);
+ }
+
+ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request request) {
+ log.debug(
+ "[managePaSendRtRequest] save V2 receipt [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber());
+
+ String debtorIdentifier =
+ Optional.ofNullable(request.getReceipt().getDebtor())
+ .map(CtSubject::getUniqueIdentifier)
+ .map(CtEntityUniqueIdentifier::getEntityUniqueIdentifierValue)
+ .orElse("");
+ ReceiptEntity receiptEntity =
+ this.getReceiptEntity(
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ debtorIdentifier,
+ request.getReceipt().getPaymentDateTime().toString());
+ try {
+ receiptEntity.setDocument(this.marshalV2(request));
+ } catch (JAXBException e) {
+ log.error(
+ "[managePaSendRtRequest] Error in receipt marshalling [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber(),
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+
+ LocalDateTime paymentDateTime =
+ request.getReceipt().getPaymentDateTime() != null
+ ? request
+ .getReceipt()
+ .getPaymentDateTime()
+ .toGregorianCalendar()
+ .toZonedDateTime()
+ .toLocalDateTime()
+ : null;
+
+ PaymentOptionModel body =
+ PaymentOptionModel.builder()
+ .idReceipt(request.getReceipt().getReceiptId())
+ .paymentDate(paymentDateTime)
+ .pspCompany(request.getReceipt().getPSPCompanyName())
+ .paymentMethod(request.getReceipt().getPaymentMethod())
+ .fee(String.valueOf(this.getFeeInCent(request.getReceipt().getFee())))
+ .build();
+
+ return this.getReceiptExceptionHandling(
+ request.getReceipt().getNoticeNumber(),
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ body,
+ receiptEntity);
+ }
+
+ private PaymentOptionModelResponse getReceiptExceptionHandling(
+ String noticeNumber,
+ String idPa,
+ String creditorReferenceId,
+ PaymentOptionModel body,
+ ReceiptEntity receiptEntity) {
+ try {
+ return this.getReceiptPaymentOption(
+ noticeNumber, idPa, creditorReferenceId, body, receiptEntity);
+ } catch (RetryableException e) {
+ log.error(
+ "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: GPD Not Reachable [noticeNumber={}]",
+ noticeNumber,
+ e);
+ queueClient.sendMessageWithResponse(
+ receiptEntity.getDocument(),
+ Duration.ofSeconds(queueSendInvisibilityTime),
+ null,
+ null,
+ Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ } catch (FeignException e) {
+ log.error(
+ "[getReceiptPaymentOption] PAA_SEMANTICA: GPD Error Response [noticeNumber={}]",
+ noticeNumber,
+ e);
+ queueClient.sendMessageWithResponse(
+ receiptEntity.getDocument(),
+ Duration.ofSeconds(queueSendInvisibilityTime),
+ null,
+ null,
+ Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ } catch (StorageException e) {
+ log.error(
+ "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: Storage exception [noticeNumber={}]",
+ noticeNumber,
+ e);
+ queueClient.sendMessageWithResponse(
+ receiptEntity.getDocument(),
+ Duration.ofSeconds(queueSendInvisibilityTime),
+ null,
+ null,
+ Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ } catch (PartnerValidationException e) {
+ // { PAA_RECEIPT_DUPLICATA, PAA_PAGAMENTO_SCONOSCIUTO }
+ throw e;
+ } catch (Exception e) {
+ // no retry because the long-term retry is enabled only when there is a gpd-core error
+ // response or a storage communication failure
+ log.error(
+ "[getReceiptPaymentOption] PAA_SYSTEM_ERROR: GPD Generic Error [noticeNumber={}]",
+ noticeNumber,
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
}
- } catch (Exception ex) {
- log.error(
- "[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}] during receipt status"
- + " save",
- noticeNumber,
- e);
- }
- throw new PartnerValidationException(PaaErrorEnum.PAA_RECEIPT_DUPLICATA);
- } catch (FeignException.NotFound e) {
- log.error(
- "[getReceiptPaymentOption] PAA_PAGAMENTO_SCONOSCIUTO: GPD Not Found Error Response [noticeNumber={}]",
- noticeNumber,
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
- } catch (PartnerValidationException e) {
- throw e;
- }
- return paymentOption;
- }
-
- public PaymentOptionModelResponse getReceiptPaymentOptionScheduler(
- String noticeNumber,
- String idPa,
- String creditorReferenceId,
- PaymentOptionModel body,
- ReceiptEntity receiptEntity)
- throws FeignException, URISyntaxException, InvalidKeyException, StorageException {
- return getReceiptPaymentOption(noticeNumber, idPa, creditorReferenceId, body, receiptEntity);
- }
+ }
+
+ private ReceiptEntity getReceiptEntity(
+ String idPa, String creditorReferenceId, String debtor, String paymentDateTime) {
+ ReceiptEntity receiptEntity = new ReceiptEntity(idPa, creditorReferenceId);
+ receiptEntity.setDebtor(debtor);
+ String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
+ receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
+ return receiptEntity;
+ }
+
+ private PaymentOptionModelResponse getReceiptPaymentOption(
+ String noticeNumber,
+ String idPa,
+ String creditorReferenceId,
+ PaymentOptionModel body,
+ ReceiptEntity receiptEntity)
+ throws FeignException, URISyntaxException, InvalidKeyException, StorageException {
+ PaymentOptionModelResponse paymentOption = new PaymentOptionModelResponse();
+ try {
+ paymentOption = gpdClient.receiptPaymentOption(idPa, noticeNumber, body);
+ // creates the PAID receipt
+ if (PaymentOptionStatus.PO_PAID.equals(paymentOption.getStatus())) {
+ this.saveReceipt(receiptEntity);
+ }
+ } catch (FeignException.Conflict e) {
+ // if PO is already paid on GPD --> checks and in case creates the receipt in PAID status
+ try {
+ log.error(
+ "[getReceiptPaymentOption] PAA_RECEIPT_DUPLICATA: GPD Conflict Error Response [noticeNumber={}]",
+ noticeNumber,
+ e);
+ ReceiptEntity receiptEntityToCreate = this.getReceipt(idPa, creditorReferenceId);
+ if (null == receiptEntityToCreate) {
+ // if no receipt found --> save the with PAID receipt
+ this.saveReceipt(receiptEntity);
+ }
+ } catch (Exception ex) {
+ log.error(
+ "[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}] during receipt status"
+ + " save",
+ noticeNumber,
+ e);
+ }
+ throw new PartnerValidationException(PaaErrorEnum.PAA_RECEIPT_DUPLICATA);
+ } catch (FeignException.NotFound e) {
+ log.error(
+ "[getReceiptPaymentOption] PAA_PAGAMENTO_SCONOSCIUTO: GPD Not Found Error Response [noticeNumber={}]",
+ noticeNumber,
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
+ } catch (PartnerValidationException e) {
+ throw e;
+ }
+ return paymentOption;
+ }
+
+ public PaymentOptionModelResponse getReceiptPaymentOptionScheduler(
+ String noticeNumber,
+ String idPa,
+ String creditorReferenceId,
+ PaymentOptionModel body,
+ ReceiptEntity receiptEntity)
+ throws FeignException, URISyntaxException, InvalidKeyException, StorageException {
+ return getReceiptPaymentOption(noticeNumber, idPa, creditorReferenceId, body, receiptEntity);
+ }
}
diff --git a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
index cb8cfa75..09db0e25 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -128,7 +128,7 @@ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queue
receiptEntity);
queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
} catch (FeignException | URISyntaxException | InvalidKeyException | StorageException e) {
- log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
+ log.debug("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
queueClient.updateMessageWithResponse(
queueMessageItem.getMessageId(),
queueMessageItem.getPopReceipt(),
@@ -138,7 +138,7 @@ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queue
Context.NONE);
} catch (PartnerValidationException e) {
// { PAA_RECEIPT_DUPLICATA, PAA_PAGAMENTO_SCONOSCIUTO }
- log.info("[paSendRT] Retry failed {} [fiscalCode={},noticeNumber={}]\",\n", e.getMessage(), idPA, noticeNumber);
+ log.warn("[paSendRT] Retry failed {} [fiscalCode={},noticeNumber={}]\",\n", e.getMessage(), idPA, noticeNumber);
queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
}
}
diff --git a/src/main/java/it/gov/pagopa/payments/utils/CommonUtil.java b/src/main/java/it/gov/pagopa/payments/utils/CommonUtil.java
index b212af0b..145fb97d 100644
--- a/src/main/java/it/gov/pagopa/payments/utils/CommonUtil.java
+++ b/src/main/java/it/gov/pagopa/payments/utils/CommonUtil.java
@@ -7,6 +7,7 @@
import java.time.ZoneId;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.Optional;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
@@ -58,4 +59,12 @@ public static GregorianCalendar convertToGregorianCalendar(LocalDateTime dateToC
public static String sanitizeInput(String input) {
return input != null ? input.replace("\n", "").replaceAll("[^a-zA-Z0-9_\\-+/]", "") : "";
}
+
+ /**
+ * @param value value to deNullify.
+ * @return return empty string if value is null
+ */
+ public static String deNull(Object value) {
+ return Optional.ofNullable(value).orElse("").toString();
+ }
}
diff --git a/src/main/java/it/gov/pagopa/payments/utils/SchedulerUtils.java b/src/main/java/it/gov/pagopa/payments/utils/SchedulerUtils.java
new file mode 100644
index 00000000..a762e390
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/payments/utils/SchedulerUtils.java
@@ -0,0 +1,35 @@
+package it.gov.pagopa.payments.utils;
+
+import org.slf4j.MDC;
+
+import java.util.Calendar;
+import java.util.UUID;
+
+import static it.gov.pagopa.payments.config.LoggingAspect.*;
+
+
+public class SchedulerUtils {
+
+ public static void updateMDCForStartExecution(String method, String args) {
+ MDC.put(METHOD, method);
+ MDC.put(START_TIME, String.valueOf(Calendar.getInstance().getTimeInMillis()));
+ MDC.put(REQUEST_ID, UUID.randomUUID().toString());
+ MDC.put(OPERATION_ID, UUID.randomUUID().toString());
+ MDC.put(ARGS, args);
+ }
+
+ public static void updateMDCForEndExecution() {
+ MDC.put(STATUS, "OK");
+ MDC.put(CODE, "201");
+ MDC.put(RESPONSE_TIME, getExecutionTime());
+ }
+
+ public static void updateMDCError(Exception e, String method) {
+ MDC.put(STATUS, "KO");
+ MDC.put(CODE, "500");
+ MDC.put(RESPONSE_TIME, getExecutionTime());
+ MDC.put(FAULT_CODE, method);
+ MDC.put(FAULT_DETAIL, e.getMessage());
+ }
+
+}
diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties
index bf6cc453..1cd3d2d3 100644
--- a/src/main/resources/application-local.properties
+++ b/src/main/resources/application-local.properties
@@ -1,4 +1,4 @@
-properties.environment=local
+info.properties.environment=local
server.port=8081
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index f1c24da2..deaf7509 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,8 +1,8 @@
# info
-application.name=@project.artifactId@
-application.version=@project.version@
-application.description=@project.description@
-properties.environment=azure
+info.application.name=@project.artifactId@
+info.application.version=@project.version@
+info.application.description=@project.description@
+info.properties.environment=azure
# Actuator
management.endpoints.web.exposure.include=health,info
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
index e80650ed..2ada1a5e 100644
--- a/src/main/resources/logback-spring.xml
+++ b/src/main/resources/logback-spring.xml
@@ -1,17 +1,36 @@
+
-
-
-
+
+
+
+
-
-
-
- %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %clr(%mdc){magenta} %m%n%wEx
-
-
-
+
+
+
+ %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m %clr(%mdc){magenta}%n%wEx
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${OTEL_SERVICE_NAME}
+ ${ECS_SERVICE_VERSION}
+ ${ENV}
+
+
+
+
+
+
+
-
-
-
diff --git a/src/test/java/it/gov/pagopa/payments/api/PaymentsControllerTest.java b/src/test/java/it/gov/pagopa/payments/api/PaymentsControllerTest.java
index 0384b941..3b8aa9d1 100644
--- a/src/test/java/it/gov/pagopa/payments/api/PaymentsControllerTest.java
+++ b/src/test/java/it/gov/pagopa/payments/api/PaymentsControllerTest.java
@@ -129,9 +129,9 @@ void getOrganizationReceipts_200_SegregationCodes() throws Exception {
@Test
void getOrganizationReceipts_404() throws Exception {
// precondition
- doThrow(new AppException(AppError.RECEIPTS_NOT_FOUND, "111", 0))
- .when(paymentsService)
- .getOrganizationReceipts(anyString(), anyString(), anyString(), anyString(), anyString(), anyInt(), anyInt(), any(ArrayList.class), anyString());
+// doThrow(new AppException(AppError.RECEIPTS_NOT_FOUND, "111", 0))
+// .when(paymentsService)
+// .getOrganizationReceipts(anyString(), anyString(), anyString(), anyString(), anyString(), anyInt(), anyInt(), any(ArrayList.class), anyString());
try {
paymentsController.getOrganizationReceipts(
anyString(), anyInt(), anyInt(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString());
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index 5384fb34..cb214f6a 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -1,8 +1,8 @@
# info
-application.name=@project.artifactId@
-application.version=@project.version@
-application.description=@project.description@
-properties.environment=test
+info.application.name=@project.artifactId@
+info.application.version=@project.version@
+info.application.description=@project.description@
+info.properties.environment=test
pt.id_intermediario=77777777777
pt.id_stazione=77777777777_1