Skip to content

Commit 2f38d28

Browse files
adamsaghygalovics
authored andcommitted
FINERACT-1968: Fix when multiple disbursement happens on the 1st day of the loan
1 parent d3b6265 commit 2f38d28

3 files changed

Lines changed: 70 additions & 12 deletions

File tree

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public LoanScheduleModel generate(final MathContext mc, final LoanApplicationTer
7777
: loanApplicationTerms.getSubmittedOnDate();
7878

7979
LoanScheduleParams scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency,
80-
Money.of(currency, chargesDueAtTimeOfDisbursement), periodStartDate, getPrincipalToBeScheduled(loanApplicationTerms));
80+
Money.of(currency, chargesDueAtTimeOfDisbursement), periodStartDate,
81+
getPrincipalToBeScheduled(loanApplicationTerms, periodStartDate));
8182

8283
List<LoanScheduleModelPeriod> periods = createNewLoanScheduleListWithDisbursementDetails(loanApplicationTerms, scheduleParams,
8384
chargesDueAtTimeOfDisbursement);
@@ -233,12 +234,14 @@ private BigDecimal deriveTotalChargesDueAtTimeOfDisbursement(final Set<LoanCharg
233234
/**
234235
* this method calculates the principal amount for generating the repayment schedule.
235236
*/
236-
private Money getPrincipalToBeScheduled(final LoanApplicationTerms loanApplicationTerms) {
237+
private Money getPrincipalToBeScheduled(final LoanApplicationTerms loanApplicationTerms, LocalDate periodStartDate) {
237238
Money principalToBeScheduled;
238239
if (loanApplicationTerms.isMultiDisburseLoan()) {
239240
if (loanApplicationTerms.getTotalDisbursedAmount().isGreaterThanZero()) {
240-
principalToBeScheduled = Money.of(loanApplicationTerms.getCurrency(),
241-
loanApplicationTerms.getDisbursementDatas().get(0).getPrincipal());
241+
BigDecimal totalDisbursalAmountsOnThe = loanApplicationTerms.getDisbursementDatas().stream()
242+
.filter(d -> d.getActualDisbursementDate().equals(periodStartDate)).map(DisbursementData::getPrincipal)
243+
.reduce(BigDecimal.ZERO, BigDecimal::add);
244+
principalToBeScheduled = Money.of(loanApplicationTerms.getCurrency(), totalDisbursalAmountsOnThe);
242245
} else if (loanApplicationTerms.getApprovedPrincipal().isGreaterThanZero()) {
243246
principalToBeScheduled = loanApplicationTerms.getApprovedPrincipal();
244247
} else {

integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3033,6 +3033,63 @@ public void uc119() {
30333033
});
30343034
}
30353035

3036+
// UC120: Advanced payment allocation with auto down payment and multiple disbursement on the first day
3037+
// ADVANCED_PAYMENT_ALLOCATION_STRATEGY
3038+
// 1. Create a Loan product with Adv. Pment. Alloc., and auto down payment
3039+
// 2. Submit Loan and approve
3040+
// 3. Disburse only 100 from 1000
3041+
// 4. Disburse again on the same day but now 901
3042+
@Test
3043+
public void uc120() {
3044+
runAt("22 November 2023", () -> {
3045+
final Account assetAccount = accountHelper.createAssetAccount();
3046+
final Account incomeAccount = accountHelper.createIncomeAccount();
3047+
final Account expenseAccount = accountHelper.createExpenseAccount();
3048+
final Account overpaymentAccount = accountHelper.createLiabilityAccount();
3049+
Integer localLoanProductId = createLoanProduct("1000", "15", "3", true, "25", true, LoanScheduleType.PROGRESSIVE,
3050+
LoanScheduleProcessingType.HORIZONTAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
3051+
final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId,
3052+
BigDecimal.valueOf(1000.0), 45, 15, 3, BigDecimal.ZERO, "22 November 2023", "01 January 2023");
3053+
3054+
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
3055+
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
3056+
.approvedOnDate("22 November 2023").locale("en"));
3057+
3058+
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
3059+
new PostLoansLoanIdRequest().actualDisbursementDate("22 November 2023").dateFormat(DATETIME_PATTERN)
3060+
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
3061+
3062+
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
3063+
validateLoanSummaryBalances(loanDetails, 75.0, 25.0, 75.0, 25.0, null);
3064+
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 22), 25.0, 25.0, 0.0, 0.0, 0.0);
3065+
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 7), 25.0, 0.0, 25.0, 0.0, 0.0);
3066+
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 22), 25.0, 0.0, 25.0, 0.0, 0.0);
3067+
validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2024, 1, 6), 25.0, 0.0, 25.0, 0.0, 0.0);
3068+
assertTrue(loanDetails.getStatus().getActive());
3069+
3070+
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
3071+
new PostLoansLoanIdRequest().actualDisbursementDate("22 November 2023").dateFormat(DATETIME_PATTERN)
3072+
.transactionAmount(BigDecimal.valueOf(901.0)).locale("en"));
3073+
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
3074+
validateLoanSummaryBalances(loanDetails, 750.75, 250.25, 750.75, 250.25, null);
3075+
validatePeriod(loanDetails, 0, LocalDate.of(2023, 11, 22), null, 100.0, null, null, null, 0.0, 0.0, null, null, null, null,
3076+
null, null, null, null, null);
3077+
validatePeriod(loanDetails, 1, LocalDate.of(2023, 11, 22), null, 901.0, null, null, null, 0.0, 0.0, null, null, null, null,
3078+
null, null, null, null, null);
3079+
validatePeriod(loanDetails, 2, LocalDate.of(2023, 11, 22), LocalDate.of(2023, 11, 22), 976.0, 25.0, 25.0, 0.0, 0.0, 0.0, 0.0,
3080+
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
3081+
validatePeriod(loanDetails, 3, LocalDate.of(2023, 11, 22), LocalDate.of(2023, 11, 22), 750.75, 225.25, 225.25, 0.0, 0.0, 0.0,
3082+
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
3083+
validatePeriod(loanDetails, 4, LocalDate.of(2023, 12, 7), null, 500.50, 250.25, 0.0, 250.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3084+
0.0, 0.0, 0.0, 0.0);
3085+
validatePeriod(loanDetails, 5, LocalDate.of(2023, 12, 22), null, 250.25, 250.25, 0.0, 250.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3086+
0.0, 0.0, 0.0, 0.0);
3087+
validatePeriod(loanDetails, 6, LocalDate.of(2024, 1, 6), null, 0.0, 250.25, 0.0, 250.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3088+
0.0, 0.0, 0.0);
3089+
assertTrue(loanDetails.getStatus().getActive());
3090+
});
3091+
}
3092+
30363093
private static void validateLoanSummaryBalances(GetLoansLoanIdResponse loanDetails, Double totalOutstanding, Double totalRepayment,
30373094
Double principalOutstanding, Double principalPaid, Double totalOverpaid) {
30383095
assertEquals(totalOutstanding, loanDetails.getSummary().getTotalOutstanding());

integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@
5757
public class LoanWithAdvancedPaymentAllocationIntegrationTests {
5858

5959
private static ClientHelper CLIENT_HELPER;
60-
private static ResponseSpecification RESPONSE_SPEC;
61-
private static RequestSpecification REQUEST_SPEC;
6260
private static Account ASSET_ACCOUNT;
6361
private static Account FEE_PENALTY_ACCOUNT;
6462
private static Account EXPENSE_ACCOUNT;
@@ -69,12 +67,12 @@ public class LoanWithAdvancedPaymentAllocationIntegrationTests {
6967
@BeforeAll
7068
public static void setupTests() {
7169
Utils.initializeRESTAssured();
72-
REQUEST_SPEC = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
73-
REQUEST_SPEC.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
74-
RESPONSE_SPEC = new ResponseSpecBuilder().expectStatusCode(200).build();
75-
AccountHelper accountHelper = new AccountHelper(REQUEST_SPEC, RESPONSE_SPEC);
76-
LOAN_TRANSACTION_HELPER = new LoanTransactionHelper(REQUEST_SPEC, RESPONSE_SPEC);
77-
CLIENT_HELPER = new ClientHelper(REQUEST_SPEC, RESPONSE_SPEC);
70+
RequestSpecification requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
71+
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
72+
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
73+
AccountHelper accountHelper = new AccountHelper(requestSpec, responseSpec);
74+
LOAN_TRANSACTION_HELPER = new LoanTransactionHelper(requestSpec, responseSpec);
75+
CLIENT_HELPER = new ClientHelper(requestSpec, responseSpec);
7876

7977
ASSET_ACCOUNT = accountHelper.createAssetAccount();
8078
FEE_PENALTY_ACCOUNT = accountHelper.createAssetAccount();

0 commit comments

Comments
 (0)