From df0163ad3f1cb36d1f323161b8a4e8d3e917e1e7 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Wed, 17 Apr 2024 17:25:49 +0200
Subject: [PATCH 01/24] PAGOPA-1695 wip
---
pom.xml | 5 +++
.../config/QueueClientConfiguration.java | 33 ++++++++++++++++
.../controller/scheduler/Scheduler.java | 28 ++++++++++++++
.../payments/service/PartnerService.java | 38 +++++++++++++++++--
4 files changed, 100 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
create mode 100644 src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java
diff --git a/pom.xml b/pom.xml
index a715bfce..d30282ef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -237,6 +237,11 @@
2.1.2
compile
+
+ com.azure
+ azure-storage-queue
+ 12.20.2
+
diff --git a/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
new file mode 100644
index 00000000..eba93462
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
@@ -0,0 +1,33 @@
+package it.gov.pagopa.payments.config;
+
+import com.azure.storage.queue.QueueClient;
+import com.azure.storage.queue.QueueClientBuilder;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class QueueClientConfiguration {
+
+ private static String QUEUE_NAME;
+
+ private static String CONNECTION_STRING;
+
+ @Value("${azure.queue.connection.string}")
+ public void setConnectionStringStatic(String connectionString) {
+ QueueClientConfiguration.CONNECTION_STRING = connectionString;
+ }
+
+ @Value("${azure.queue.queueName}")
+ public void setTableNameStatic(String queueName) {
+ QueueClientConfiguration.QUEUE_NAME = queueName;
+ }
+
+ @Bean
+ public QueueClient queueClientConfig(){
+ return new QueueClientBuilder()
+ .queueName(QUEUE_NAME)
+ .connectionString(CONNECTION_STRING)
+ .buildClient();
+ }
+}
diff --git a/src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java b/src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java
new file mode 100644
index 00000000..878d36f1
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java
@@ -0,0 +1,28 @@
+package it.gov.pagopa.payments.controller.scheduler;
+
+import it.gov.pagopa.payments.service.PartnerService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+@Slf4j
+@Validated
+public class Scheduler {
+
+ @Autowired
+ PartnerService partnerService;
+
+ @GetMapping(
+ value = "/scheduler",
+ produces = {MediaType.APPLICATION_JSON_VALUE})
+ public ResponseEntity getFailureReceipts() {
+ partnerService.getAllFailuresQueue();
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+}
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 9795d379..d8f8a188 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -4,6 +4,8 @@
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableErrorCode;
import com.azure.data.tables.models.TableServiceException;
+import com.azure.storage.queue.QueueClient;
+import com.azure.storage.queue.models.QueueMessageItem;
import com.microsoft.azure.storage.StorageException;
import feign.FeignException;
import feign.RetryableException;
@@ -49,15 +51,13 @@
import java.io.StringWriter;
import java.math.BigDecimal;
import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
+import javax.xml.bind.*;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
@@ -109,6 +109,8 @@ public class PartnerService {
@Autowired private TableClient tableClient;
+ @Autowired private QueueClient queueClient;
+
@Autowired private CustomizedMapper customizedModelMapper;
private static final String DBERROR = "Error in organization table connection";
@@ -905,14 +907,42 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
throw e;
} catch (RetryableException e) {
log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", noticeNumber, e);
+ queueClient.sendMessage(receiptEntity.getDocument());
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (FeignException e) {
log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", noticeNumber, e);
+ queueClient.sendMessage(receiptEntity.getDocument());
throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
} catch (Exception e) {
log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", noticeNumber, e);
+ queueClient.sendMessage(receiptEntity.getDocument());
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
}
return paymentOption;
}
+
+ public void getAllFailuresQueue() {
+ try {
+ QueueMessageItem queueMessageItem;
+ List failureBodies = new ArrayList<>();
+ Unmarshaller unmarshaller = JAXBContext.newInstance(PaSendRTV2Request.class).createUnmarshaller();
+ while ((queueMessageItem = queueClient.receiveMessage()) != null) {
+ failureBodies.add(getFailureQueue(queueMessageItem));
+ }
+ for (String failureBody : failureBodies) {
+ JAXBElement request = (JAXBElement) unmarshaller.unmarshal(new ByteArrayInputStream(failureBody.getBytes(StandardCharsets.UTF_8)));
+ paSendRTV2(request.getValue());
+ }
+ } catch (JAXBException e) {
+ log.error(
+ "[managePaSendRtRequest] Error in receipt unmarshalling in queue",
+ e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
+ }
+
+ public String getFailureQueue(QueueMessageItem queueMessageItem){
+ queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
+ return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
+ }
}
From 4b7da606ff52f56eb1e3b04adb14b88870f1dcd1 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Thu, 18 Apr 2024 14:43:54 +0200
Subject: [PATCH 02/24] PAGOPA-1695 wip handling xml
---
.../payments/service/PartnerService.java | 109 ++++++++++++++----
1 file changed, 86 insertions(+), 23 deletions(-)
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 d8f8a188..d050d567 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -48,6 +48,7 @@
import it.gov.pagopa.payments.utils.CustomizedMapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.StringReader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.net.URISyntaxException;
@@ -67,6 +68,8 @@
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
+import javax.xml.xpath.*;
+
import it.gov.pagopa.payments.utils.Validator;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@@ -76,6 +79,10 @@
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@Service
@@ -760,11 +767,16 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
"[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(),
- request.getReceipt().getDebtor(),
+ debtorIdentifier,
request.getReceipt().getPaymentDateTime().toString());
try {
@@ -808,11 +820,16 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request reque
"[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(),
- request.getReceipt().getDebtor(),
+ debtorIdentifier,
request.getReceipt().getPaymentDateTime().toString());
try {
receiptEntity.setDocument(this.marshalV2(request));
@@ -852,14 +869,9 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request reque
}
private ReceiptEntity getReceiptEntity(
- String idPa, String creditorReferenceId, CtSubject debtor, String paymentDateTime) {
+ String idPa, String creditorReferenceId, String debtor, String paymentDateTime) {
ReceiptEntity receiptEntity = new ReceiptEntity(idPa, creditorReferenceId);
- String debtorIdentifier =
- Optional.ofNullable(debtor)
- .map(CtSubject::getUniqueIdentifier)
- .map(CtEntityUniqueIdentifier::getEntityUniqueIdentifierValue)
- .orElse("");
- receiptEntity.setDebtor(debtorIdentifier);
+ receiptEntity.setDebtor(debtor);
String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
return receiptEntity;
@@ -922,27 +934,78 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
}
public void getAllFailuresQueue() {
+ QueueMessageItem queueMessageItem;
+ List failureBodies = new ArrayList<>();
+ XPathFactory xPathfactory = XPathFactory.newInstance();
+ XPath xpath = xPathfactory.newXPath();
+ while ((queueMessageItem = queueClient.receiveMessage()) != null) {
+ failureBodies.add(getFailureQueue(queueMessageItem));
+ }
try {
- QueueMessageItem queueMessageItem;
- List failureBodies = new ArrayList<>();
- Unmarshaller unmarshaller = JAXBContext.newInstance(PaSendRTV2Request.class).createUnmarshaller();
- while ((queueMessageItem = queueClient.receiveMessage()) != null) {
- failureBodies.add(getFailureQueue(queueMessageItem));
- }
for (String failureBody : failureBodies) {
- JAXBElement request = (JAXBElement) unmarshaller.unmarshal(new ByteArrayInputStream(failureBody.getBytes(StandardCharsets.UTF_8)));
- paSendRTV2(request.getValue());
+ Document xmlDoc = getXMLDocument(failureBody);
+ handlingXml(xmlDoc, xpath);
}
- } catch (JAXBException e) {
- log.error(
- "[managePaSendRtRequest] Error in receipt unmarshalling in queue",
- e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ } catch (XPathExpressionException e) {
+
+ }
+ }
+
+ public void handlingXml (Document xmlDoc, XPath xpath) throws XPathExpressionException {
+ XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
+ NodeList nodes = (NodeList) xPathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
+
+ Element node = (Element) nodes.item(0);
+
+ String idPA = node.getElementsByTagName("idPA").item(0).getTextContent();
+ String creditorReferenceId = node.getElementsByTagName("creditorReferenceId").item(0).getTextContent();
+ String noticeNumber = node.getElementsByTagName("noticeNumber").item(0).getTextContent();
+ String paymentDateTime = node.getElementsByTagName("paymentDateTime").item(0).getTextContent();
+ String receiptId = node.getElementsByTagName("receiptId").item(0).getTextContent();
+ String PSPCompanyName = node.getElementsByTagName("PSPCompanyName").item(0).getTextContent();
+ String paymentMethod = node.getElementsByTagName("paymentMethod").item(0).getTextContent();
+ String fee = node.getElementsByTagName("fee").item(0).getTextContent();
+ String entityUniqueIdentifierValue = node.getElementsByTagName("entityUniqueIdentifierValue").item(0).getTextContent();
+
+ ReceiptEntity receiptEntity = new ReceiptEntity(idPA, creditorReferenceId);
+ receiptEntity.setDebtor(entityUniqueIdentifierValue);
+ String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
+ receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
+
+ LocalDateTime localPaymentDateTime = paymentDateTime != null ? LocalDateTime.parse(paymentDateTime) : null;
+ PaymentOptionModel body =
+ PaymentOptionModel.builder()
+ .idReceipt(receiptId)
+ .paymentDate(localPaymentDateTime)
+ .pspCompany(PSPCompanyName)
+ .paymentMethod(paymentMethod)
+ .fee(String.valueOf(getFeeInCent(new BigDecimal(fee))))
+ .build();
+
+ try {
+ getReceiptPaymentOption(
+ noticeNumber,
+ idPA,
+ creditorReferenceId,
+ body,
+ receiptEntity);
+ } catch (Exception e) {
+ log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
}
}
public String getFailureQueue(QueueMessageItem queueMessageItem){
- queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
+ //queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
}
+
+ public Document getXMLDocument(String xmlString) {
+ try {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputSource is = new InputSource(new StringReader(xmlString));
+ return builder.parse(is);
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ throw new AppException(AppError.UNKNOWN);
+ }
+ }
}
From 0d126f830893340b114dc8f7006621e485cc40c1 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Fri, 19 Apr 2024 13:05:09 +0200
Subject: [PATCH 03/24] PAGOPA-1695 wip
---
.../payments/service/PartnerService.java | 24 +++++++++++--------
.../payments/service/PartnerServiceTest.java | 24 +++++++++++++++++++
2 files changed, 38 insertions(+), 10 deletions(-)
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 d050d567..b2c16139 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -1,5 +1,6 @@
package it.gov.pagopa.payments.service;
+import com.azure.core.util.Context;
import com.azure.data.tables.TableClient;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableErrorCode;
@@ -54,6 +55,7 @@
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
+import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Predicate;
@@ -919,39 +921,40 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
throw e;
} catch (RetryableException e) {
log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessage(receiptEntity.getDocument());
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (FeignException e) {
log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessage(receiptEntity.getDocument());
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
} catch (Exception e) {
log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessage(receiptEntity.getDocument());
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
}
return paymentOption;
}
public void getAllFailuresQueue() {
- QueueMessageItem queueMessageItem;
List failureBodies = new ArrayList<>();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
- while ((queueMessageItem = queueClient.receiveMessage()) != null) {
- failureBodies.add(getFailureQueue(queueMessageItem));
+ // The message is dequeued and locked for 30 seconds by default
+ Optional optQueueMessageItem = queueClient.receiveMessages(1).stream().findFirst();
+ while (optQueueMessageItem.isPresent()) {
+ failureBodies.add(getFailureQueue(optQueueMessageItem.get()));
}
try {
for (String failureBody : failureBodies) {
- Document xmlDoc = getXMLDocument(failureBody);
- handlingXml(xmlDoc, xpath);
+ handlingXml(failureBody, xpath);
}
} catch (XPathExpressionException e) {
}
}
- public void handlingXml (Document xmlDoc, XPath xpath) throws XPathExpressionException {
+ public void handlingXml (String failureBody, XPath xpath) throws XPathExpressionException {
+ Document xmlDoc = getXMLDocument(failureBody);
XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
NodeList nodes = (NodeList) xPathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
@@ -971,6 +974,7 @@ public void handlingXml (Document xmlDoc, XPath xpath) throws XPathExpressionExc
receiptEntity.setDebtor(entityUniqueIdentifierValue);
String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
+ receiptEntity.setDocument(failureBody);
LocalDateTime localPaymentDateTime = paymentDateTime != null ? LocalDateTime.parse(paymentDateTime) : null;
PaymentOptionModel body =
@@ -995,7 +999,7 @@ public void handlingXml (Document xmlDoc, XPath xpath) throws XPathExpressionExc
}
public String getFailureQueue(QueueMessageItem queueMessageItem){
- //queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
+ queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
}
diff --git a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
index 31c09daa..3277f198 100644
--- a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
+++ b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
@@ -22,6 +22,7 @@
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
+import com.azure.storage.queue.QueueClient;
import org.junit.ClassRule;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -103,6 +104,8 @@ class PartnerServiceTest {
@Mock private GpsClient gpsClient;
+ @Mock private QueueClient queueClient;
+
private String genericService = "/xsd/general-service.xsd";
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(genericService);
@@ -438,6 +441,7 @@ void paSendRTTest() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -481,6 +485,7 @@ void paSendRTTestKOConflict() throws DatatypeConfigurationException, IOException
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -523,6 +528,7 @@ void paSendRTTestKOUnknown() throws DatatypeConfigurationException, IOException
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -566,6 +572,7 @@ void paSendRTTestKOStatus(String status, String iuv) throws DatatypeConfiguratio
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -611,6 +618,7 @@ void paSendRTTestKORetryableException() throws DatatypeConfigurationException, I
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -653,6 +661,7 @@ void paSendRTTestKOFeignException() throws DatatypeConfigurationException, IOExc
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
PaSendRTReq requestBody = PaSendRTReqMock.getMock("11111111112222225");
@@ -694,6 +703,7 @@ void paSendRTTestKO() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -748,6 +758,7 @@ void paDemandPaymentNoticeTest()
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -797,6 +808,7 @@ void paDemandPaymentNoticeNotFoundTest()
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -830,6 +842,7 @@ void paGetPaymentV2Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -893,6 +906,7 @@ void paGetPaymentV2_TransferTypePAGOPA_Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -975,6 +989,7 @@ void paGetPaymentIncompleteAddressV2Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1085,6 +1100,7 @@ void paSendRTV2Test() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1128,6 +1144,7 @@ void paSendRTV2TestKOConflict() throws DatatypeConfigurationException, IOExcepti
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1170,6 +1187,7 @@ void paSendRTV2TestKOUnknown() throws DatatypeConfigurationException, IOExceptio
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1213,6 +1231,7 @@ void paSendRTV2TestKOStatus(String status, String iuv) throws DatatypeConfigurat
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1258,6 +1277,7 @@ void paSendRTV2TestKORetryableException() throws DatatypeConfigurationException,
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1300,6 +1320,7 @@ void paSendRTV2TestKOFeignException() throws DatatypeConfigurationException, IOE
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
PaSendRTV2Request requestBody = PaSendRTReqMock.getMockV2("11111111112222235");
@@ -1341,6 +1362,7 @@ void paSendRTV2TestKO() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1383,6 +1405,7 @@ void paSendRTV2ReceiptConflict() throws DatatypeConfigurationException, IOExcept
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
@@ -1426,6 +1449,7 @@ void paSendRTReceiptConflict() throws DatatypeConfigurationException, IOExceptio
gpdClient,
gpsClient,
tableClientConfiguration(),
+ queueClient,
customizedModelMapper));
// Test preconditions
From 805681c39bedca053a0fd2ea502bbfa9ee0475de Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 23 Apr 2024 11:35:48 +0200
Subject: [PATCH 04/24] PAGOPA-1695 wip fixing logic and junit
---
.../payments/service/PartnerService.java | 249 ++++++++++--------
.../payments/service/PartnerServiceTest.java | 102 +++++--
src/test/resources/application.properties | 3 +
3 files changed, 216 insertions(+), 138 deletions(-)
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 b2c16139..26259a3f 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -765,109 +765,137 @@ private PaymentsModelResponse manageGetPaymentRequest(String idPa, CtQrCode qrCo
}
private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
- log.debug(
- "[managePaSendRtRequest] save receipt [noticeNumber={}]",
- request.getReceipt().getNoticeNumber());
+ log.debug(
+ "[managePaSendRtRequest] save receipt [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber());
- String debtorIdentifier =
+ 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.getReceiptPaymentOption(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- body,
- receiptEntity);
+ 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();
+ try {
+ return this.getReceiptPaymentOption(
+ request.getReceipt().getNoticeNumber(),
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ body,
+ receiptEntity);
+ } catch (RetryableException e) {
+ log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ } catch (FeignException e) {
+ log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ } catch (PartnerValidationException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
}
private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request request) {
- log.debug(
- "[managePaSendRtRequest] save V2 receipt [noticeNumber={}]",
- request.getReceipt().getNoticeNumber());
+ log.debug(
+ "[managePaSendRtRequest] save V2 receipt [noticeNumber={}]",
+ request.getReceipt().getNoticeNumber());
- String debtorIdentifier =
+ 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.getReceiptPaymentOption(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- body,
- receiptEntity);
+ 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();
+ try {
+ return this.getReceiptPaymentOption(
+ request.getReceipt().getNoticeNumber(),
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ body,
+ receiptEntity);
+ } catch (RetryableException e) {
+ log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ } catch (FeignException e) {
+ log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ } catch (PartnerValidationException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
+ }
}
private ReceiptEntity getReceiptEntity(
@@ -883,7 +911,7 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
String idPa,
String creditorReferenceId,
PaymentOptionModel body,
- ReceiptEntity receiptEntity) {
+ ReceiptEntity receiptEntity) throws FeignException, URISyntaxException, InvalidKeyException, StorageException{
PaymentOptionModelResponse paymentOption = new PaymentOptionModelResponse();
try {
paymentOption = gpdClient.receiptPaymentOption(idPa, noticeNumber, body);
@@ -919,41 +947,29 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
} catch (PartnerValidationException e) {
throw e;
- } catch (RetryableException e) {
- log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- } catch (FeignException e) {
- log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
- } catch (Exception e) {
- log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", noticeNumber, e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
}
return paymentOption;
}
public void getAllFailuresQueue() {
- List failureBodies = new ArrayList<>();
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
- // The message is dequeued and locked for 30 seconds by default
- Optional optQueueMessageItem = queueClient.receiveMessages(1).stream().findFirst();
- while (optQueueMessageItem.isPresent()) {
- failureBodies.add(getFailureQueue(optQueueMessageItem.get()));
- }
try {
- for (String failureBody : failureBodies) {
- handlingXml(failureBody, xpath);
+ // The message is dequeued and locked for 30 seconds by default
+ List queueList = queueClient.receiveMessages(10, Duration.ofMinutes(5L), null, Context.NONE).stream().toList();
+ for(QueueMessageItem message: queueList) {
+ if(checkQueueCountValidity(message)) {
+ handlingXml(getFailureQueue(message), xpath, message);
+ } else {
+ queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
+ }
}
} catch (XPathExpressionException e) {
}
}
- public void handlingXml (String failureBody, XPath xpath) throws XPathExpressionException {
+ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queueMessageItem) throws XPathExpressionException {
Document xmlDoc = getXMLDocument(failureBody);
XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
NodeList nodes = (NodeList) xPathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
@@ -993,16 +1009,19 @@ public void handlingXml (String failureBody, XPath xpath) throws XPathExpression
creditorReferenceId,
body,
receiptEntity);
- } catch (Exception e) {
+ } catch (FeignException | URISyntaxException | InvalidKeyException | StorageException e) {
log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
+ queueClient.updateMessageWithResponse(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt(), receiptEntity.getDocument(), Duration.ofMinutes(10L), null, Context.NONE);
}
}
+ public boolean checkQueueCountValidity(QueueMessageItem message) {
+ return message.getDequeueCount() <= 5; //TODO parametrize this variable
+ }
+
public String getFailureQueue(QueueMessageItem queueMessageItem){
- queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
}
-
public Document getXMLDocument(String xmlString) {
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
diff --git a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
index 3277f198..353490c9 100644
--- a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
+++ b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
@@ -23,6 +23,9 @@
import javax.xml.stream.XMLStreamException;
import com.azure.storage.queue.QueueClient;
+import com.azure.storage.queue.QueueClientBuilder;
+import com.microsoft.azure.storage.queue.CloudQueue;
+import com.microsoft.azure.storage.queue.CloudQueueClient;
import org.junit.ClassRule;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -104,8 +107,6 @@ class PartnerServiceTest {
@Mock private GpsClient gpsClient;
- @Mock private QueueClient queueClient;
-
private String genericService = "/xsd/general-service.xsd";
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(genericService);
@@ -441,7 +442,7 @@ void paSendRTTest() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -462,6 +463,9 @@ void paSendRTTest() throws DatatypeConfigurationException, IOException {
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception e) {
log.info("Error during table creation", e);
}
@@ -485,7 +489,7 @@ void paSendRTTestKOConflict() throws DatatypeConfigurationException, IOException
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -503,6 +507,9 @@ void paSendRTTestKOConflict() throws DatatypeConfigurationException, IOException
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -528,7 +535,7 @@ void paSendRTTestKOUnknown() throws DatatypeConfigurationException, IOException
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -546,6 +553,9 @@ void paSendRTTestKOUnknown() throws DatatypeConfigurationException, IOException
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -572,7 +582,7 @@ void paSendRTTestKOStatus(String status, String iuv) throws DatatypeConfiguratio
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -593,6 +603,9 @@ void paSendRTTestKOStatus(String status, String iuv) throws DatatypeConfiguratio
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", ex);
}
@@ -618,7 +631,7 @@ void paSendRTTestKORetryableException() throws DatatypeConfigurationException, I
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -636,6 +649,9 @@ void paSendRTTestKORetryableException() throws DatatypeConfigurationException, I
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -661,7 +677,7 @@ void paSendRTTestKOFeignException() throws DatatypeConfigurationException, IOExc
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
PaSendRTReq requestBody = PaSendRTReqMock.getMock("11111111112222225");
@@ -678,6 +694,9 @@ void paSendRTTestKOFeignException() throws DatatypeConfigurationException, IOExc
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -703,7 +722,7 @@ void paSendRTTestKO() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -721,6 +740,9 @@ void paSendRTTestKO() throws DatatypeConfigurationException, IOException {
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -758,7 +780,7 @@ void paDemandPaymentNoticeTest()
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -808,7 +830,7 @@ void paDemandPaymentNoticeNotFoundTest()
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -842,7 +864,7 @@ void paGetPaymentV2Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -906,7 +928,7 @@ void paGetPaymentV2_TransferTypePAGOPA_Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -989,7 +1011,7 @@ void paGetPaymentIncompleteAddressV2Test()
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1100,7 +1122,7 @@ void paSendRTV2Test() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1121,6 +1143,9 @@ void paSendRTV2Test() throws DatatypeConfigurationException, IOException {
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception e) {
log.info("Error during table creation", e);
}
@@ -1144,7 +1169,7 @@ void paSendRTV2TestKOConflict() throws DatatypeConfigurationException, IOExcepti
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1162,6 +1187,9 @@ void paSendRTV2TestKOConflict() throws DatatypeConfigurationException, IOExcepti
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -1187,7 +1215,7 @@ void paSendRTV2TestKOUnknown() throws DatatypeConfigurationException, IOExceptio
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1205,6 +1233,9 @@ void paSendRTV2TestKOUnknown() throws DatatypeConfigurationException, IOExceptio
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -1231,7 +1262,7 @@ void paSendRTV2TestKOStatus(String status, String iuv) throws DatatypeConfigurat
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1252,6 +1283,9 @@ void paSendRTV2TestKOStatus(String status, String iuv) throws DatatypeConfigurat
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", ex);
}
@@ -1277,7 +1311,7 @@ void paSendRTV2TestKORetryableException() throws DatatypeConfigurationException,
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1295,6 +1329,9 @@ void paSendRTV2TestKORetryableException() throws DatatypeConfigurationException,
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -1320,7 +1357,7 @@ void paSendRTV2TestKOFeignException() throws DatatypeConfigurationException, IOE
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
PaSendRTV2Request requestBody = PaSendRTReqMock.getMockV2("11111111112222235");
@@ -1337,6 +1374,9 @@ void paSendRTV2TestKOFeignException() throws DatatypeConfigurationException, IOE
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -1362,7 +1402,7 @@ void paSendRTV2TestKO() throws DatatypeConfigurationException, IOException {
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1380,6 +1420,9 @@ void paSendRTV2TestKO() throws DatatypeConfigurationException, IOException {
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception ex) {
log.info("Error during table creation", e);
}
@@ -1405,7 +1448,7 @@ void paSendRTV2ReceiptConflict() throws DatatypeConfigurationException, IOExcept
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1426,6 +1469,9 @@ void paSendRTV2ReceiptConflict() throws DatatypeConfigurationException, IOExcept
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception e) {
log.info("Error during table creation", e);
}
@@ -1449,7 +1495,7 @@ void paSendRTReceiptConflict() throws DatatypeConfigurationException, IOExceptio
gpdClient,
gpsClient,
tableClientConfiguration(),
- queueClient,
+ queueClientConfiguration(),
customizedModelMapper));
// Test preconditions
@@ -1470,6 +1516,9 @@ void paSendRTReceiptConflict() throws DatatypeConfigurationException, IOExceptio
cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
CloudTable table = cloudTableClient.getTableReference("receiptsTable");
table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
} catch (Exception e) {
log.info("Error during table creation", e);
}
@@ -1488,4 +1537,11 @@ private TableClient tableClientConfiguration() {
.tableName("receiptsTable")
.buildClient();
}
+
+ private QueueClient queueClientConfiguration() {
+ return new QueueClientBuilder()
+ .connectionString(storageConnectionString)
+ .queueName("testqueue")
+ .buildClient();
+ }
}
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index 2ce15b5c..e9dcf4e0 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -32,3 +32,6 @@ retry.maxDelay=200
xsd.generic-service=payments/src/main/resources/xsd/general-service.xsd
+
+azure.queue.connection.string=DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;QueueEndpoint=http://localhost:8902/;
+azure.queue.queueName=testqueue
From 6cc83a0abcedc2283046ac93095bd14543df64ee Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 23 Apr 2024 13:00:51 +0200
Subject: [PATCH 05/24] PAGOPA-1695 adding scheduler class
---
.../pagopa/payments/scheduler/Scheduler.java | 36 +++++
.../SchedulerTest.java} | 4 +-
.../payments/service/PartnerService.java | 4 +-
.../payments/service/SchedulerService.java | 129 ++++++++++++++++++
4 files changed, 169 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
rename src/main/java/it/gov/pagopa/payments/{controller/scheduler/Scheduler.java => scheduler/SchedulerTest.java} (91%)
create mode 100644 src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
diff --git a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
new file mode 100644
index 00000000..d70d2782
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -0,0 +1,36 @@
+package it.gov.pagopa.payments.scheduler;
+
+import it.gov.pagopa.payments.service.SchedulerService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+@Component
+@Slf4j
+@ConditionalOnProperty(name = "cron.job.schedule.retry.enabled", matchIfMissing = true)
+public class Scheduler {
+
+ private static final String LOG_BASE_HEADER_INFO = "[OperationType: %s] - [ClassMethod: %s] - [MethodParamsToLog: %s]";
+ private static final String CRON_JOB = "CRON JOB";
+ private Thread threadOfExecution;
+
+ @Autowired
+ SchedulerService schedulerService;
+
+ @Scheduled(cron = "${cron.job.schedule.expression.retry.status}")
+ @Async
+ @Transactional
+ public void changeDebtPositionStatusToValid() {
+ 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.getAllFailuresQueue();
+ this.threadOfExecution = Thread.currentThread();
+ }
+}
+
diff --git a/src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java b/src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
similarity index 91%
rename from src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java
rename to src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
index 878d36f1..14b5c407 100644
--- a/src/main/java/it/gov/pagopa/payments/controller/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
@@ -1,4 +1,4 @@
-package it.gov.pagopa.payments.controller.scheduler;
+package it.gov.pagopa.payments.scheduler;
import it.gov.pagopa.payments.service.PartnerService;
import lombok.extern.slf4j.Slf4j;
@@ -13,7 +13,7 @@
@Controller
@Slf4j
@Validated
-public class Scheduler {
+public class SchedulerTest {
@Autowired
PartnerService partnerService;
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 26259a3f..9e9f467f 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -694,7 +694,7 @@ private ReceiptEntity getReceipt(String organizationFiscalCode, String iuv)
}
}
- private long getFeeInCent(BigDecimal fee) {
+ public long getFeeInCent(BigDecimal fee) {
long feeInCent = 0;
if (null != fee) {
feeInCent = fee.multiply(BigDecimal.valueOf(100)).longValue();
@@ -907,7 +907,7 @@ private ReceiptEntity getReceiptEntity(
return receiptEntity;
}
- private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
+ public PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
String idPa,
String creditorReferenceId,
PaymentOptionModel body,
diff --git a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
new file mode 100644
index 00000000..a803c48f
--- /dev/null
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -0,0 +1,129 @@
+package it.gov.pagopa.payments.service;
+
+import com.azure.core.util.Context;
+import com.azure.storage.queue.QueueClient;
+import com.azure.storage.queue.models.QueueMessageItem;
+import com.microsoft.azure.storage.StorageException;
+import feign.FeignException;
+import it.gov.pagopa.payments.entity.ReceiptEntity;
+import it.gov.pagopa.payments.exception.AppError;
+import it.gov.pagopa.payments.exception.AppException;
+import it.gov.pagopa.payments.model.PaymentOptionModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.*;
+import java.io.IOException;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Slf4j
+public class SchedulerService {
+
+ @Value(value = "${azure.queue.dequeue.limit}")
+ private Integer dequeueLimit;
+ @Autowired
+ QueueClient queueClient;
+
+ @Autowired
+ PartnerService partnerService;
+
+ public void getAllFailuresQueue() {
+ XPathFactory xPathfactory = XPathFactory.newInstance();
+ XPath xpath = xPathfactory.newXPath();
+ try {
+ // The message is dequeued and locked for 30 seconds by default
+ List queueList = queueClient.receiveMessages(10, Duration.ofMinutes(5L), null, Context.NONE).stream().toList();
+ for(QueueMessageItem message: queueList) {
+ if(checkQueueCountValidity(message)) {
+ handlingXml(getFailureQueue(message), xpath, message);
+ } else {
+ queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
+ }
+ }
+ } catch (XPathExpressionException e) {
+
+ }
+ }
+
+ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queueMessageItem) throws XPathExpressionException {
+ Document xmlDoc = getXMLDocument(failureBody);
+ XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
+ NodeList nodes = (NodeList) xPathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
+
+ Element node = (Element) nodes.item(0);
+
+ String idPA = node.getElementsByTagName("idPA").item(0).getTextContent();
+ String creditorReferenceId = node.getElementsByTagName("creditorReferenceId").item(0).getTextContent();
+ String noticeNumber = node.getElementsByTagName("noticeNumber").item(0).getTextContent();
+ String paymentDateTime = node.getElementsByTagName("paymentDateTime").item(0).getTextContent();
+ String receiptId = node.getElementsByTagName("receiptId").item(0).getTextContent();
+ String PSPCompanyName = node.getElementsByTagName("PSPCompanyName").item(0).getTextContent();
+ String paymentMethod = node.getElementsByTagName("paymentMethod").item(0).getTextContent();
+ String fee = node.getElementsByTagName("fee").item(0).getTextContent();
+ String entityUniqueIdentifierValue = node.getElementsByTagName("entityUniqueIdentifierValue").item(0).getTextContent();
+
+ ReceiptEntity receiptEntity = new ReceiptEntity(idPA, creditorReferenceId);
+ receiptEntity.setDebtor(entityUniqueIdentifierValue);
+ String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
+ receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
+ receiptEntity.setDocument(failureBody);
+
+ LocalDateTime localPaymentDateTime = paymentDateTime != null ? LocalDateTime.parse(paymentDateTime) : null;
+ PaymentOptionModel body =
+ PaymentOptionModel.builder()
+ .idReceipt(receiptId)
+ .paymentDate(localPaymentDateTime)
+ .pspCompany(PSPCompanyName)
+ .paymentMethod(paymentMethod)
+ .fee(String.valueOf(partnerService.getFeeInCent(new BigDecimal(fee))))
+ .build();
+
+ try {
+ partnerService.getReceiptPaymentOption(
+ noticeNumber,
+ idPA,
+ creditorReferenceId,
+ body,
+ receiptEntity);
+ } catch (FeignException | URISyntaxException | InvalidKeyException | StorageException e) {
+ log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
+ queueClient.updateMessageWithResponse(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt(), receiptEntity.getDocument(), Duration.ofMinutes(10L), null, Context.NONE);
+ }
+ }
+
+ public boolean checkQueueCountValidity(QueueMessageItem message) {
+ return message.getDequeueCount() <= dequeueLimit;
+ }
+
+ public String getFailureQueue(QueueMessageItem queueMessageItem){
+ return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
+ }
+ public Document getXMLDocument(String xmlString) {
+ try {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputSource is = new InputSource(new StringReader(xmlString));
+ return builder.parse(is);
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ throw new AppException(AppError.UNKNOWN);
+ }
+ }
+}
From 579fb63a76896bf0b904558b39151c33fa37b910 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 30 Apr 2024 17:10:51 +0200
Subject: [PATCH 06/24] PAGOPA-1695 updating logic and inserting junit tests
---
openapi/openapi.json | 813 +++++++++---------
.../payments/scheduler/SchedulerTest.java | 28 -
.../payments/service/PartnerService.java | 116 +--
.../payments/service/SchedulerService.java | 45 +-
.../pagopa/payments/mock/PaSendRTReqMock.java | 36 +-
.../payments/service/PartnerServiceTest.java | 86 +-
.../service/SchedulerServiceTest.java | 309 +++++++
src/test/resources/application.properties | 7 +
8 files changed, 870 insertions(+), 570 deletions(-)
delete mode 100644 src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
create mode 100644 src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
diff --git a/openapi/openapi.json b/openapi/openapi.json
index c2fcb9dd..0caf8f6e 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.20"
+ "openapi" : "3.0.1",
+ "info" : {
+ "title" : "PagoPA API Payments",
+ "description" : "Payments",
+ "termsOfService" : "https://www.pagopa.gov.it/",
+ "version" : "0.12.20"
},
- "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/src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java b/src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
deleted file mode 100644
index 14b5c407..00000000
--- a/src/main/java/it/gov/pagopa/payments/scheduler/SchedulerTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package it.gov.pagopa.payments.scheduler;
-
-import it.gov.pagopa.payments.service.PartnerService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-
-@Controller
-@Slf4j
-@Validated
-public class SchedulerTest {
-
- @Autowired
- PartnerService partnerService;
-
- @GetMapping(
- value = "/scheduler",
- produces = {MediaType.APPLICATION_JSON_VALUE})
- public ResponseEntity getFailureReceipts() {
- partnerService.getAllFailuresQueue();
- return new ResponseEntity<>(HttpStatus.OK);
- }
-}
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 9e9f467f..198eab5e 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -6,7 +6,6 @@
import com.azure.data.tables.models.TableErrorCode;
import com.azure.data.tables.models.TableServiceException;
import com.azure.storage.queue.QueueClient;
-import com.azure.storage.queue.models.QueueMessageItem;
import com.microsoft.azure.storage.StorageException;
import feign.FeignException;
import feign.RetryableException;
@@ -49,11 +48,9 @@
import it.gov.pagopa.payments.utils.CustomizedMapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.StringReader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.net.URISyntaxException;
-import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.time.Duration;
import java.time.LocalDateTime;
@@ -70,7 +67,6 @@
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
-import javax.xml.xpath.*;
import it.gov.pagopa.payments.utils.Validator;
import lombok.AllArgsConstructor;
@@ -81,10 +77,6 @@
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@Service
@@ -110,6 +102,9 @@ public class PartnerService {
@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;
@@ -817,12 +812,16 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
receiptEntity);
} catch (RetryableException e) {
log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (FeignException e) {
log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ } catch (StorageException e) {
+ log.error("[getReceiptPaymentOption] Storage exception [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (PartnerValidationException e) {
throw e;
} catch (Exception e) {
@@ -884,12 +883,16 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request reque
receiptEntity);
} catch (RetryableException e) {
log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (FeignException e) {
log.error("[getReceiptPaymentOption] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofMinutes(10L), null, null, Context.NONE);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
+ } catch (StorageException e) {
+ log.error("[getReceiptPaymentOption] Storage exception [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
+ throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
} catch (PartnerValidationException e) {
throw e;
} catch (Exception e) {
@@ -907,11 +910,11 @@ private ReceiptEntity getReceiptEntity(
return receiptEntity;
}
- public PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
+ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
String idPa,
String creditorReferenceId,
PaymentOptionModel body,
- ReceiptEntity receiptEntity) throws FeignException, URISyntaxException, InvalidKeyException, StorageException{
+ ReceiptEntity receiptEntity) throws FeignException, URISyntaxException, InvalidKeyException, StorageException {
PaymentOptionModelResponse paymentOption = new PaymentOptionModelResponse();
try {
paymentOption = gpdClient.receiptPaymentOption(idPa, noticeNumber, body);
@@ -951,84 +954,11 @@ public PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
return paymentOption;
}
- public void getAllFailuresQueue() {
- XPathFactory xPathfactory = XPathFactory.newInstance();
- XPath xpath = xPathfactory.newXPath();
- try {
- // The message is dequeued and locked for 30 seconds by default
- List queueList = queueClient.receiveMessages(10, Duration.ofMinutes(5L), null, Context.NONE).stream().toList();
- for(QueueMessageItem message: queueList) {
- if(checkQueueCountValidity(message)) {
- handlingXml(getFailureQueue(message), xpath, message);
- } else {
- queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
- }
- }
- } catch (XPathExpressionException e) {
-
- }
- }
-
- public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queueMessageItem) throws XPathExpressionException {
- Document xmlDoc = getXMLDocument(failureBody);
- XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
- NodeList nodes = (NodeList) xPathExpr.evaluate(xmlDoc, XPathConstants.NODESET);
-
- Element node = (Element) nodes.item(0);
-
- String idPA = node.getElementsByTagName("idPA").item(0).getTextContent();
- String creditorReferenceId = node.getElementsByTagName("creditorReferenceId").item(0).getTextContent();
- String noticeNumber = node.getElementsByTagName("noticeNumber").item(0).getTextContent();
- String paymentDateTime = node.getElementsByTagName("paymentDateTime").item(0).getTextContent();
- String receiptId = node.getElementsByTagName("receiptId").item(0).getTextContent();
- String PSPCompanyName = node.getElementsByTagName("PSPCompanyName").item(0).getTextContent();
- String paymentMethod = node.getElementsByTagName("paymentMethod").item(0).getTextContent();
- String fee = node.getElementsByTagName("fee").item(0).getTextContent();
- String entityUniqueIdentifierValue = node.getElementsByTagName("entityUniqueIdentifierValue").item(0).getTextContent();
-
- ReceiptEntity receiptEntity = new ReceiptEntity(idPA, creditorReferenceId);
- receiptEntity.setDebtor(entityUniqueIdentifierValue);
- String paymentDateTimeIdentifier = Optional.ofNullable(paymentDateTime).orElse("");
- receiptEntity.setPaymentDateTime(paymentDateTimeIdentifier);
- receiptEntity.setDocument(failureBody);
-
- LocalDateTime localPaymentDateTime = paymentDateTime != null ? LocalDateTime.parse(paymentDateTime) : null;
- PaymentOptionModel body =
- PaymentOptionModel.builder()
- .idReceipt(receiptId)
- .paymentDate(localPaymentDateTime)
- .pspCompany(PSPCompanyName)
- .paymentMethod(paymentMethod)
- .fee(String.valueOf(getFeeInCent(new BigDecimal(fee))))
- .build();
-
- try {
- getReceiptPaymentOption(
- noticeNumber,
- idPA,
- creditorReferenceId,
- body,
- receiptEntity);
- } catch (FeignException | URISyntaxException | InvalidKeyException | StorageException e) {
- log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
- queueClient.updateMessageWithResponse(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt(), receiptEntity.getDocument(), Duration.ofMinutes(10L), null, Context.NONE);
- }
- }
-
- public boolean checkQueueCountValidity(QueueMessageItem message) {
- return message.getDequeueCount() <= 5; //TODO parametrize this variable
- }
-
- public String getFailureQueue(QueueMessageItem queueMessageItem){
- return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
- }
- public Document getXMLDocument(String xmlString) {
- try {
- DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- InputSource is = new InputSource(new StringReader(xmlString));
- return builder.parse(is);
- } catch (ParserConfigurationException | SAXException | IOException e) {
- throw new AppException(AppError.UNKNOWN);
- }
+ 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 a803c48f..46d5fca8 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -9,6 +9,8 @@
import it.gov.pagopa.payments.exception.AppError;
import it.gov.pagopa.payments.exception.AppException;
import it.gov.pagopa.payments.model.PaymentOptionModel;
+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;
@@ -36,10 +38,19 @@
@Service
@Slf4j
+@NoArgsConstructor
+@AllArgsConstructor
public class SchedulerService {
@Value(value = "${azure.queue.dequeue.limit}")
private Integer dequeueLimit;
+
+ @Value(value = "${azure.queue.receive.invisibilityTime}")
+ private Long queueReceiveInvisibilityTime;
+
+ @Value(value = "${azure.queue.send.invisibilityTime}")
+ private Long queueUpdateInvisibilityTime;
+
@Autowired
QueueClient queueClient;
@@ -49,18 +60,23 @@ public class SchedulerService {
public void getAllFailuresQueue() {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
- try {
- // The message is dequeued and locked for 30 seconds by default
- List queueList = queueClient.receiveMessages(10, Duration.ofMinutes(5L), null, Context.NONE).stream().toList();
- for(QueueMessageItem message: queueList) {
- if(checkQueueCountValidity(message)) {
+ // The message is dequeued and locked for a timeout equal to seconds
+ List queueList = queueClient.receiveMessages(
+ 10,
+ Duration.ofSeconds(queueReceiveInvisibilityTime),
+ null,
+ Context.NONE)
+ .stream().toList();
+ for(QueueMessageItem message: queueList) {
+ if(checkQueueCountValidity(message)) {
+ try{
handlingXml(getFailureQueue(message), xpath, message);
- } else {
- queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
+ } catch (XPathExpressionException e) {
+ log.error("[paSendRT] XML error during retry process [messageId={},popReceipt={}]\",\n", message.getMessageId() , message.getPopReceipt());
}
+ } else {
+ queueClient.deleteMessage(message.getMessageId(), message.getPopReceipt());
}
- } catch (XPathExpressionException e) {
-
}
}
@@ -98,15 +114,22 @@ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queue
.build();
try {
- partnerService.getReceiptPaymentOption(
+ partnerService.getReceiptPaymentOptionScheduler(
noticeNumber,
idPA,
creditorReferenceId,
body,
receiptEntity);
+ queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
} catch (FeignException | URISyntaxException | InvalidKeyException | StorageException e) {
log.info("[paSendRT] Retry failed [fiscalCode={},noticeNumber={}]\",\n", idPA, noticeNumber);
- queueClient.updateMessageWithResponse(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt(), receiptEntity.getDocument(), Duration.ofMinutes(10L), null, Context.NONE);
+ queueClient.updateMessageWithResponse(
+ queueMessageItem.getMessageId(),
+ queueMessageItem.getPopReceipt(),
+ receiptEntity.getDocument(),
+ Duration.ofSeconds(queueUpdateInvisibilityTime),
+ null,
+ Context.NONE);
}
}
diff --git a/src/test/java/it/gov/pagopa/payments/mock/PaSendRTReqMock.java b/src/test/java/it/gov/pagopa/payments/mock/PaSendRTReqMock.java
index 2767d88e..06b6050e 100644
--- a/src/test/java/it/gov/pagopa/payments/mock/PaSendRTReqMock.java
+++ b/src/test/java/it/gov/pagopa/payments/mock/PaSendRTReqMock.java
@@ -1,10 +1,7 @@
package it.gov.pagopa.payments.mock;
-import it.gov.pagopa.payments.model.partner.CtReceipt;
-import it.gov.pagopa.payments.model.partner.CtReceiptV2;
-import it.gov.pagopa.payments.model.partner.PaSendRTReq;
-import it.gov.pagopa.payments.model.partner.PaSendRTV2Request;
-import it.gov.pagopa.payments.model.partner.StOutcome;
+import it.gov.pagopa.payments.model.partner.*;
+
import java.math.BigDecimal;
import java.time.LocalDateTime;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -61,4 +58,33 @@ public static PaSendRTV2Request getMockV2(String iuv) throws DatatypeConfigurati
return mock;
}
+
+ public static PaSendRTReq getMockDebtor(String iuv) throws DatatypeConfigurationException {
+ CtEntityUniqueIdentifier debtorCode = new CtEntityUniqueIdentifier();
+ debtorCode.setEntityUniqueIdentifierValue("debtorCode");
+
+ CtSubject debtor = new CtSubject();
+ debtor.setUniqueIdentifier(debtorCode);
+
+ CtReceipt receipt = new CtReceipt();
+ receipt.setReceiptId("c110729d258c4ab1b765fe902aae41d6");
+ receipt.setNoticeNumber("3" + iuv);
+ receipt.setFiscalCode("77777777777");
+ receipt.setOutcome(StOutcome.OK);
+ receipt.setCreditorReferenceId(iuv);
+ receipt.setPaymentMethod("creditCard");
+ receipt.setPSPCompanyName("Intesa San Paolo");
+ receipt.setFee(BigDecimal.valueOf(2));
+ receipt.setDebtor(debtor);
+ receipt.setPaymentDateTime(
+ DatatypeFactory.newInstance().newXMLGregorianCalendar(LocalDateTime.now().toString()));
+
+ PaSendRTReq mock = new PaSendRTReq();
+ mock.setIdBrokerPA("77777777777");
+ mock.setIdPA("77777777777");
+ mock.setIdStation("77777777777_01");
+ mock.setReceipt(receipt);
+
+ return mock;
+ }
}
diff --git a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
index 353490c9..b6c52fdd 100644
--- a/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
+++ b/src/test/java/it/gov/pagopa/payments/service/PartnerServiceTest.java
@@ -5,8 +5,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -38,6 +37,7 @@
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
@@ -111,6 +111,9 @@ class PartnerServiceTest {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(genericService);
+ @Value(value = "${azure.queue.send.invisibilityTime}")
+ private Long queueSendInvisibilityTime;
+
private final ObjectFactory factoryUtil = new ObjectFactory();
@Autowired private CustomizedMapper customizedModelMapper;
@@ -438,6 +441,7 @@ void paSendRTTest() throws DatatypeConfigurationException, IOException {
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -485,6 +489,7 @@ void paSendRTTestKOConflict() throws DatatypeConfigurationException, IOException
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -531,6 +536,7 @@ void paSendRTTestKOUnknown() throws DatatypeConfigurationException, IOException
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -578,6 +584,7 @@ void paSendRTTestKOStatus(String status, String iuv) throws DatatypeConfiguratio
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -627,6 +634,7 @@ void paSendRTTestKORetryableException() throws DatatypeConfigurationException, I
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -673,6 +681,7 @@ void paSendRTTestKOFeignException() throws DatatypeConfigurationException, IOExc
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -718,6 +727,7 @@ void paSendRTTestKO() throws DatatypeConfigurationException, IOException {
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -776,6 +786,7 @@ void paDemandPaymentNoticeTest()
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -826,6 +837,7 @@ void paDemandPaymentNoticeNotFoundTest()
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -860,6 +872,7 @@ void paGetPaymentV2Test()
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -924,6 +937,7 @@ void paGetPaymentV2_TransferTypePAGOPA_Test()
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1007,6 +1021,7 @@ void paGetPaymentIncompleteAddressV2Test()
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1118,6 +1133,7 @@ void paSendRTV2Test() throws DatatypeConfigurationException, IOException {
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1165,6 +1181,7 @@ void paSendRTV2TestKOConflict() throws DatatypeConfigurationException, IOExcepti
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1211,6 +1228,7 @@ void paSendRTV2TestKOUnknown() throws DatatypeConfigurationException, IOExceptio
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1258,6 +1276,7 @@ void paSendRTV2TestKOStatus(String status, String iuv) throws DatatypeConfigurat
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1307,6 +1326,7 @@ void paSendRTV2TestKORetryableException() throws DatatypeConfigurationException,
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1353,6 +1373,7 @@ void paSendRTV2TestKOFeignException() throws DatatypeConfigurationException, IOE
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1398,6 +1419,7 @@ void paSendRTV2TestKO() throws DatatypeConfigurationException, IOException {
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1444,6 +1466,7 @@ void paSendRTV2ReceiptConflict() throws DatatypeConfigurationException, IOExcept
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1491,6 +1514,7 @@ void paSendRTReceiptConflict() throws DatatypeConfigurationException, IOExceptio
spy(
new PartnerService(
resource,
+ queueSendInvisibilityTime,
factory,
gpdClient,
gpsClient,
@@ -1531,12 +1555,60 @@ void paSendRTReceiptConflict() throws DatatypeConfigurationException, IOExceptio
assertEquals("L'id del pagamento ricevuto e' duplicato", e.getMessage());
}
- private TableClient tableClientConfiguration() {
- return new TableClientBuilder()
- .connectionString(storageConnectionString)
- .tableName("receiptsTable")
- .buildClient();
+ @Test
+ void paSendRTQueueInsertTest() throws DatatypeConfigurationException, IOException {
+
+ var pService =
+ spy(
+ new PartnerService(
+ resource,
+ queueSendInvisibilityTime,
+ factory,
+ gpdClient,
+ gpsClient,
+ tableClientConfiguration(),
+ queueClientConfiguration(),
+ customizedModelMapper));
+ // Test preconditions
+ PaSendRTReq requestBody = PaSendRTReqMock.getMock("11111111112222225");
+
+ var e = Mockito.mock(FeignException.class);
+ when(gpdClient.receiptPaymentOption(anyString(), anyString(), any(PaymentOptionModel.class)))
+ .thenThrow(e);
+
+ try {
+ CloudStorageAccount cloudStorageAccount = CloudStorageAccount.parse(storageConnectionString);
+ CloudTableClient cloudTableClient = cloudStorageAccount.createCloudTableClient();
+ TableRequestOptions tableRequestOptions = new TableRequestOptions();
+ tableRequestOptions.setRetryPolicyFactory(RetryNoRetry.getInstance());
+ cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
+ CloudTable table = cloudTableClient.getTableReference("receiptsTable");
+ table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.createIfNotExists();
+ } catch (Exception ex) {
+ log.info("Error during table creation", e);
+ }
+
+ try {
+ // Test execution
+ assertEquals(0, queueClientConfiguration().receiveMessages(10).stream().toList().size());
+ pService.paSendRT(requestBody);
+ fail();
+ } catch (PartnerValidationException ex) {
+ // Test post condition
+ assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
+ assertEquals(1, queueClientConfiguration().receiveMessages(10).stream().toList().size());
}
+ }
+
+ private TableClient tableClientConfiguration() {
+ return new TableClientBuilder()
+ .connectionString(storageConnectionString)
+ .tableName("receiptsTable")
+ .buildClient();
+ }
private QueueClient queueClientConfiguration() {
return new QueueClientBuilder()
diff --git a/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java b/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
new file mode 100644
index 00000000..0e2bd6b1
--- /dev/null
+++ b/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
@@ -0,0 +1,309 @@
+package it.gov.pagopa.payments.service;
+
+import com.azure.core.util.Context;
+import com.azure.data.tables.TableClient;
+import com.azure.data.tables.TableClientBuilder;
+import com.azure.storage.queue.QueueClient;
+import com.azure.storage.queue.QueueClientBuilder;
+import com.azure.storage.queue.models.QueueMessageItem;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.RetryNoRetry;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.queue.CloudQueue;
+import com.microsoft.azure.storage.queue.CloudQueueClient;
+import com.microsoft.azure.storage.table.CloudTable;
+import com.microsoft.azure.storage.table.CloudTableClient;
+import com.microsoft.azure.storage.table.TableRequestOptions;
+import feign.FeignException;
+import it.gov.pagopa.payments.endpoints.validation.exceptions.PartnerValidationException;
+import it.gov.pagopa.payments.entity.ReceiptEntity;
+import it.gov.pagopa.payments.mock.*;
+import it.gov.pagopa.payments.model.*;
+import it.gov.pagopa.payments.model.partner.*;
+import it.gov.pagopa.payments.utils.CustomizedMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.ClassRule;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import javax.xml.datatype.*;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+import static org.testcontainers.shaded.org.awaitility.Awaitility.await;
+
+@Testcontainers
+@ExtendWith(MockitoExtension.class)
+@Slf4j
+@SpringBootTest
+class SchedulerServiceTest {
+
+ @Autowired private SchedulerService schedulerService;
+
+ @InjectMocks private PartnerService partnerService;
+
+ @Mock private ObjectFactory factory;
+
+ @Mock private GpdClient gpdClient;
+
+ @Mock private GpsClient gpsClient;
+
+ private String genericService = "/xsd/general-service.xsd";
+ ResourceLoader resourceLoader = new DefaultResourceLoader();
+ Resource resource = resourceLoader.getResource(genericService);
+
+ @Value(value = "${azure.queue.send.invisibilityTime}")
+ private Long queueSendInvisibilityTime;
+ private final ObjectFactory factoryUtil = new ObjectFactory();
+
+ @Autowired private CustomizedMapper customizedModelMapper;
+
+ @ClassRule @Container
+ public static GenericContainer> azurite =
+ new GenericContainer<>(
+ DockerImageName.parse("mcr.microsoft.com/azure-storage/azurite:latest"))
+ .withExposedPorts(10001, 10002, 10000);
+
+ String storageConnectionString =
+ String.format(
+ "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;TableEndpoint=http://%s:%s/devstoreaccount1;QueueEndpoint=http://%s:%s/devstoreaccount1;BlobEndpoint=http://%s:%s/devstoreaccount1",
+ azurite.getContainerIpAddress(),
+ azurite.getMappedPort(10002),
+ azurite.getContainerIpAddress(),
+ azurite.getMappedPort(10001),
+ azurite.getContainerIpAddress(),
+ azurite.getMappedPort(10000));
+
+ @Test
+ void paSendRTQueueReceiveTestOk() throws DatatypeConfigurationException, IOException, URISyntaxException, InvalidKeyException, StorageException {
+
+ var pService =
+ spy(
+ new PartnerService(
+ resource,
+ queueSendInvisibilityTime,
+ factory,
+ gpdClient,
+ gpsClient,
+ tableClientConfiguration(),
+ queueClientConfiguration(),
+ customizedModelMapper));
+
+ var schedService =
+ spy(
+ new SchedulerService(
+ 5,
+ 1L,
+ 1L,
+ queueClientConfiguration(),
+ pService));
+
+ // Test preconditions
+ PaSendRTReq requestBody = PaSendRTReqMock.getMockDebtor("11111111112222225");
+
+ var e = Mockito.mock(FeignException.class);
+ when(gpdClient.receiptPaymentOption(anyString(), anyString(), nullable(PaymentOptionModel.class)))
+ .thenThrow(e);
+ doReturn(MockUtil.readModelFromFile("gpd/receiptPaymentOption.json", PaymentOptionModelResponse.class))
+ .when(pService)
+ .getReceiptPaymentOptionScheduler(anyString(), anyString(), anyString(), any(PaymentOptionModel.class), any(ReceiptEntity.class));
+
+ try {
+ CloudStorageAccount cloudStorageAccount = CloudStorageAccount.parse(storageConnectionString);
+ CloudTableClient cloudTableClient = cloudStorageAccount.createCloudTableClient();
+ TableRequestOptions tableRequestOptions = new TableRequestOptions();
+ tableRequestOptions.setRetryPolicyFactory(RetryNoRetry.getInstance());
+ cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
+ CloudTable table = cloudTableClient.getTableReference("receiptsTable");
+ table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.create();
+ } catch (Exception ex) {
+ log.info("Error during table creation", e);
+ }
+
+ try {
+ // Test execution
+ queueClientConfiguration().clearMessages();
+ assertEquals(0, queueClientConfiguration().receiveMessages(10).stream().toList().size());
+ pService.paSendRT(requestBody);
+ fail();
+ } catch (PartnerValidationException ex) {
+ // Test post condition
+ assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
+ schedService.getAllFailuresQueue();
+ await().pollDelay(Duration.ofSeconds(2L)).until(() -> true);
+ assertEquals(0, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ }
+ }
+
+ @Test
+ void paSendRTQueueReceiveTestKo() throws DatatypeConfigurationException, IOException, URISyntaxException, InvalidKeyException, StorageException {
+
+ var pService =
+ spy(
+ new PartnerService(
+ resource,
+ queueSendInvisibilityTime,
+ factory,
+ gpdClient,
+ gpsClient,
+ tableClientConfiguration(),
+ queueClientConfiguration(),
+ customizedModelMapper));
+
+ var schedService =
+ spy(
+ new SchedulerService(
+ 5,
+ 1L,
+ 1L,
+ queueClientConfiguration(),
+ pService));
+
+ // Test preconditions
+ PaSendRTReq requestBody = PaSendRTReqMock.getMockDebtor("11111111112222225");
+
+ var e = Mockito.mock(FeignException.class);
+ when(gpdClient.receiptPaymentOption(anyString(), anyString(), nullable(PaymentOptionModel.class)))
+ .thenThrow(e);
+ doThrow(FeignException.class)
+ .when(pService)
+ .getReceiptPaymentOptionScheduler(anyString(), anyString(), anyString(), any(PaymentOptionModel.class), any(ReceiptEntity.class));
+
+ try {
+ CloudStorageAccount cloudStorageAccount = CloudStorageAccount.parse(storageConnectionString);
+ CloudTableClient cloudTableClient = cloudStorageAccount.createCloudTableClient();
+ TableRequestOptions tableRequestOptions = new TableRequestOptions();
+ tableRequestOptions.setRetryPolicyFactory(RetryNoRetry.getInstance());
+ cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
+ CloudTable table = cloudTableClient.getTableReference("receiptsTable");
+ table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.create();
+ } catch (Exception ex) {
+ log.info("Error during table creation", e);
+ }
+
+ try {
+ // Test execution
+ queueClientConfiguration().clearMessages();
+ assertEquals(0, queueClientConfiguration().receiveMessages(10).stream().toList().size());
+ pService.paSendRT(requestBody);
+ fail();
+ } catch (PartnerValidationException ex) {
+ // Test post condition
+ assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
+ schedService.getAllFailuresQueue();
+ await().pollDelay(Duration.ofSeconds(2L)).until(() -> true);
+ assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ }
+ }
+
+ @Test
+ void paSendRTQueueReceiveTestDequeueCountKo() throws DatatypeConfigurationException, IOException, URISyntaxException, InvalidKeyException, StorageException {
+
+ var pService =
+ spy(
+ new PartnerService(
+ resource,
+ queueSendInvisibilityTime,
+ factory,
+ gpdClient,
+ gpsClient,
+ tableClientConfiguration(),
+ queueClientConfiguration(),
+ customizedModelMapper));
+
+ var schedService =
+ spy(
+ new SchedulerService(
+ 5,
+ 1L,
+ 1L,
+ queueClientConfiguration(),
+ pService));
+
+ // Test preconditions
+ PaSendRTReq requestBody = PaSendRTReqMock.getMockDebtor("11111111112222225");
+
+ var e = Mockito.mock(FeignException.class);
+ when(gpdClient.receiptPaymentOption(anyString(), anyString(), nullable(PaymentOptionModel.class)))
+ .thenThrow(e);
+
+ try {
+ CloudStorageAccount cloudStorageAccount = CloudStorageAccount.parse(storageConnectionString);
+ CloudTableClient cloudTableClient = cloudStorageAccount.createCloudTableClient();
+ TableRequestOptions tableRequestOptions = new TableRequestOptions();
+ tableRequestOptions.setRetryPolicyFactory(RetryNoRetry.getInstance());
+ cloudTableClient.setDefaultRequestOptions(tableRequestOptions);
+ CloudTable table = cloudTableClient.getTableReference("receiptsTable");
+ table.createIfNotExists();
+ CloudQueueClient cloudQueueClient = cloudStorageAccount.createCloudQueueClient();
+ CloudQueue queue = cloudQueueClient.getQueueReference("testqueue");
+ queue.create();
+ } catch (Exception ex) {
+ log.info("Error during table creation", e);
+ }
+
+ try {
+ // Test execution
+ queueClientConfiguration().clearMessages();
+ assertEquals(0, queueClientConfiguration().receiveMessages(10).stream().toList().size());
+ pService.paSendRT(requestBody);
+ fail();
+ } catch (PartnerValidationException ex) {
+ // Test post condition
+ assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
+ for(int i = 0; i <= 4; i++) {
+ QueueMessageItem receptionMessage = queueClientConfiguration().receiveMessage();
+ queueClientConfiguration().updateMessage(
+ receptionMessage.getMessageId(),
+ receptionMessage.getPopReceipt(),
+ "text",
+ null
+ );
+ }
+ schedService.getAllFailuresQueue();
+ assertEquals(0, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
+ }
+ }
+
+ private TableClient tableClientConfiguration() {
+ return new TableClientBuilder()
+ .connectionString(storageConnectionString)
+ .tableName("receiptsTable")
+ .buildClient();
+ }
+
+ private QueueClient queueClientConfiguration() {
+ return new QueueClientBuilder()
+ .connectionString(storageConnectionString)
+ .queueName("testqueue")
+ .buildClient();
+ }
+}
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index e9dcf4e0..54bb5e3d 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -35,3 +35,10 @@ xsd.generic-service=payments/src/main/resources/xsd/general-service.xsd
azure.queue.connection.string=DefaultEndpointsProtocol=http;AccountName=localhost;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==;QueueEndpoint=http://localhost:8902/;
azure.queue.queueName=testqueue
+azure.queue.dequeue.limit=5
+azure.queue.send.invisibilityTime=0
+azure.queue.receive.invisibilityTime=0
+
+# cron configuration
+cron.job.schedule.enabled=false
+cron.job.schedule.expression.retry.status=*/35 * * * * *
From d6c62244efa8476c43d099809ee1b8fb65209b5a Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Mon, 6 May 2024 16:19:36 +0200
Subject: [PATCH 07/24] PAGOPA-1695 solving some issues
---
.../config/QueueClientConfiguration.java | 4 +-
.../payments/service/PartnerService.java | 60 +++++++++----------
2 files changed, 30 insertions(+), 34 deletions(-)
diff --git a/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
index eba93462..be234179 100644
--- a/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
+++ b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
@@ -14,12 +14,12 @@ public class QueueClientConfiguration {
private static String CONNECTION_STRING;
@Value("${azure.queue.connection.string}")
- public void setConnectionStringStatic(String connectionString) {
+ public static void setConnectionStringStatic(String connectionString) {
QueueClientConfiguration.CONNECTION_STRING = connectionString;
}
@Value("${azure.queue.queueName}")
- public void setTableNameStatic(String queueName) {
+ public static void setTableNameStatic(String queueName) {
QueueClientConfiguration.QUEUE_NAME = queueName;
}
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 198eab5e..0c1ce3e5 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -803,31 +803,13 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTReq request) {
.paymentMethod(request.getReceipt().getPaymentMethod())
.fee(String.valueOf(this.getFeeInCent(request.getReceipt().getFee())))
.build();
- try {
- return this.getReceiptPaymentOption(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
- body,
- receiptEntity);
- } catch (RetryableException e) {
- log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), 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] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SEMANTICA);
- } catch (StorageException e) {
- log.error("[getReceiptPaymentOption] Storage exception [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- queueClient.sendMessageWithResponse(receiptEntity.getDocument(), Duration.ofSeconds(queueSendInvisibilityTime), null, null, Context.NONE);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- } catch (PartnerValidationException e) {
- throw e;
- } catch (Exception e) {
- log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
- throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
- }
+
+ return this.getReceiptExceptionHandling(
+ request.getReceipt().getNoticeNumber(),
+ request.getIdPA(),
+ request.getReceipt().getCreditorReferenceId(),
+ body,
+ receiptEntity);
}
private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request request) {
@@ -874,29 +856,43 @@ private PaymentOptionModelResponse managePaSendRtRequest(PaSendRTV2Request reque
.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(
- request.getReceipt().getNoticeNumber(),
- request.getIdPA(),
- request.getReceipt().getCreditorReferenceId(),
+ noticeNumber,
+ idPa,
+ creditorReferenceId,
body,
receiptEntity);
} catch (RetryableException e) {
- log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ log.error("[getReceiptPaymentOption] 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] GPD Error Response [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ log.error("[getReceiptPaymentOption] 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] Storage exception [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ log.error("[getReceiptPaymentOption] 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) {
throw e;
} catch (Exception e) {
- log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", request.getReceipt().getNoticeNumber(), e);
+ log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", noticeNumber, e);
throw new PartnerValidationException(PaaErrorEnum.PAA_SYSTEM_ERROR);
}
}
From 429d5d19dcee2ef66793ea338cd3f3d83e924102 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Mon, 6 May 2024 16:25:05 +0200
Subject: [PATCH 08/24] PAGOPA-1695 fixing junit
---
.../gov/pagopa/payments/config/QueueClientConfiguration.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
index be234179..eba93462 100644
--- a/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
+++ b/src/main/java/it/gov/pagopa/payments/config/QueueClientConfiguration.java
@@ -14,12 +14,12 @@ public class QueueClientConfiguration {
private static String CONNECTION_STRING;
@Value("${azure.queue.connection.string}")
- public static void setConnectionStringStatic(String connectionString) {
+ public void setConnectionStringStatic(String connectionString) {
QueueClientConfiguration.CONNECTION_STRING = connectionString;
}
@Value("${azure.queue.queueName}")
- public static void setTableNameStatic(String queueName) {
+ public void setTableNameStatic(String queueName) {
QueueClientConfiguration.QUEUE_NAME = queueName;
}
From 7dbd3f4005177d46ce56a7b3b8f4515bd0d066c2 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 10:02:31 +0200
Subject: [PATCH 09/24] PAGOPA-1695 adding xml validation
---
.../it/gov/pagopa/payments/service/SchedulerService.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
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 46d5fca8..66714dad 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -21,6 +21,7 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -142,7 +143,10 @@ public String getFailureQueue(QueueMessageItem queueMessageItem){
}
public Document getXMLDocument(String xmlString) {
try {
- DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ DocumentBuilderFactory x = DocumentBuilderFactory.newInstance();
+ x.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ x.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ DocumentBuilder builder = x.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xmlString));
return builder.parse(is);
} catch (ParserConfigurationException | SAXException | IOException e) {
From 91079473632c88b2bbee0458d310ed0b55f2f357 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 10:21:22 +0200
Subject: [PATCH 10/24] PAGOPA-1695 testing security
---
.../it/gov/pagopa/payments/service/SchedulerService.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
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 66714dad..50a90fd7 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -143,10 +143,10 @@ public String getFailureQueue(QueueMessageItem queueMessageItem){
}
public Document getXMLDocument(String xmlString) {
try {
- DocumentBuilderFactory x = DocumentBuilderFactory.newInstance();
- x.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
- x.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
- DocumentBuilder builder = x.newDocumentBuilder();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultNSInstance();
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xmlString));
return builder.parse(is);
} catch (ParserConfigurationException | SAXException | IOException e) {
From 1e178fa0bf0bb3f460b428d9867c42622966e9a0 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 11:43:30 +0200
Subject: [PATCH 11/24] PAGOPA-1695 changing documentbuilderfactory
---
.../java/it/gov/pagopa/payments/service/SchedulerService.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 50a90fd7..7a0dffee 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -143,7 +143,7 @@ public String getFailureQueue(QueueMessageItem queueMessageItem){
}
public Document getXMLDocument(String xmlString) {
try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultNSInstance();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
DocumentBuilder builder = factory.newDocumentBuilder();
From 2818c440b988278e880faa7e3026d0b4baeeb801 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 12:26:31 +0200
Subject: [PATCH 12/24] PAGOPA-1695 adding values for kubernetes
---
helm/values-dev.yaml | 7 +++++++
helm/values-prod.yaml | 7 +++++++
helm/values-uat.yaml | 7 +++++++
.../it/gov/pagopa/payments/scheduler/Scheduler.java | 2 +-
src/main/resources/application.properties | 11 +++++++++++
5 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index 7114f62f..219cf606 100644
--- a/helm/values-dev.yaml
+++ b/helm/values-dev.yaml
@@ -75,6 +75,12 @@ microservice-chart:
API_CONFIG_HOST: "https://api.dev.platform.pagopa.it/apiconfig/auth/api/v1"
GPS_HOST: "https://api.dev.platform.pagopa.it/gps/spontaneous-payments-service/v1"
GPD_HOST: "https://api.dev.platform.pagopa.it/gpd/api/v1"
+ QUEUE_NAME: "gpd-receipt-poison-queue"
+ DEQUEUE_LIMIT: "5"
+ QUEUE_SEND_INVISIBILITY_TIME: "120"
+ QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
+ CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string'
@@ -82,6 +88,7 @@ microservice-chart:
GPD_SUBSCRIPTION_KEY: "gpd-d-gpd-subscription-key"
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"
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 82823dce..046a09f5 100644
--- a/helm/values-prod.yaml
+++ b/helm/values-prod.yaml
@@ -75,6 +75,12 @@ microservice-chart:
API_CONFIG_HOST: "https://api.platform.pagopa.it/apiconfig/auth/api/v1"
GPS_HOST: "https://api.platform.pagopa.it/gps/spontaneous-payments-service/v1"
GPD_HOST: "https://api.platform.pagopa.it/gpd/api/v1"
+ QUEUE_NAME: "gpd-receipt-poison-queue"
+ DEQUEUE_LIMIT: "5"
+ QUEUE_SEND_INVISIBILITY_TIME: "120"
+ QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
+ CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-p-connection-string'
@@ -82,6 +88,7 @@ microservice-chart:
GPD_SUBSCRIPTION_KEY: "gpd-p-gpd-subscription-key"
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"
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 e5c46c43..e6204d0d 100644
--- a/helm/values-uat.yaml
+++ b/helm/values-uat.yaml
@@ -75,6 +75,12 @@ microservice-chart:
API_CONFIG_HOST: "https://api.uat.platform.pagopa.it/apiconfig/auth/api/v1"
GPS_HOST: "https://api.uat.platform.pagopa.it/gps/spontaneous-payments-service/v1"
GPD_HOST: "https://api.uat.platform.pagopa.it/gpd/api/v1"
+ QUEUE_NAME: "gpd-receipt-poison-queue"
+ DEQUEUE_LIMIT: "5"
+ QUEUE_SEND_INVISIBILITY_TIME: "120"
+ QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
+ CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-u-connection-string'
@@ -82,6 +88,7 @@ microservice-chart:
GPD_SUBSCRIPTION_KEY: "gpd-u-gpd-subscription-key"
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"
keyvault:
name: "pagopa-u-gps-kv"
tenantId: "7788edaf-0346-4068-9d79-c868aed15b3d"
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 d70d2782..4e6e9d9c 100644
--- a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -24,7 +24,7 @@ public class Scheduler {
@Autowired
SchedulerService schedulerService;
- @Scheduled(cron = "${cron.job.schedule.expression.retry.status}")
+ @Scheduled(cron = "${cron.job.schedule.expression.retry.trigger}")
@Async
@Transactional
public void changeDebtPositionStatusToValid() {
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 634077ee..3fabcd75 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -45,3 +45,14 @@ spring.cache.type=caffeine
spring.cache.caffeine.spec=maximumSize=${CACHE_SIZE}, expireAfterAccess=${CACHE_EXPIRATION_TIME}
xsd.generic-service=classpath:/xsd/general-service.xsd
+
+# queue configuration
+azure.queue.connection.string=${QUEUE_CONNECTION_STRING}
+azure.queue.queueName=${QUEUE_NAME}
+azure.queue.dequeue.limit=${DEQUEUE_LIMIT}
+azure.queue.send.invisibilityTime=${QUEUE_SEND_INVISIBILITY_TIME}
+azure.queue.receive.invisibilityTime=${QUEUE_RECEIVE_INVISIBILITY_TIME}
+
+# cron configuration
+cron.job.schedule.retry.enabled=${CRON_JOB_SCHEDULE_RETRY_ENABLED}
+cron.job.schedule.expression.retry.status=${CRON_JOB_SCHEDULE_HISTORY_TRIGGER}
From 1560c355f9d4b91bf0f541cb3b6ffc6ed6aa80f5 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 12:56:08 +0200
Subject: [PATCH 13/24] PAGOPA-1695 update local properties file
---
src/main/resources/application-local.properties | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties
index f6c5b80f..f904a89d 100644
--- a/src/main/resources/application-local.properties
+++ b/src/main/resources/application-local.properties
@@ -32,4 +32,14 @@ retry.maxDelay=500
retry.multiplier=2
# cache configuration
-spring.cache.caffeine.spec=maximumSize=100, expireAfterAccess=10s
\ No newline at end of file
+spring.cache.caffeine.spec=maximumSize=100, expireAfterAccess=10s
+
+azure.queue.connection.string=${QUEUE_CONNECTION_STRING}
+azure.queue.queueName=testqueue
+azure.queue.dequeue.limit=5
+azure.queue.send.invisibilityTime=0
+azure.queue.receive.invisibilityTime=0
+
+# cron configuration
+cron.job.schedule.enabled=false
+cron.job.schedule.expression.retry.status=*/35 * * * * *
\ No newline at end of file
From 0f2e5dba1b0166848745609cac7848644f7321d4 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 14:23:12 +0200
Subject: [PATCH 14/24] PAGOPA-1695 update helm value
---
helm/values-dev.yaml | 4 ++--
helm/values-prod.yaml | 4 ++--
helm/values-uat.yaml | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index a623ca59..ede26422 100644
--- a/helm/values-dev.yaml
+++ b/helm/values-dev.yaml
@@ -81,8 +81,8 @@ microservice-chart:
DEQUEUE_LIMIT: "5"
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
- CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
- CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string'
diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml
index 68a1e7f0..9117b1cf 100644
--- a/helm/values-prod.yaml
+++ b/helm/values-prod.yaml
@@ -81,8 +81,8 @@ microservice-chart:
DEQUEUE_LIMIT: "5"
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
- CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
- CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-p-connection-string'
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index bf61090a..b82a438e 100644
--- a/helm/values-uat.yaml
+++ b/helm/values-uat.yaml
@@ -82,7 +82,7 @@ microservice-chart:
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
- CRON_JOB_SCHEDULE_HISTORY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-u-connection-string'
From db4cb6b1d8ec132aa10b633dd9181e1b47f5299c Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 14:26:12 +0200
Subject: [PATCH 15/24] PAGOPA-1695 update properties file
---
src/main/resources/application-local.properties | 2 +-
src/main/resources/application.properties | 2 +-
src/test/resources/application.properties | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties
index f904a89d..49f41dca 100644
--- a/src/main/resources/application-local.properties
+++ b/src/main/resources/application-local.properties
@@ -42,4 +42,4 @@ azure.queue.receive.invisibilityTime=0
# cron configuration
cron.job.schedule.enabled=false
-cron.job.schedule.expression.retry.status=*/35 * * * * *
\ No newline at end of file
+cron.job.schedule.expression.retry.trigger=*/35 * * * * *
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index d6374bb6..f1c24da2 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -59,4 +59,4 @@ azure.queue.receive.invisibilityTime=${QUEUE_RECEIVE_INVISIBILITY_TIME}
# cron configuration
cron.job.schedule.retry.enabled=${CRON_JOB_SCHEDULE_RETRY_ENABLED}
-cron.job.schedule.expression.retry.status=${CRON_JOB_SCHEDULE_HISTORY_TRIGGER}
+cron.job.schedule.expression.retry.trigger=${CRON_JOB_SCHEDULE_RETRY_TRIGGER}
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index 54bb5e3d..5384fb34 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -41,4 +41,4 @@ azure.queue.receive.invisibilityTime=0
# cron configuration
cron.job.schedule.enabled=false
-cron.job.schedule.expression.retry.status=*/35 * * * * *
+cron.job.schedule.expression.retry.trigger=*/35 * * * * *
From 4f22564f22e39dc6b33aa27e3d81ed06bc69feae Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 14:28:29 +0200
Subject: [PATCH 16/24] PAGOPA-1695 minor fix
---
helm/values-uat.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index b82a438e..277132f7 100644
--- a/helm/values-uat.yaml
+++ b/helm/values-uat.yaml
@@ -81,7 +81,7 @@ microservice-chart:
DEQUEUE_LIMIT: "5"
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
- CRON_JOB_SCHEDULE_RETRY_ENABLED: "false"
+ CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
envSecret:
# required
From 384034b5123cabb2919bc70b6812038afe88e3ad Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 14:34:44 +0200
Subject: [PATCH 17/24] PAGOPA-1695 minor fix
---
src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
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 4e6e9d9c..5779f8ab 100644
--- a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -26,8 +26,7 @@ public class Scheduler {
@Scheduled(cron = "${cron.job.schedule.expression.retry.trigger}")
@Async
- @Transactional
- public void changeDebtPositionStatusToValid() {
+ 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.getAllFailuresQueue();
this.threadOfExecution = Thread.currentThread();
From 1dccd1fd6774af551fac054cc77cf9beb16e4b65 Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 14:36:08 +0200
Subject: [PATCH 18/24] PAGOPA-1695 minor fix
---
.../java/it/gov/pagopa/payments/scheduler/Scheduler.java | 3 +--
.../it/gov/pagopa/payments/service/SchedulerService.java | 2 +-
.../gov/pagopa/payments/service/SchedulerServiceTest.java | 6 +++---
3 files changed, 5 insertions(+), 6 deletions(-)
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 5779f8ab..cfa77db8 100644
--- a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -7,7 +7,6 @@
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -28,7 +27,7 @@ public class Scheduler {
@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.getAllFailuresQueue();
+ schedulerService.retryFailedPaSendRT();
this.threadOfExecution = Thread.currentThread();
}
}
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 7a0dffee..f5125122 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -58,7 +58,7 @@ public class SchedulerService {
@Autowired
PartnerService partnerService;
- public void getAllFailuresQueue() {
+ public void retryFailedPaSendRT() {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
// The message is dequeued and locked for a timeout equal to seconds
diff --git a/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java b/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
index 0e2bd6b1..81f1ba9c 100644
--- a/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
+++ b/src/test/java/it/gov/pagopa/payments/service/SchedulerServiceTest.java
@@ -152,7 +152,7 @@ void paSendRTQueueReceiveTestOk() throws DatatypeConfigurationException, IOExcep
// Test post condition
assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
- schedService.getAllFailuresQueue();
+ schedService.retryFailedPaSendRT();
await().pollDelay(Duration.ofSeconds(2L)).until(() -> true);
assertEquals(0, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
}
@@ -217,7 +217,7 @@ void paSendRTQueueReceiveTestKo() throws DatatypeConfigurationException, IOExcep
// Test post condition
assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
assertEquals(PaaErrorEnum.PAA_SEMANTICA, ex.getError());
- schedService.getAllFailuresQueue();
+ schedService.retryFailedPaSendRT();
await().pollDelay(Duration.ofSeconds(2L)).until(() -> true);
assertEquals(1, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
}
@@ -288,7 +288,7 @@ void paSendRTQueueReceiveTestDequeueCountKo() throws DatatypeConfigurationExcept
null
);
}
- schedService.getAllFailuresQueue();
+ schedService.retryFailedPaSendRT();
assertEquals(0, queueClientConfiguration().peekMessages(10, null, Context.NONE).stream().toList().size());
}
}
From d42ef655fe53e5ed64a5f7c1367ca0383d5ca41a Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Tue, 7 May 2024 16:31:59 +0200
Subject: [PATCH 19/24] PAGOPA-1695 fixing comments
---
helm/values-dev.yaml | 2 +-
helm/values-prod.yaml | 2 +-
helm/values-uat.yaml | 2 +-
.../it/gov/pagopa/payments/service/SchedulerService.java | 9 +++++++--
4 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index ede26422..872fff9c 100644
--- a/helm/values-dev.yaml
+++ b/helm/values-dev.yaml
@@ -82,7 +82,7 @@ microservice-chart:
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
- CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-d-connection-string'
diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml
index 9117b1cf..75081871 100644
--- a/helm/values-prod.yaml
+++ b/helm/values-prod.yaml
@@ -82,7 +82,7 @@ microservice-chart:
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
- CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-p-connection-string'
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index 277132f7..2d4f964b 100644
--- a/helm/values-uat.yaml
+++ b/helm/values-uat.yaml
@@ -82,7 +82,7 @@ microservice-chart:
QUEUE_SEND_INVISIBILITY_TIME: "120"
QUEUE_RECEIVE_INVISIBILITY_TIME: "300"
CRON_JOB_SCHEDULE_RETRY_ENABLED: "true"
- CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 13 * * *"
+ CRON_JOB_SCHEDULE_RETRY_TRIGGER: "0 0 0,6,12,18 * * *"
envSecret:
# required
APPLICATIONINSIGHTS_CONNECTION_STRING: 'ai-u-connection-string'
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 f5125122..d7816896 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -71,7 +71,7 @@ public void retryFailedPaSendRT() {
for(QueueMessageItem message: queueList) {
if(checkQueueCountValidity(message)) {
try{
- handlingXml(getFailureQueue(message), xpath, message);
+ handlingXml(getMessageContent(message), xpath, message);
} catch (XPathExpressionException e) {
log.error("[paSendRT] XML error during retry process [messageId={},popReceipt={}]\",\n", message.getMessageId() , message.getPopReceipt());
}
@@ -81,6 +81,10 @@ public void retryFailedPaSendRT() {
}
}
+ /*
+ This method is used to parse the xml string and extract the necessary values to create a payment option body.
+ After this, the payment process is triggered with the newly created body.
+ */
public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queueMessageItem) throws XPathExpressionException {
Document xmlDoc = getXMLDocument(failureBody);
XPathExpression xPathExpr = xpath.compile('/' + xmlDoc.getFirstChild().getNodeName());
@@ -138,9 +142,10 @@ public boolean checkQueueCountValidity(QueueMessageItem message) {
return message.getDequeueCount() <= dequeueLimit;
}
- public String getFailureQueue(QueueMessageItem queueMessageItem){
+ public String getMessageContent(QueueMessageItem queueMessageItem){
return new String(queueMessageItem.getBody().toBytes(), StandardCharsets.UTF_8);
}
+
public Document getXMLDocument(String xmlString) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultInstance();
From 7740bcd0c0350797dc459ff29869705f9a9004e1 Mon Sep 17 00:00:00 2001
From: AngeloCaporaso
Date: Wed, 8 May 2024 14:07:34 +0200
Subject: [PATCH 20/24] [PAGOPA-1695] chore: Update log
---
.../pagopa/payments/service/PartnerService.java | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
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 0c1ce3e5..dda9d552 100644
--- a/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/PartnerService.java
@@ -878,21 +878,23 @@ private PaymentOptionModelResponse getReceiptExceptionHandling(String noticeNumb
body,
receiptEntity);
} catch (RetryableException e) {
- log.error("[getReceiptPaymentOption] GPD Not Reachable [noticeNumber={}]", noticeNumber, 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] GPD Error Response [noticeNumber={}]", noticeNumber, 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] Storage exception [noticeNumber={}]", noticeNumber, 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) {
- log.error("[getReceiptPaymentOption] GPD Generic Error [noticeNumber={}]", noticeNumber, 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);
}
}
@@ -922,7 +924,7 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
// if PO is already paid on GPD --> checks and in case creates the receipt in PAID status
try {
log.error(
- "[getReceiptPaymentOption] GPD Conflict Error Response [noticeNumber={}]",
+ "[getReceiptPaymentOption] PAA_RECEIPT_DUPLICATA: GPD Conflict Error Response [noticeNumber={}]",
noticeNumber,
e);
ReceiptEntity receiptEntityToCreate = this.getReceipt(idPa, creditorReferenceId);
@@ -940,7 +942,7 @@ private PaymentOptionModelResponse getReceiptPaymentOption(String noticeNumber,
throw new PartnerValidationException(PaaErrorEnum.PAA_RECEIPT_DUPLICATA);
} catch (FeignException.NotFound e) {
log.error(
- "[getReceiptPaymentOption] GPD Not Found Error Response [noticeNumber={}]",
+ "[getReceiptPaymentOption] PAA_PAGAMENTO_SCONOSCIUTO: GPD Not Found Error Response [noticeNumber={}]",
noticeNumber,
e);
throw new PartnerValidationException(PaaErrorEnum.PAA_PAGAMENTO_SCONOSCIUTO);
From 8c59dbcfd9a29ed7b874dfc015b0d8e4f76ed220 Mon Sep 17 00:00:00 2001
From: pagopa-github-bot
Date: Wed, 8 May 2024 12:09:46 +0000
Subject: [PATCH 21/24] Bump to version
0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability [skip ci]
---
helm/Chart.yaml | 4 +-
helm/values-dev.yaml | 2 +-
helm/values-prod.yaml | 2 +-
helm/values-uat.yaml | 2 +-
openapi/openapi.json | 813 ++++++++++++++++++++++--------------------
pom.xml | 2 +-
6 files changed, 432 insertions(+), 393 deletions(-)
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
index bddb3380..e18100a3 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.93.0
-appVersion: 0.12.21
+version: 0.94.0
+appVersion: 0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
dependencies:
- name: microservice-chart
version: 2.4.0
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index 872fff9c..77cc5dbc 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.21"
+ tag: "0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml
index 75081871..5fadde4c 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.21"
+ tag: "0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index 2d4f964b..16330493 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.21"
+ tag: "0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/openapi/openapi.json b/openapi/openapi.json
index 0caf8f6e..e1ab4b1e 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -1,515 +1,554 @@
{
- "openapi" : "3.0.1",
- "info" : {
- "title" : "PagoPA API Payments",
- "description" : "Payments",
- "termsOfService" : "https://www.pagopa.gov.it/",
- "version" : "0.12.20"
+ "openapi": "3.0.1",
+ "info": {
+ "title": "PagoPA API Payments",
+ "description": "Payments",
+ "termsOfService": "https://www.pagopa.gov.it/",
+ "version": "0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
},
- "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
+ }
+ },
+ {
+ "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"
+ ],
+ "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 48bc0cfe..5a2d5a11 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
it.gov.pagopa
payments
- 0.12.21
+ 0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
Payments
Payments
From 518a98e743d95ce8265bae4e512be4adcb9f822f Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Wed, 8 May 2024 14:57:22 +0200
Subject: [PATCH 22/24] PAGOPA-1695 fixing scheduler job
---
.../java/it/gov/pagopa/payments/scheduler/Scheduler.java | 6 ++++++
1 file changed, 6 insertions(+)
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 cfa77db8..fed08bfb 100644
--- a/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
+++ b/src/main/java/it/gov/pagopa/payments/scheduler/Scheduler.java
@@ -5,6 +5,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -13,6 +14,7 @@
@Component
@Slf4j
+@EnableScheduling
@ConditionalOnProperty(name = "cron.job.schedule.retry.enabled", matchIfMissing = true)
public class Scheduler {
@@ -30,5 +32,9 @@ public void retryPaSendRT() {
schedulerService.retryFailedPaSendRT();
this.threadOfExecution = Thread.currentThread();
}
+
+ public Thread getThreadOfExecution() {
+ return this.threadOfExecution;
+ }
}
From a599a7a32f103b91cc2fcdd0d99ae6e8420929d1 Mon Sep 17 00:00:00 2001
From: pagopa-github-bot
Date: Wed, 8 May 2024 13:10:44 +0000
Subject: [PATCH 23/24] Bump to version
0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability [skip ci]
---
helm/Chart.yaml | 4 ++--
helm/values-dev.yaml | 2 +-
helm/values-prod.yaml | 2 +-
helm/values-uat.yaml | 2 +-
openapi/openapi.json | 2 +-
pom.xml | 2 +-
6 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
index e18100a3..8a3d3bca 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.94.0
-appVersion: 0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
+version: 0.95.0
+appVersion: 0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
dependencies:
- name: microservice-chart
version: 2.4.0
diff --git a/helm/values-dev.yaml b/helm/values-dev.yaml
index 77cc5dbc..2a820f64 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.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
+ tag: "0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/helm/values-prod.yaml b/helm/values-prod.yaml
index 5fadde4c..d5ac8c8f 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.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
+ tag: "0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml
index 16330493..9f5c2e83 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.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
+ tag: "0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
pullPolicy: Always
livenessProbe:
httpGet:
diff --git a/openapi/openapi.json b/openapi/openapi.json
index e1ab4b1e..134dfb18 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -4,7 +4,7 @@
"title": "PagoPA API Payments",
"description": "Payments",
"termsOfService": "https://www.pagopa.gov.it/",
- "version": "0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
+ "version": "0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability"
},
"servers": [
{
diff --git a/pom.xml b/pom.xml
index 5a2d5a11..76868fcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
it.gov.pagopa
payments
- 0.12.21-1-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
+ 0.12.21-2-PAGOPA-1695-sviluppo-pa-send-rt-long-term-reliability
Payments
Payments
From d653c330453e554b5b0db433e876f13c0b4b7a2b Mon Sep 17 00:00:00 2001
From: FedericoRuzzier <49512050+FedericoRuzzier@users.noreply.github.com>
Date: Wed, 8 May 2024 16:13:08 +0200
Subject: [PATCH 24/24] PAGOPA-1695 adding catch in scheduler
---
.../it/gov/pagopa/payments/service/SchedulerService.java | 5 +++++
1 file changed, 5 insertions(+)
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 d7816896..cb8cfa75 100644
--- a/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
+++ b/src/main/java/it/gov/pagopa/payments/service/SchedulerService.java
@@ -5,6 +5,7 @@
import com.azure.storage.queue.models.QueueMessageItem;
import com.microsoft.azure.storage.StorageException;
import feign.FeignException;
+import it.gov.pagopa.payments.endpoints.validation.exceptions.PartnerValidationException;
import it.gov.pagopa.payments.entity.ReceiptEntity;
import it.gov.pagopa.payments.exception.AppError;
import it.gov.pagopa.payments.exception.AppException;
@@ -135,6 +136,10 @@ public void handlingXml (String failureBody, XPath xpath, QueueMessageItem queue
Duration.ofSeconds(queueUpdateInvisibilityTime),
null,
Context.NONE);
+ } catch (PartnerValidationException e) {
+ // { PAA_RECEIPT_DUPLICATA, PAA_PAGAMENTO_SCONOSCIUTO }
+ log.info("[paSendRT] Retry failed {} [fiscalCode={},noticeNumber={}]\",\n", e.getMessage(), idPA, noticeNumber);
+ queueClient.deleteMessage(queueMessageItem.getMessageId(), queueMessageItem.getPopReceipt());
}
}