From cc2e142277a509d53bb7a1efd0c111705de5da11 Mon Sep 17 00:00:00 2001 From: svariant Date: Tue, 28 Jan 2025 17:10:32 +0100 Subject: [PATCH] [PIDM-35] feat: Improve Transfer update iban method loop --- .../payments/api/IPaymentsController.java | 2 +- .../UpdateTransferIbanMassiveModel.java | 5 +- .../repository/PaymentOptionRepository.java | 3 +- .../repository/TransferRepository.java | 11 +-- .../service/payments/PaymentsService.java | 88 +++++++++---------- 5 files changed, 49 insertions(+), 60 deletions(-) diff --git a/src/main/java/it/gov/pagopa/debtposition/controller/payments/api/IPaymentsController.java b/src/main/java/it/gov/pagopa/debtposition/controller/payments/api/IPaymentsController.java index f75a3efc..dffe42dd 100644 --- a/src/main/java/it/gov/pagopa/debtposition/controller/payments/api/IPaymentsController.java +++ b/src/main/java/it/gov/pagopa/debtposition/controller/payments/api/IPaymentsController.java @@ -303,7 +303,7 @@ ResponseEntity updateNotificationFee( schema = @Schema(implementation = ProblemJson.class))) }) @PostMapping( - value = "/organizations/{organizationfiscalcode}/transfers/iban/update", + value = "/organizations/{organizationfiscalcode}/transfers/update/iban", produces = {MediaType.TEXT_PLAIN_VALUE}, consumes = {MediaType.APPLICATION_JSON_VALUE}) ResponseEntity updateTransferIbanMassive( diff --git a/src/main/java/it/gov/pagopa/debtposition/model/payments/UpdateTransferIbanMassiveModel.java b/src/main/java/it/gov/pagopa/debtposition/model/payments/UpdateTransferIbanMassiveModel.java index 4e234161..e40ddf1f 100644 --- a/src/main/java/it/gov/pagopa/debtposition/model/payments/UpdateTransferIbanMassiveModel.java +++ b/src/main/java/it/gov/pagopa/debtposition/model/payments/UpdateTransferIbanMassiveModel.java @@ -1,22 +1,21 @@ package it.gov.pagopa.debtposition.model.payments; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotNull; +@Builder @Data @AllArgsConstructor @NoArgsConstructor public class UpdateTransferIbanMassiveModel { @NotNull - @JsonProperty("old_iban") private String oldIban; @NotNull - @JsonProperty("new_iban") private String newIban; } diff --git a/src/main/java/it/gov/pagopa/debtposition/repository/PaymentOptionRepository.java b/src/main/java/it/gov/pagopa/debtposition/repository/PaymentOptionRepository.java index b275c805..d1a8e9e5 100644 --- a/src/main/java/it/gov/pagopa/debtposition/repository/PaymentOptionRepository.java +++ b/src/main/java/it/gov/pagopa/debtposition/repository/PaymentOptionRepository.java @@ -2,6 +2,7 @@ import it.gov.pagopa.debtposition.entity.PaymentOption; +import it.gov.pagopa.debtposition.entity.PaymentPosition; import it.gov.pagopa.debtposition.model.enumeration.PaymentOptionStatus; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -25,6 +26,6 @@ public interface PaymentOptionRepository extends JpaRepository findByOrganizationFiscalCodeAndIuvOrOrganizationFiscalCodeAndNav(String organizationFiscalCodeIuv, String iuv, String organizationFiscalCodeNav, String nav); // Derived Query - using method naming convention - get all PaymentOption by payment_position_id and in the specified statuses - List findByPaymentPositionIdAndStatusIn(Long paymentPositionId, List statusList); + List findByPaymentPositionInAndStatusIn(List paymentPositionList, List statusList); } diff --git a/src/main/java/it/gov/pagopa/debtposition/repository/TransferRepository.java b/src/main/java/it/gov/pagopa/debtposition/repository/TransferRepository.java index 97cde490..af5d6468 100644 --- a/src/main/java/it/gov/pagopa/debtposition/repository/TransferRepository.java +++ b/src/main/java/it/gov/pagopa/debtposition/repository/TransferRepository.java @@ -1,11 +1,11 @@ package it.gov.pagopa.debtposition.repository; +import it.gov.pagopa.debtposition.entity.PaymentOption; import it.gov.pagopa.debtposition.entity.Transfer; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -14,12 +14,9 @@ @Repository public interface TransferRepository extends JpaRepository, - JpaSpecificationExecutor, PagingAndSortingRepository { - - // Derived Query - using method naming convention - get all Transfer by paymentOptionId - List findByPaymentOptionId(Long paymentOptionId); + JpaSpecificationExecutor { @Modifying - @Query("update Transfer tr set tr.newIban = :newIban, tr.lastUpdatedDate = :currentDate where tr.payment_option_id=:paymentOptionId and tr.iban=:oldIban") - int updateTransferIban(@Param(value="paymentOptionId") Long paymentOptionId, @Param(value = "oldIban") String oldIban, @Param(value = "newIban") String newIban, @Param(value = "currentDate") LocalDateTime currentDate); + @Query("update Transfer tr set tr.iban = :newIban, tr.lastUpdatedDate = :currentDate where tr.paymentOption in (:paymentOptionList) and tr.iban=:oldIban") + int updateTransferIban(@Param(value="paymentOptionList") List paymentOptionList, @Param(value = "oldIban") String oldIban, @Param(value = "newIban") String newIban, @Param(value = "currentDate") LocalDateTime currentDate); } diff --git a/src/main/java/it/gov/pagopa/debtposition/service/payments/PaymentsService.java b/src/main/java/it/gov/pagopa/debtposition/service/payments/PaymentsService.java index 830525e2..063d3602 100644 --- a/src/main/java/it/gov/pagopa/debtposition/service/payments/PaymentsService.java +++ b/src/main/java/it/gov/pagopa/debtposition/service/payments/PaymentsService.java @@ -1,23 +1,5 @@ package it.gov.pagopa.debtposition.service.payments; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Optional; - -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -import it.gov.pagopa.debtposition.repository.TransferRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import feign.FeignException; import it.gov.pagopa.debtposition.client.NodeClient; import it.gov.pagopa.debtposition.entity.PaymentOption; @@ -35,8 +17,24 @@ import it.gov.pagopa.debtposition.model.payments.PaymentOptionModel; import it.gov.pagopa.debtposition.repository.PaymentOptionRepository; import it.gov.pagopa.debtposition.repository.PaymentPositionRepository; +import it.gov.pagopa.debtposition.repository.TransferRepository; import it.gov.pagopa.debtposition.util.DebtPositionValidation; 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.springframework.transaction.annotation.Transactional; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; @Service @@ -57,7 +55,6 @@ public PaymentsService(PaymentPositionRepository paymentPositionRepository, Paym } - @Value("${nav.aux.digit}") private String auxDigit; @@ -85,7 +82,7 @@ public PaymentOption getPaymentOptionByNAV(@NotBlank String organizationFiscalCo public PaymentOption pay(@NotBlank String organizationFiscalCode, @NotBlank String nav, @NotNull @Valid PaymentOptionModel paymentOptionModel) { Optional ppToPay = paymentPositionRepository. - findByPaymentOptionOrganizationFiscalCodeAndPaymentOptionIuvOrPaymentOptionOrganizationFiscalCodeAndPaymentOptionNav(organizationFiscalCode, nav, organizationFiscalCode, nav); + findByPaymentOptionOrganizationFiscalCodeAndPaymentOptionIuvOrPaymentOptionOrganizationFiscalCodeAndPaymentOptionNav(organizationFiscalCode, nav, organizationFiscalCode, nav); if (ppToPay.isEmpty()) { throw new AppException(AppError.PAYMENT_OPTION_NOT_FOUND, organizationFiscalCode, nav); @@ -120,7 +117,7 @@ public Transfer report(@NotBlank String organizationFiscalCode, public PaymentOption updateNotificationFee(@NotBlank String organizationFiscalCode, @NotBlank String nav, Long notificationFeeAmount) { // Check if exists a payment option with the passed IUV related to the organization - // TODO #naviuv: temporary regression management: search by nav or iuv + // TODO #naviuv: temporary regression management: search by nav or iuv Optional paymentOptionOpt = paymentOptionRepository.findByOrganizationFiscalCodeAndIuvOrOrganizationFiscalCodeAndNav(organizationFiscalCode, nav, organizationFiscalCode, nav); if (paymentOptionOpt.isEmpty()) { throw new AppException(AppError.PAYMENT_OPTION_NOT_FOUND, organizationFiscalCode, nav); @@ -130,33 +127,32 @@ public PaymentOption updateNotificationFee(@NotBlank String organizationFiscalCo if (!PaymentOptionStatus.PO_UNPAID.equals(paymentOption.getStatus())) { throw new AppException(AppError.PAYMENT_OPTION_NOTIFICATION_FEE_UPDATE_NOT_UPDATABLE, organizationFiscalCode, nav); } - + // Executing the amount updating with the inserted notification fee updateAmountsWithNotificationFee(paymentOption, organizationFiscalCode, notificationFeeAmount); - + // Executes a call to the node's checkPosition API to see if there is a payment in progress try { - // TODO #naviuv: temporary regression management: search by nav or iuv --> possible double call to the node + // TODO #naviuv: temporary regression management: search by nav or iuv --> possible double call to the node // 1. first call attempt is with the nav variable valued as iuv (auxDigit added) - NodePosition position = NodePosition.builder().fiscalCode(organizationFiscalCode).noticeNumber(auxDigit+nav).build(); - NodeCheckPositionResponse chkPositionRes = - nodeClient.getCheckPosition(NodeCheckPositionModel.builder().positionslist(Collections.singletonList(position)).build()); - paymentOption.setPaymentInProgress("OK".equalsIgnoreCase(chkPositionRes.getOutcome())?Boolean.FALSE:Boolean.TRUE); + NodePosition position = NodePosition.builder().fiscalCode(organizationFiscalCode).noticeNumber(auxDigit + nav).build(); + NodeCheckPositionResponse chkPositionRes = + nodeClient.getCheckPosition(NodeCheckPositionModel.builder().positionslist(Collections.singletonList(position)).build()); + paymentOption.setPaymentInProgress("OK".equalsIgnoreCase(chkPositionRes.getOutcome()) ? Boolean.FALSE : Boolean.TRUE); } catch (FeignException.BadRequest e) { - // 2. if the first call fails with a bad request error --> try with a nav call - NodePosition position = NodePosition.builder().fiscalCode(organizationFiscalCode).noticeNumber(nav).build(); - try { - NodeCheckPositionResponse chkPositionRes = - nodeClient.getCheckPosition(NodeCheckPositionModel.builder().positionslist(Collections.singletonList(position)).build()); - paymentOption.setPaymentInProgress("OK".equalsIgnoreCase(chkPositionRes.getOutcome())?Boolean.FALSE:Boolean.TRUE); - } catch (Exception ex) { - log.error("Error checking the position on the node for PO with fiscalCode " + organizationFiscalCode + " and noticeNumber " + "("+auxDigit+")"+nav, ex); + // 2. if the first call fails with a bad request error --> try with a nav call + NodePosition position = NodePosition.builder().fiscalCode(organizationFiscalCode).noticeNumber(nav).build(); + try { + NodeCheckPositionResponse chkPositionRes = + nodeClient.getCheckPosition(NodeCheckPositionModel.builder().positionslist(Collections.singletonList(position)).build()); + paymentOption.setPaymentInProgress("OK".equalsIgnoreCase(chkPositionRes.getOutcome()) ? Boolean.FALSE : Boolean.TRUE); + } catch (Exception ex) { + log.error("Error checking the position on the node for PO with fiscalCode " + organizationFiscalCode + " and noticeNumber " + "(" + auxDigit + ")" + nav, ex); // By business rules it is expected to treat the error as if the node had responded KO paymentOption.setPaymentInProgress(Boolean.TRUE); } - } - catch (Exception e) { - log.error("Error checking the position on the node for PO with fiscalCode " + organizationFiscalCode + " and noticeNumber " + "("+auxDigit+")"+nav, e); + } catch (Exception e) { + log.error("Error checking the position on the node for PO with fiscalCode " + organizationFiscalCode + " and noticeNumber " + "(" + auxDigit + ")" + nav, e); // By business rules it is expected to treat the error as if the node had responded KO paymentOption.setPaymentInProgress(Boolean.TRUE); } @@ -321,23 +317,19 @@ private void setPaymentPositionStatus(PaymentPosition pp) { } // Update all Organization's IBANs on Transfer of payable PaymentPosition + @Transactional public int updateTransferIbanMassive(String organizationFiscalCode, String oldIban, String newIban) { int numberOfUpdates = 0; // Retrieve all payment_position with organization_fiscal_code AND in status (DRAFT or PUBLISHED or VALID or PARTIALLY_PAID) List ppToUpdate = paymentPositionRepository.findByOrganizationFiscalCodeAndStatusIn(organizationFiscalCode, List.of(DebtPositionStatus.DRAFT, DebtPositionStatus.PUBLISHED, DebtPositionStatus.VALID, DebtPositionStatus.PARTIALLY_PAID)); - if (ppToUpdate.isEmpty()) { throw new AppException(AppError.DEBT_POSITION_IN_UPDATABLE_STATE_NOT_FOUND, organizationFiscalCode); } - for (PaymentPosition pp : ppToUpdate) { - // Retrieve all payment_option with payment_position_id AND in status PO_UNPAID - List poToUpdate = paymentOptionRepository.findByPaymentPositionIdAndStatusIn(pp.getId(), List.of(PaymentOptionStatus.PO_UNPAID)); + // Retrieve all payment_option with payment_position_id AND in status PO_UNPAID + List poToUpdate = paymentOptionRepository.findByPaymentPositionInAndStatusIn(ppToUpdate, List.of(PaymentOptionStatus.PO_UNPAID)); - for (PaymentOption po : poToUpdate) { - // Update all Transfers that have the specified payment_option_id and oldIban as IBAN - numberOfUpdates += transferRepository.updateTransferIban(po.getId(), oldIban, newIban, LocalDateTime.now(ZoneOffset.UTC)); - } - } + // Update all Transfers that have the specified payment_option_id and oldIban as IBAN + numberOfUpdates += transferRepository.updateTransferIban(poToUpdate, oldIban, newIban, LocalDateTime.now(ZoneOffset.UTC)); return numberOfUpdates; }