From 58127c1c8f1a33bcc2fdd43eb860e5800cdda863 Mon Sep 17 00:00:00 2001 From: Ruchi Dhamankar Date: Mon, 18 Sep 2023 15:04:02 +0530 Subject: [PATCH] FINERACT-1958-disbursement-period-order-backdated-disbursement --- .../service/LoanReadPlatformServiceImpl.java | 2 +- .../LoanAccountBackdatedDisbursementTest.java | 200 ++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 891d2bcd096..9ddf349e37c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -1706,7 +1706,7 @@ public Integer retriveLoanCounter(final Long clientId, Long productId) { public Collection retrieveLoanDisbursementDetails(final Long loanId) { final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper(sqlGenerator); final String sql = "select " + rm.schema() - + " where dd.loan_id=? and dd.is_reversed=false group by dd.id, lc.amount_waived_derived order by dd.expected_disburse_date"; + + " where dd.loan_id=? and dd.is_reversed=false group by dd.id, lc.amount_waived_derived order by dd.expected_disburse_date,dd.disbursedon_date"; return this.jdbcTemplate.query(sql, rm, loanId); // NOSONAR } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java index 9390f7d8621..aef6bd14c87 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountBackdatedDisbursementTest.java @@ -43,10 +43,13 @@ import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +@ExtendWith(LoanTestLifecycleExtension.class) public class LoanAccountBackdatedDisbursementTest { private ResponseSpecification responseSpec; @@ -793,6 +796,203 @@ public void loanAccountBackDatedDisbursementWithDisbursementDateBeforeLoanSubmit } + @Test + public void loanAccountBackDatedDisbursementForLoanProductWithDisableDownPaymentAndScheduleStartDateTypeAsDisbursementDate_DisbursementPeriodsOrderTest() { + try { + + // Set business date + LocalDate businessDate = LocalDate.of(2023, 03, 3); + + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); + + // Loan ExternalId + String loanExternalIdStr = UUID.randomUUID().toString(); + + final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); + + // set repayment start date type as disbursement date + final Integer repaymentStartDateType = 1; + + // down-payment configuration + Boolean enableDownPayment = false; + Boolean enableAutoRepaymentForDownPayment = false; + + // Loan Product creation with repayment start date type and down payment configuration with multi + // disbursement + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements( + loanTransactionHelper, repaymentStartDateType, enableDownPayment, null, enableAutoRepaymentForDownPayment); + + assertNotNull(getLoanProductsProductResponse); + assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); + assertEquals(enableDownPayment, getLoanProductsProductResponse.getEnableDownPayment()); + + // create loan account with submitted date as business date (03 March 2023) and expected disbursement date + // as future date (07 March 2023) + final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(), + loanExternalIdStr); + + // Retrieve Loan with loanId + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + + assertNotNull(loanDetails); + assertNotNull(loanDetails.getRepaymentSchedule()); + + // verify amounts + assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected()); + + // verify schedule is according to expected disbursement date + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); + assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); + assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + + // first disbursement on a future date (7 March 2023) + + businessDate = LocalDate.of(2023, 03, 7); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); + + loanTransactionHelper.disburseLoanWithTransactionAmount("07 March 2023", loanId, "500"); + + loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + + // verify loan schedule is according to disbursement date after first disbursement + assertNotNull(loanDetails); + assertNotNull(loanDetails.getRepaymentSchedule()); + + // verify amounts + assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected()); + + // disbursement period + assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate()); + + // first installment + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); + assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); + assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod()); + + // second installment + assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); + assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); + assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod()); + + // third installment + assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); + assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); + assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod()); + + // fourth installment + assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); + assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate()); + assertEquals(LocalDate.of(2023, 07, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod()); + + // make repayment on 7 March to pay installment + final PostLoansLoanIdTransactionsResponse repaymentTransaction_1 = loanTransactionHelper.makeLoanRepayment(loanExternalIdStr, + new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("7 March 2023").locale("en") + .transactionAmount(125.00)); + + loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + + assertNotNull(loanDetails); + assertNotNull(loanDetails.getRepaymentSchedule()); + + // verify amounts + assertEquals(500.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected()); + assertEquals(375.0, loanDetails.getRepaymentSchedule().getTotalOutstanding()); + + // first installment + // check installment gets paid + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); + assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); + assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalPaidForPeriod()); + assertEquals(true, loanDetails.getRepaymentSchedule().getPeriods().get(1).getComplete()); + + // second installment + assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); + assertEquals(LocalDate.of(2023, 04, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); + assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod()); + + // third installment + assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); + assertEquals(LocalDate.of(2023, 05, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); + assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod()); + + // fourth installment + assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); + assertEquals(LocalDate.of(2023, 06, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate()); + assertEquals(LocalDate.of(2023, 07, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod()); + + // set business date + + businessDate = LocalDate.of(2023, 03, 8); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate); + + // second disbursement backdated 5 March + + loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 2023", loanId, "500"); + + loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + + // verify loan schedule is according to backdated disbursement date after second disbursement + + assertNotNull(loanDetails); + assertNotNull(loanDetails.getRepaymentSchedule()); + + // verify amounts + assertEquals(1000.0, loanDetails.getRepaymentSchedule().getTotalPrincipalExpected()); + assertEquals(875.0, loanDetails.getRepaymentSchedule().getTotalOutstanding()); + + // verify disbursement period order + assertEquals(LocalDate.of(2023, 03, 5), loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate()); + assertEquals(LocalDate.of(2023, 03, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + + // first installment for 5 March disbursal + // check installment gets paid + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); + assertEquals(LocalDate.of(2023, 03, 5), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); + assertEquals(LocalDate.of(2023, 04, 5), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); + assertEquals(250.00, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod()); + assertEquals(125.00, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalPaidForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(2).getComplete()); + + // second installment + assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); + assertEquals(LocalDate.of(2023, 04, 5), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); + assertEquals(LocalDate.of(2023, 05, 5), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); + assertEquals(250.00, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(3).getComplete()); + + // third installment + assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); + assertEquals(LocalDate.of(2023, 05, 5), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate()); + assertEquals(LocalDate.of(2023, 06, 5), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); + assertEquals(250.00, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(4).getComplete()); + + // fourth installment + assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().get(5).getPeriod()); + assertEquals(LocalDate.of(2023, 06, 5), loanDetails.getRepaymentSchedule().getPeriods().get(5).getFromDate()); + assertEquals(LocalDate.of(2023, 07, 5), loanDetails.getRepaymentSchedule().getPeriods().get(5).getDueDate()); + assertEquals(250.00, loanDetails.getRepaymentSchedule().getPeriods().get(5).getTotalInstallmentAmountForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(5).getComplete()); + + } finally { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); + } + } + private Integer createLoanAccountMultipleRepaymentsDisbursement(final Integer clientID, final Long loanProductID, final String externalId) {