This is an automated email from the ASF dual-hosted git repository.
arnold 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 a987956cb FINERACT-1785: Allow to add charge (penalty) with same
disbursement date
a987956cb is described below
commit a987956cbc5ceb3e26752379901bb99decab6d0a
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Fri Dec 9 09:03:09 2022 -0600
FINERACT-1785: Allow to add charge (penalty) with same disbursement date
---
.../portfolio/loanaccount/domain/LoanCharge.java | 11 ----
.../LoanRepaymentScheduleProcessingWrapper.java | 6 +-
...paymentScheduleTransactionProcessorFactory.java | 2 -
.../LoanChargeSpecificDueDateTest.java | 71 ++++++++++++++++++++--
.../common/loans/LoanTransactionHelper.java | 7 +++
5 files changed, 76 insertions(+), 21 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
index 3c5ddf8ae..3ab6dbb79 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
@@ -632,17 +632,6 @@ public class LoanCharge extends AbstractPersistableCustom {
return target != null && target.isAfter(fromNotInclusive) &&
!target.isAfter(upToAndInclusive);
}
- public boolean isDueForCollectionFromIncludingAndUpToAndIncluding(final
LocalDate fromNotInclusive, final LocalDate upToAndInclusive) {
- final LocalDate dueDate = getDueLocalDate();
- return
occursOnDayFromAndIncludingAndUpToAndIncluding(fromNotInclusive,
upToAndInclusive, dueDate);
- }
-
- private boolean occursOnDayFromAndIncludingAndUpToAndIncluding(final
LocalDate fromAndInclusive, final LocalDate upToAndInclusive,
- final LocalDate target) {
- return target != null && (target.isEqual(fromAndInclusive) ||
target.isAfter(fromAndInclusive))
- && !target.isAfter(upToAndInclusive);
- }
-
public boolean isFeeCharge() {
return !this.penaltyCharge;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
index 72fec14af..fb7f80f20 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleProcessingWrapper.java
@@ -119,8 +119,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
} else if
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
cumulative = cumulative.plus(loanCharge.amount());
// Special case for Loan Charges (Due Date) added the same
disbursement date
- } else if (period.isFirstPeriod()
- &&
loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(periodStart,
periodEnd)) {
+ } else if (period.isFirstPeriod() &&
periodStart.equals(loanCharge.getDueDate())) {
cumulative = cumulative.plus(loanCharge.amount());
}
}
@@ -213,6 +212,9 @@ public class LoanRepaymentScheduleProcessingWrapper {
cumulative = cumulative.plus(loanChargeAmt);
} else if
(loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
cumulative = cumulative.plus(loanCharge.amount());
+ // Special case for Loan Charges (Due Date) added the same
disbursement date
+ } else if (period.isFirstPeriod() &&
periodStart.equals(loanCharge.getDueDate())) {
+ cumulative = cumulative.plus(loanCharge.amount());
}
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
index 08afe83fb..06d7be483 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleTransactionProcessorFactory.java
@@ -21,13 +21,11 @@ package org.apache.fineract.portfolio.loanaccount.domain;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
import
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import
org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
import
org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.springframework.beans.factory.annotation.Value;
-@Slf4j
@RequiredArgsConstructor
public class LoanRepaymentScheduleTransactionProcessorFactory {
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
index 571dd834d..7f0dcbeca 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeSpecificDueDateTest.java
@@ -62,7 +62,7 @@ public class LoanChargeSpecificDueDateTest {
}
@Test
- public void testApplyLoanSpecificDueDateChargeWithDisbursementDate() {
+ public void testApplyLoanSpecificDueDateFeeWithDisbursementDate() {
final LocalDate todaysDate = Utils.getLocalDateOfTenant();
@@ -82,7 +82,7 @@ public class LoanChargeSpecificDueDateTest {
// Get loan details
GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
- validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("0.00"));
+ validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("0.00"), false);
// Apply Loan Charge with specific due date
@@ -99,7 +99,7 @@ public class LoanChargeSpecificDueDateTest {
// Get loan details expecting to have a delinquency classification
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
- validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("10.00"));
+ validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("10.00"), false);
// Make a full repayment to close the Loan
Float amount = Float.valueOf("1010.00");
@@ -110,7 +110,62 @@ public class LoanChargeSpecificDueDateTest {
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
assertNotNull(getLoansLoanIdResponse);
- validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"),
Double.valueOf("0.00"));
+ validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"),
Double.valueOf("0.00"), false);
+
+ }
+
+ @Test
+ public void testApplyLoanSpecificDueDatePenaltyWithDisbursementDate() {
+
+ final LocalDate todaysDate = Utils.getLocalDateOfTenant();
+
+ // Client and Loan account creation
+ final Integer clientId = ClientHelper.createClient(this.requestSpec,
this.responseSpec, "01 January 2012");
+ final GetLoanProductsProductIdResponse getLoanProductsProductResponse
= createLoanProduct(loanTransactionHelper, null);
+ assertNotNull(getLoanProductsProductResponse);
+
+ // Older date to have more than one overdue installment
+ LocalDate transactionDate = todaysDate;
+ String operationDate = Utils.dateFormatter.format(transactionDate);
+ log.info("Operation date {}", transactionDate);
+
+ // Create Loan Account
+ final Integer loanId = createLoanAccount(loanTransactionHelper,
clientId.toString(),
+ getLoanProductsProductResponse.getId().toString(),
operationDate);
+
+ // Get loan details
+ GetLoansLoanIdResponse getLoansLoanIdResponse =
loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
+ validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("0.00"), true);
+
+ // Apply Loan Charge with specific due date
+
+ final String feeAmount = "10.00";
+ String payloadJSON =
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
feeAmount, true);
+ final PostChargesResponse postChargesResponse =
ChargesHelper.createLoanCharge(requestSpec, responseSpec, payloadJSON);
+ assertNotNull(postChargesResponse);
+ final Long loanChargeId = postChargesResponse.getResourceId();
+ assertNotNull(loanChargeId);
+
+ payloadJSON =
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(loanChargeId.toString(),
operationDate, feeAmount);
+ PostLoansLoanIdChargesResponse postLoansLoanIdChargesResponse =
loanTransactionHelper.addChargeForLoan(loanId, payloadJSON,
+ responseSpec);
+ assertNotNull(postLoansLoanIdChargesResponse);
+
+ // Get loan details expecting to have a delinquency classification
+ getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
+ validateLoanAccount(getLoansLoanIdResponse,
Double.valueOf(principalAmount), Double.valueOf("10.00"), true);
+
+ // Make a full repayment to close the Loan
+ Float amount = Float.valueOf("1010.00");
+ PostLoansLoanIdTransactionsResponse loanIdTransactionsResponse =
loanTransactionHelper.makeLoanRepayment(operationDate, amount,
+ loanId);
+ assertNotNull(loanIdTransactionsResponse);
+ log.info("Loan Transaction Id: {} {}", loanId,
loanIdTransactionsResponse.getResourceId());
+
+ getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec,
responseSpec, loanId);
+ assertNotNull(getLoansLoanIdResponse);
+ validateLoanAccount(getLoansLoanIdResponse, Double.valueOf("0.00"),
Double.valueOf("0.00"), true);
+ loanTransactionHelper.validateLoanStatus(getLoansLoanIdResponse,
"loanStatusType.closed.obligations.met");
}
@@ -137,11 +192,15 @@ public class LoanChargeSpecificDueDateTest {
return loanId;
}
- private void validateLoanAccount(GetLoansLoanIdResponse
getLoansLoanIdResponse, Double principal, Double fees) {
+ private void validateLoanAccount(GetLoansLoanIdResponse
getLoansLoanIdResponse, Double principal, Double fees, boolean isPenalty) {
assertNotNull(getLoansLoanIdResponse);
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
loanTransactionHelper.validateLoanPrincipalOustandingBalance(getLoansLoanIdResponse,
principal);
-
loanTransactionHelper.validateLoanFeesOustandingBalance(getLoansLoanIdResponse,
fees);
+ if (isPenalty) {
+
loanTransactionHelper.validateLoanPenaltiesOustandingBalance(getLoansLoanIdResponse,
fees);
+ } else {
+
loanTransactionHelper.validateLoanFeesOustandingBalance(getLoansLoanIdResponse,
fees);
+ }
loanTransactionHelper.validateLoanTotalOustandingBalance(getLoansLoanIdResponse,
(principal + fees));
}
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 1eba90212..f2f079129 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
@@ -1563,6 +1563,13 @@ public class LoanTransactionHelper extends
IntegrationTest {
}
}
+ public void validateLoanPenaltiesOustandingBalance(GetLoansLoanIdResponse
getLoansLoanIdResponse, Double amountExpected) {
+ GetLoansLoanIdSummary getLoansLoanIdSummary =
getLoansLoanIdResponse.getSummary();
+ assertNotNull(getLoansLoanIdSummary);
+ log.info("Loan with Fees Outstanding Balance {} expected {}",
getLoansLoanIdSummary.getFeeChargesOutstanding(), amountExpected);
+ assertEquals(amountExpected,
getLoansLoanIdSummary.getPenaltyChargesOutstanding());
+ }
+
public void validateLoanTotalOustandingBalance(GetLoansLoanIdResponse
getLoansLoanIdResponse, Double amountExpected) {
GetLoansLoanIdSummary getLoansLoanIdSummary =
getLoansLoanIdResponse.getSummary();
if (getLoansLoanIdSummary != null) {