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
commit 88d2f44cb49bdd3e7f591c441bb5740951f2676c Author: Adam Saghy <[email protected]> AuthorDate: Fri Sep 29 10:05:08 2023 +0200 FINERACT-1958: Business events for down payment installments --- .../loanschedule/data/LoanSchedulePeriodData.java | 18 +++++----- .../domain/LoanAccountDomainServiceJpa.java | 6 ++-- .../service/LoanReadPlatformServiceImpl.java | 26 +++++++++------ .../LoanWritePlatformServiceJpaRepositoryImpl.java | 8 ++--- ...oanProductWithDownPaymentConfigurationTest.java | 39 ++++++++++++++++++++-- 5 files changed, 68 insertions(+), 29 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java index 1cc8c958b..2cef9f4a9 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java @@ -97,10 +97,10 @@ public final class LoanSchedulePeriodData { return new LoanSchedulePeriodData(periodNumber, periodDate, periodDate, principalDue, principalOutstanding); } - public static LoanSchedulePeriodData repaymentPeriodWithPayments(@SuppressWarnings("unused") final Long loanId, - final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate, final LocalDate obligationsMetOnDate, - final boolean complete, final BigDecimal principalOriginalDue, final BigDecimal principalPaid, - final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding, final BigDecimal outstandingPrincipalBalanceOfLoan, + public static LoanSchedulePeriodData periodWithPayments(@SuppressWarnings("unused") final Long loanId, final Integer periodNumber, + final LocalDate fromDate, final LocalDate dueDate, final LocalDate obligationsMetOnDate, final boolean complete, + final BigDecimal principalOriginalDue, final BigDecimal principalPaid, final BigDecimal principalWrittenOff, + final BigDecimal principalOutstanding, final BigDecimal outstandingPrincipalBalanceOfLoan, final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding, final BigDecimal feeChargesDue, final BigDecimal feeChargesPaid, final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, @@ -109,7 +109,7 @@ public final class LoanSchedulePeriodData { final BigDecimal totalDueForPeriod, final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod, final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding, final BigDecimal totalActualCostOfLoanForPeriod, - final BigDecimal totalInstallmentAmountForPeriod, final BigDecimal totalCredits) { + final BigDecimal totalInstallmentAmountForPeriod, final BigDecimal totalCredits, final boolean isDownPayment) { return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, obligationsMetOnDate, complete, principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, @@ -117,7 +117,7 @@ public final class LoanSchedulePeriodData { feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaid, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding, - totalActualCostOfLoanForPeriod, totalInstallmentAmountForPeriod, totalCredits); + totalActualCostOfLoanForPeriod, totalInstallmentAmountForPeriod, totalCredits, isDownPayment); } public static LoanSchedulePeriodData withPaidDetail(final LoanSchedulePeriodData loanSchedulePeriodData, final boolean complete, @@ -138,7 +138,7 @@ public final class LoanSchedulePeriodData { loanSchedulePeriodData.totalPaidLateForPeriod, loanSchedulePeriodData.totalWaivedForPeriod, loanSchedulePeriodData.totalWrittenOffForPeriod, loanSchedulePeriodData.totalOutstandingForPeriod, loanSchedulePeriodData.totalActualCostOfLoanForPeriod, loanSchedulePeriodData.totalInstallmentAmountForPeriod, - loanSchedulePeriodData.totalCredits); + loanSchedulePeriodData.totalCredits, loanSchedulePeriodData.getDownPaymentPeriod()); } /* @@ -348,7 +348,7 @@ public final class LoanSchedulePeriodData { final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod, final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding, final BigDecimal totalActualCostOfLoanForPeriod, final BigDecimal totalInstallmentAmountForPeriod, - final BigDecimal totalCredits) { + final BigDecimal totalCredits, final boolean isDownPayment) { this.period = periodNumber; this.fromDate = fromDate; this.dueDate = dueDate; @@ -403,7 +403,7 @@ public final class LoanSchedulePeriodData { this.totalOverdue = null; } this.totalCredits = totalCredits; - this.downPaymentPeriod = false; + this.downPaymentPeriod = isDownPayment; } private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index ecfcd5f0f..604e5804f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -53,6 +53,8 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanRefundPostBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanRefundPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPostBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionGoodwillCreditPostBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionGoodwillCreditPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionMakeRepaymentPostBusinessEvent; @@ -290,7 +292,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { } else if (isRecoveryRepayment) { repaymentEvent = new LoanTransactionRecoveryPaymentPreBusinessEvent(loan); } else if (repaymentTransactionType.isDownPayment()) { - repaymentEvent = new LoanTransactionMakeRepaymentPreBusinessEvent(loan); + repaymentEvent = new LoanTransactionDownPaymentPreBusinessEvent(loan); } return repaymentEvent; } @@ -311,7 +313,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { } else if (isRecoveryRepayment) { repaymentEvent = new LoanTransactionRecoveryPaymentPostBusinessEvent(transaction); } else if (repaymentTransactionType.isDownPayment()) { - repaymentEvent = new LoanTransactionMakeRepaymentPostBusinessEvent(transaction); + repaymentEvent = new LoanTransactionDownPaymentPostBusinessEvent(transaction); } return repaymentEvent; } 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 9ddf349e3..f4715ae18 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 @@ -1140,7 +1140,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa + " ls.fee_charges_amount as feeChargesDue, ls.fee_charges_completed_derived as feeChargesPaid, ls.fee_charges_waived_derived as feeChargesWaived, ls.fee_charges_writtenoff_derived as feeChargesWrittenOff, " + " ls.penalty_charges_amount as penaltyChargesDue, ls.penalty_charges_completed_derived as penaltyChargesPaid, ls.penalty_charges_waived_derived as penaltyChargesWaived, " + " ls.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff, ls.total_paid_in_advance_derived as totalPaidInAdvanceForPeriod, " - + " ls.total_paid_late_derived as totalPaidLateForPeriod, ls.credits_amount as totalCredits " + + " ls.total_paid_late_derived as totalPaidLateForPeriod, ls.credits_amount as totalCredits, ls.is_down_payment isDownPayment " + " from m_loan_repayment_schedule ls "; } @@ -1351,14 +1351,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(principalDue); } - final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, - dueDate, obligationsMetOnDate, complete, principalDue, principalPaid, principalWrittenOff, principalOutstanding, - outstandingPrincipalBalanceOfLoan, interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, - interestOutstanding, feeChargesExpectedDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, - feeChargesOutstanding, penaltyChargesExpectedDue, penaltyChargesPaid, penaltyChargesWaived, - penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaidForPeriod, - totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod, - totalOutstandingForPeriod, totalActualCostOfLoanForPeriod, totalInstallmentAmount, credits); + final boolean isDownPayment = rs.getBoolean("isDownPayment"); + + LoanSchedulePeriodData periodData; + + periodData = LoanSchedulePeriodData.periodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete, + principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, + interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue, + feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue, + penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, + totalPaidForPeriod, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, + totalWrittenOffForPeriod, totalOutstandingForPeriod, totalActualCostOfLoanForPeriod, totalInstallmentAmount, + credits, isDownPayment); periods.add(periodData); } @@ -2300,13 +2304,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa final BigDecimal totalInstallmentAmount = null; final BigDecimal totalCredits = null; - return LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete, + return LoanSchedulePeriodData.periodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete, principalOriginalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaid, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding, - totalActualCostOfLoanForPeriod, totalInstallmentAmount, totalCredits); + totalActualCostOfLoanForPeriod, totalInstallmentAmount, totalCredits, false); } } 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 007cb31bd..4f0e5ae5d 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 @@ -82,8 +82,8 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPostBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanChargeOffPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanDisbursalTransactionBusinessEvent; -import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionMakeRepaymentPostBusinessEvent; -import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionMakeRepaymentPreBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPostBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionDownPaymentPreBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanUndoChargeOffBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanUndoWrittenOffBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanWaiveInterestBusinessEvent; @@ -459,11 +459,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } loan.adjustNetDisbursalAmount(amountToDisburse.getAmount()); if (loan.isAutoRepaymentForDownPaymentEnabled()) { - businessEventNotifierService.notifyPreBusinessEvent(new LoanTransactionMakeRepaymentPreBusinessEvent(loan)); + businessEventNotifierService.notifyPreBusinessEvent(new LoanTransactionDownPaymentPreBusinessEvent(loan)); LoanTransaction downPaymentTransaction = loan.handleDownPayment(amountToDisburse.getAmount(), command, scheduleGeneratorDTO); businessEventNotifierService - .notifyPostBusinessEvent(new LoanTransactionMakeRepaymentPostBusinessEvent(downPaymentTransaction)); + .notifyPostBusinessEvent(new LoanTransactionDownPaymentPostBusinessEvent(downPaymentTransaction)); businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java index b07561d42..70739307c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java @@ -311,7 +311,7 @@ public class LoanProductWithDownPaymentConfigurationTest { try { // Set business date - LocalDate disbursementDate = LocalDate.of(2023, 03, 3); + LocalDate disbursementDate = LocalDate.of(2023, 3, 3); GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate); @@ -364,6 +364,7 @@ public class LoanProductWithDownPaymentConfigurationTest { // first disbursement loanTransactionHelper.disburseLoanWithTransactionAmount("03 March 2023", loanId, "1000"); + loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); // verify down-payment transaction created checkDownPaymentTransaction(disbursementDate, 250.0f, 0.0f, 0.0f, 0.0f, loanId); @@ -373,13 +374,45 @@ public class LoanProductWithDownPaymentConfigurationTest { this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "03 March 2023", new JournalEntry(250, JournalEntry.TransactionType.DEBIT)); + // verify installment details + assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate()); + assertEquals(1000.0, loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding()); + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); + assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + assertEquals(250.0, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod()); + assertEquals(true, loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod()); + assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); + assertEquals(LocalDate.of(2023, 4, 2), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); + assertEquals(750.0, loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod()); + // second disbursement - disbursementDate = LocalDate.of(2023, 03, 5); + disbursementDate = LocalDate.of(2023, 3, 5); BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate); loanTransactionHelper.disburseLoanWithTransactionAmount("05 March 2023", loanId, "200"); checkDownPaymentTransaction(disbursementDate, 50.0f, 0.0f, 0.0f, 0.0f, loanId); + loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + // verify installment details + assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(0).getDueDate()); + assertEquals(1000.0, loanDetails.getRepaymentSchedule().getPeriods().get(0).getPrincipalLoanBalanceOutstanding()); + assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); + assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); + assertEquals(250.0, loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod()); + assertEquals(true, loanDetails.getRepaymentSchedule().getPeriods().get(1).getDownPaymentPeriod()); + assertEquals(LocalDate.of(2023, 3, 5), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); + assertEquals(200.0, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPrincipalLoanBalanceOutstanding()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(2).getDownPaymentPeriod()); + assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); + assertEquals(LocalDate.of(2023, 3, 5), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); + assertEquals(50.0, loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod()); + assertEquals(true, loanDetails.getRepaymentSchedule().getPeriods().get(3).getDownPaymentPeriod()); + assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); + assertEquals(LocalDate.of(2023, 4, 2), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); + assertEquals(900.0, loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod()); + assertEquals(false, loanDetails.getRepaymentSchedule().getPeriods().get(4).getDownPaymentPeriod()); + // verify journal entries for down-payment this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "05 March 2023", new JournalEntry(50, JournalEntry.TransactionType.CREDIT)); @@ -397,7 +430,7 @@ public class LoanProductWithDownPaymentConfigurationTest { try { // Set business date - LocalDate disbursementDate = LocalDate.of(2023, 03, 3); + LocalDate disbursementDate = LocalDate.of(2023, 3, 3); GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, disbursementDate);
