You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ad...@apache.org on 2023/01/19 13:06:29 UTC
[fineract] branch develop updated: FINERACT-1847: Removing Edit function from Goodwill Credit or Payout Refund or Merchant Issued Refund transactions on API level
This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 6d3cac8c0 FINERACT-1847: Removing Edit function from Goodwill Credit or Payout Refund or Merchant Issued Refund transactions on API level
6d3cac8c0 is described below
commit 6d3cac8c02b5846703f6c0d07fe28b0ba501b232
Author: Jose Alberto Hernandez <al...@MacBook-Pro.local>
AuthorDate: Mon Jan 2 15:37:46 2023 -0600
FINERACT-1847: Removing Edit function from Goodwill Credit or Payout Refund or Merchant Issued Refund transactions on API level
---
.../loanaccount/domain/LoanTransaction.java | 4 +
.../LoanRepaymentAdjustmentCommandHandler.java | 1 -
.../LoanWritePlatformServiceJpaRepositoryImpl.java | 14 +-
...lanceRefundandRepaymentTypeIntegrationTest.java | 141 +++++++++++++++++++++
.../LoanTransactionChargebackTest.java | 23 +++-
.../common/loans/LoanTransactionHelper.java | 29 ++++-
6 files changed, 197 insertions(+), 15 deletions(-)
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index c95fd3710..9a0fbcc60 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -651,6 +651,10 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
return getTypeOf().isChargeback() && isNotReversed();
}
+ public boolean isEditable() {
+ return !(isChargeback() || isGoodwillCredit() || isPayoutRefund() || isMerchantIssuedRefund());
+ }
+
public boolean isPenaltyPayment() {
boolean isPenalty = false;
if (isChargePayment()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentAdjustmentCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentAdjustmentCommandHandler.java
index e04e9bf6f..3e313f152 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentAdjustmentCommandHandler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/LoanRepaymentAdjustmentCommandHandler.java
@@ -37,7 +37,6 @@ public class LoanRepaymentAdjustmentCommandHandler implements NewCommandSourceHa
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
-
return this.writePlatformService.adjustLoanTransaction(command.getLoanId(), command.entityId(), command);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 31139afe4..5b0aca276 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -163,6 +163,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepositor
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException;
import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
+import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanForeclosureException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanMultiDisbursementException;
@@ -1066,16 +1067,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
transactionId);
}
- if (transactionToAdjust.isChargeback()) {
- throw new PlatformServiceUnavailableException("error.msg.loan.transaction.update.not.allowed", "Loan transaction:"
- + transactionId + " update not allowed as loan transaction is charge back and is linked to other transaction",
- transactionId);
- }
-
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final ExternalId txnExternalId = externalIdFactory.createFromCommand(command, LoanApiConstants.externalIdParameterName);
+ final boolean isAdjustCommand = (transactionAmount.compareTo(BigDecimal.ZERO) > 0);
+ if (isAdjustCommand && !transactionToAdjust.isEditable()) {
+ final String errorMessage = "Loan transaction: " + transactionId + " update not allowed as loan transaction is a "
+ + transactionToAdjust.getTypeOf().getCode();
+ throw new InvalidLoanTransactionTypeException("transaction", "error.msg.loan.transaction.update.not.allowed", errorMessage);
+ }
+
// We dont need auto generation for reversal external id... if it is not provided, it remains null (empty)
final String reversalExternalId = command.stringValueOfParameterNamedAllowingNull(LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME);
final ExternalId reversalTxnExternalId = ExternalIdFactory.produce(reversalExternalId);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
index 45091e9f4..1feb1c1c7 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java
@@ -27,6 +27,7 @@ import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.util.ArrayList;
import java.util.HashMap;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CommonConstants;
import org.apache.fineract.integrationtests.common.Utils;
@@ -50,6 +51,7 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
private static final Logger LOG = LoggerFactory.getLogger(ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.class);
private ResponseSpecification responseSpec;
+ private ResponseSpecification responseSpec403;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private LoanTransactionHelper loanTransactionHelperValidationError;
@@ -73,6 +75,7 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+ this.responseSpec403 = new ResponseSpecBuilder().expectStatusCode(403).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.loanTransactionHelperValidationError = new LoanTransactionHelper(this.requestSpec, new ResponseSpecBuilder().build());
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
@@ -438,4 +441,142 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest {
}
+ @Test
+ public void undoGoodWillCreditTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(GOODWILL_CREDIT,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.reverseLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec);
+ }
+
+ @Test
+ public void undoPayoutRefundTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(PAYOUT_REFUND,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.reverseLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec);
+ }
+
+ @Test
+ public void undoMerchantIssuedRefundTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(MERCHANT_ISSUED_REFUND,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.reverseLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec);
+ }
+
+ @Test
+ public void adjustGoodWillCreditTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(GOODWILL_CREDIT,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.adjustLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec403);
+ }
+
+ @Test
+ public void adjustPayoutRefundTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(PAYOUT_REFUND,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.adjustLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec403);
+ }
+
+ @Test
+ public void adjustMerchantIssuedRefundTransactionTest() {
+ // Given
+ disburseLoanOfAccountingRule(CASH_BASED);
+ HashMap loanSummaryMap = this.loanTransactionHelper.getLoanSummary(this.requestSpec, this.responseSpec, disbursedLoanID);
+
+ // pay off all of principal, interest (no fees or penalties)
+ final Float principalOutstanding = (Float) loanSummaryMap.get("principalOutstanding");
+ final Float interestOutstanding = (Float) loanSummaryMap.get("interestOutstanding");
+ final Float totalOutstanding = (Float) loanSummaryMap.get("totalOutstanding");
+ final Float overpaidAmount = 159.00f;
+ final Float transactionAmount = totalOutstanding + overpaidAmount;
+ final String transactionDate = "09 January 2022";
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(MERCHANT_ISSUED_REFUND,
+ transactionDate, transactionAmount, this.disbursedLoanID);
+ Assertions.assertNotNull(loanTransactionResponse);
+ Assertions.assertNotNull(loanTransactionResponse.getResourceId());
+
+ // Then
+ loanTransactionHelper.adjustLoanTransaction(this.disbursedLoanID, loanTransactionResponse.getResourceId(), transactionDate,
+ responseSpec403);
+ }
+
}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java
index 7a15c9453..b5bbdfa6d 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java
@@ -57,6 +57,7 @@ public class LoanTransactionChargebackTest {
private ResponseSpecification responseSpec;
private ResponseSpecification responseSpecErr400;
+ private ResponseSpecification responseSpecErr403;
private ResponseSpecification responseSpecErr503;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
@@ -71,6 +72,7 @@ public class LoanTransactionChargebackTest {
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.responseSpecErr400 = new ResponseSpecBuilder().expectStatusCode(400).build();
+ this.responseSpecErr403 = new ResponseSpecBuilder().expectStatusCode(403).build();
this.responseSpecErr503 = new ResponseSpecBuilder().expectStatusCode(503).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
@@ -114,12 +116,30 @@ public class LoanTransactionChargebackTest {
// Try to reverse a Loan Transaction charge back
PostLoansLoanIdTransactionsResponse reverseTransactionResponse = loanTransactionHelper.reverseLoanTransaction(loanId,
- chargebackTransactionId, operationDate, responseSpecErr503);
+ chargebackTransactionId, operationDate, responseSpecErr403);
// Try to reverse a Loan Transaction repayment with linked transactions
reverseTransactionResponse = loanTransactionHelper.reverseLoanTransaction(loanId, transactionId, operationDate, responseSpecErr503);
}
+ @Test
+ public void applyAndAdjustLoanTransactionChargeback() {
+ // Client and Loan account creation
+ final Integer loanId = createAccounts(15, 1);
+
+ Float amount = Float.valueOf(amountVal);
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse = loanTransactionHelper.makeLoanRepayment(operationDate, amount,
+ loanId);
+ assertNotNull(loanTransactionResponse);
+ final Long transactionId = loanTransactionResponse.getResourceId();
+
+ final Long chargebackTransactionId = loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "1000.00", 0,
+ responseSpec);
+
+ // Then
+ loanTransactionHelper.adjustLoanTransaction(loanId, chargebackTransactionId, operationDate, responseSpecErr403);
+ }
+
@Test
public void applyLoanTransactionChargebackWithAmountZero() {
// Client and Loan account creation
@@ -141,7 +161,6 @@ public class LoanTransactionChargebackTest {
loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse, "loanStatusType.closed.obligations.met");
loanTransactionHelper.applyChargebackTransaction(loanId, transactionId, "0.00", 0, responseSpecErr400);
-
}
@Test
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
index c2ee76342..cb3ba3993 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
@@ -504,7 +504,14 @@ public class LoanTransactionHelper extends IntegrationTest {
}
public HashMap reverseRepayment(final Integer loanId, final Integer transactionId, String date) {
- return (HashMap) performLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId), getUndoJsonBody(date), "");
+ return (HashMap) performLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId),
+ getAdjustTransactionJsonBody(date, "0"), "");
+ }
+
+ public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final String repaymentTypeCommand, final String date,
+ final Float amountToBePaid, final Integer loanID) {
+ log.info("Repayment with amount {} in {} for Loan {}", amountToBePaid, date, loanID);
+ return postLoanTransaction(createLoanTransactionURL(repaymentTypeCommand, loanID), getRepaymentBodyAsJSON(date, amountToBePaid));
}
public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final String date, final Float amountToBePaid, final Integer loanID) {
@@ -701,9 +708,16 @@ public class LoanTransactionHelper extends IntegrationTest {
return ok(fineract().loanTransactions.adjustLoanTransaction1(loanId, transactionExternalId, request, "adjust"));
}
+ public PostLoansLoanIdTransactionsResponse adjustLoanTransaction(final Integer loanId, final Long transactionId, String date,
+ ResponseSpecification responseSpec) {
+ return postLoanTransaction(createLoanTransactionURL(null, loanId, transactionId.intValue()),
+ getAdjustTransactionJsonBody(date, "10"), responseSpec);
+ }
+
public PostLoansLoanIdTransactionsResponse reverseLoanTransaction(final Integer loanId, final Long transactionId, String date,
ResponseSpecification responseSpec) {
- return postLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId.intValue()), getUndoJsonBody(date), responseSpec);
+ return postLoanTransaction(createLoanTransactionURL(UNDO, loanId, transactionId.intValue()),
+ getAdjustTransactionJsonBody(date, "0"), responseSpec);
}
public PostLoansLoanIdTransactionsResponse reverseLoanTransaction(final Long loanId, final Long transactionId,
@@ -1074,10 +1088,10 @@ public class LoanTransactionHelper extends IntegrationTest {
return new Gson().toJson(map);
}
- private String getUndoJsonBody(String date) {
+ private String getAdjustTransactionJsonBody(String date, String amount) {
final HashMap<String, String> map = new HashMap<>();
map.put("transactionDate", date);
- map.put("transactionAmount", "0");
+ map.put("transactionAmount", amount);
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en");
return new Gson().toJson(map);
@@ -1257,8 +1271,11 @@ public class LoanTransactionHelper extends IntegrationTest {
}
private String createLoanTransactionURL(final String command, final Integer loanID, final Integer transactionId) {
- return "/fineract-provider/api/v1/loans/" + loanID + "/transactions/" + transactionId + "?command=" + command + "&"
- + Utils.TENANT_IDENTIFIER;
+ String url = "/fineract-provider/api/v1/loans/" + loanID + "/transactions/" + transactionId + "?";
+ if (command != null) {
+ url = url + "command=" + command + "&";
+ }
+ return url + Utils.TENANT_IDENTIFIER;
}
private String createGlimAccountURL(final String command, final Integer glimID) {