Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PIDM-42] fix(payment-status): payment position/option status not coherent #289

Merged
merged 11 commits into from
Feb 5, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import it.gov.pagopa.debtposition.entity.PaymentOption;
import it.gov.pagopa.debtposition.entity.PaymentPosition;
import it.gov.pagopa.debtposition.exception.AppError;
import it.gov.pagopa.debtposition.exception.AppException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.EnumSet;
Expand Down Expand Up @@ -93,4 +95,24 @@ public static PaymentPosition expirationCheckAndUpdate(PaymentOption po) {
}
return pp;
}

/**
* Checks if the user is trying to pay the full amount for the payment position but there is an
* installment already paid, in which case
*
* @param paymentOptionToPay the payment option being paid
* @param nav the identifier of the notice being paid
*/
public static void checkAlreadyPaidInstallments(PaymentOption paymentOptionToPay, String nav) {

PaymentPosition paymentPosition = paymentOptionToPay.getPaymentPosition();
if (Boolean.FALSE.equals(paymentOptionToPay.getIsPartialPayment())
&& paymentPosition.getStatus().equals(DebtPositionStatus.PARTIALLY_PAID)) {

throw new AppException(
AppError.PAYMENT_OPTION_ALREADY_PAID,
paymentOptionToPay.getOrganizationFiscalCode(),
nav);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import javax.validation.Valid;
Expand Down Expand Up @@ -69,6 +70,7 @@ public PaymentOption getPaymentOptionByNAV(@NotBlank String organizationFiscalCo
// PaymentPosition used when converting PaymentOption to POWithDebtor
DebtPositionStatus.validityCheckAndUpdate(paymentOption);
DebtPositionStatus.expirationCheckAndUpdate(paymentOption);
DebtPositionStatus.checkAlreadyPaidInstallments(paymentOption, nav);

return paymentOption;
}
Expand Down Expand Up @@ -233,7 +235,10 @@ private PaymentOption updatePaymentStatus(PaymentPosition pp, String nav, Paymen
}

// aggiorno lo stato della payment position
if (countPaidPartialPayment > 0 && countPaidPartialPayment < numberOfPartialPayment) {
// PIDM-42 if paying the full amount when there is already a paid partial payment
// then update the payment position status to PAID
if (countPaidPartialPayment > 0 && countPaidPartialPayment < numberOfPartialPayment
&& Boolean.TRUE.equals(Objects.requireNonNull(poToPay).getIsPartialPayment())) {
pp.setStatus(DebtPositionStatus.PARTIALLY_PAID);
} else {
pp.setStatus(DebtPositionStatus.PAID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,31 @@

// La posizione debitoria è già in PARTIALLY_PAID ed arriva una richiesta di pagamento su una
// payment option non rateizzata (isPartialPayment = false) => errore
// PIDM-42: if this is a full payment and the position is partially paid then
// log this but allow the payment option status to be changed to PO_PAID instead of throwing an
// error
// NOTE: the exception handling has been moved to the get/activate validation
// (checkAlreadyPaidInstallments)
if (ppToPay.getStatus().equals(DebtPositionStatus.PARTIALLY_PAID)
&& Boolean.FALSE.equals(poToPay.getIsPartialPayment())) {
throw new AppException(
AppError.PAYMENT_OPTION_ALREADY_PAID, poToPay.getOrganizationFiscalCode(), nav);

// log detailed information about this edge case
log.warn(
"Potential payment state inconsistency detected || "
+ "Organization: {} || "
+ "IUPD: {} || "
+ "NAV: {} || "
+ "Position Status: {} || "
+ "Payment Option Status: {} || "
+ "Is Partial Payment: {} || "
+ "Timestamp: {}",
ppToPay.getOrganizationFiscalCode(),
ppToPay.getIupd(),
nav,
ppToPay.getStatus(),
poToPay.getStatus(),
poToPay.getIsPartialPayment(),
LocalDateTime.now());
Comment on lines +282 to +297

Check failure

Code scanning / CodeQL

Log Injection High

This log entry depends on a
user-provided value
.

Copilot Autofix AI about 1 month ago

To fix the log injection issue, we need to sanitize the nav parameter before logging it. The best way to do this is to remove any potentially harmful characters from the nav parameter, such as new-line characters, which can be used to forge log entries. We can use a utility method to sanitize the input by replacing or removing such characters.

  1. Create a utility method to sanitize the nav parameter by removing new-line characters and other potentially harmful characters.
  2. Use this utility method to sanitize the nav parameter before logging it in the DebtPositionValidation class.
Suggested changeset 1
src/main/java/it/gov/pagopa/debtposition/util/DebtPositionValidation.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/it/gov/pagopa/debtposition/util/DebtPositionValidation.java b/src/main/java/it/gov/pagopa/debtposition/util/DebtPositionValidation.java
--- a/src/main/java/it/gov/pagopa/debtposition/util/DebtPositionValidation.java
+++ b/src/main/java/it/gov/pagopa/debtposition/util/DebtPositionValidation.java
@@ -25,2 +25,3 @@
 import org.apache.logging.log4j.util.Strings;
+import org.apache.commons.lang3.StringUtils;
 
@@ -29,2 +30,9 @@
 
+  private static String sanitize(String input) {
+    if (input == null) {
+      return null;
+    }
+    return StringUtils.replaceChars(input, "\n\r", "");
+  }
+
   private static final String LOG_BASE_PARAMS_DETAIL =
@@ -281,2 +289,3 @@
       // log detailed information about this edge case
+      String sanitizedNav = sanitize(nav);
       log.warn(
@@ -292,3 +301,3 @@
           ppToPay.getIupd(),
-          nav,
+          sanitizedNav,
           ppToPay.getStatus(),
EOF
@@ -25,2 +25,3 @@
import org.apache.logging.log4j.util.Strings;
import org.apache.commons.lang3.StringUtils;

@@ -29,2 +30,9 @@

private static String sanitize(String input) {
if (input == null) {
return null;
}
return StringUtils.replaceChars(input, "\n\r", "");
}

private static final String LOG_BASE_PARAMS_DETAIL =
@@ -281,2 +289,3 @@
// log detailed information about this edge case
String sanitizedNav = sanitize(nav);
log.warn(
@@ -292,3 +301,3 @@
ppToPay.getIupd(),
nav,
sanitizedNav,
ppToPay.getStatus(),
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ void payPaymentOption_Multiple_Partial_409() throws Exception {
}

@Test
void payPaymentOption_Multiple_Partial2_409() throws Exception {
void getPaymentOption_Multiple_Partial_409() throws Exception {
// creo una posizione debitoria (senza 'validity date' impostata e nav non valorizzato) con più
// opzioni di pagamento
mvc.perform(
Expand Down Expand Up @@ -652,13 +652,12 @@ void payPaymentOption_Multiple_Partial2_409() throws Exception {
MockMvcResultMatchers.jsonPath("$.status")
.value(DebtPositionStatus.PARTIALLY_PAID.toString()));

// effettuo un nuovo pagamento sulla payment option non rateizzabile (isPartialPayment = false)
// e ottengo errore
// effettuo una GET/ACTIVATE sulla payment option corrispondente alla rata unica/intero importo
// e ottengo errore 409
mvc.perform(
post("/organizations/PAY_Multiple_Partial2_409_12345678901/paymentoptions/"
+ auxDigit
+ "123456IUVMULTIPLEMOCK3/pay")
.content(TestUtil.toJson(DebtPositionMock.getPayPOMock1()))
get("/organizations/PAY_Multiple_Partial2_409_12345678901/paymentoptions/"
+ auxDigit
+ "123456IUVMULTIPLEMOCK3")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isConflict());
}
Expand Down
Loading