FINERACT-1981: Disbursement on overpaid loan
This commit is contained in:
+81
@@ -46,6 +46,8 @@ import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
|
||||
import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||
@@ -3124,6 +3126,85 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
||||
});
|
||||
}
|
||||
|
||||
// UC122: Advanced payment allocation, 2nd disbursement on overpaid loan
|
||||
// ADVANCED_PAYMENT_ALLOCATION_STRATEGY
|
||||
// 1. Create a Loan product with Adv. Pment. Alloc.
|
||||
// 2. Submit Loan and approve
|
||||
// 3. Disburse only 100 from 1000
|
||||
// 4. Overpay the loan (110)
|
||||
// 5. Disburse again 100
|
||||
@Test
|
||||
public void uc122() {
|
||||
runAt("24 November 2023", () -> {
|
||||
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
|
||||
.numberOfRepayments(3).repaymentEvery(15).enableDownPayment(true)
|
||||
.disbursedAmountPercentageForDownPayment(BigDecimal.valueOf(25)).enableAutoRepaymentForDownPayment(false);
|
||||
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductResponse.getResourceId(), "22 November 2023",
|
||||
1000.0, 4);
|
||||
|
||||
applicationRequest = applicationRequest.numberOfRepayments(3).loanTermFrequency(45)
|
||||
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY).repaymentEvery(15);
|
||||
|
||||
PostLoansResponse loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
|
||||
loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
|
||||
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
|
||||
.approvedOnDate("22 November 2023").locale("en"));
|
||||
|
||||
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
|
||||
new PostLoansLoanIdRequest().actualDisbursementDate("22 November 2023").dateFormat(DATETIME_PATTERN)
|
||||
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||
validateLoanSummaryBalances(loanDetails, 100.0, 0.0, 100.0, 0.0, null);
|
||||
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 22), 25.0, 0.0, 25.0, 0.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 7), 25.0, 0.0, 25.0, 0.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 22), 25.0, 0.0, 25.0, 0.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2024, 1, 6), 25.0, 0.0, 25.0, 0.0, 0.0);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
|
||||
loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat(DATETIME_PATTERN).transactionDate("23 November 2023").locale("en").transactionAmount(110.0));
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||
validateLoanSummaryBalances(loanDetails, 0.0, 100.0, 0.0, 100.0, 10.0);
|
||||
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 22), 25.0, 25.0, 0.0, 0.0, 25.0);
|
||||
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 12, 7), 25.0, 25.0, 0.0, 25.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 22), 25.0, 25.0, 0.0, 25.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2024, 1, 6), 25.0, 25.0, 0.0, 25.0, 0.0);
|
||||
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||
|
||||
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
|
||||
new PostLoansLoanIdRequest().actualDisbursementDate("24 November 2023").dateFormat(DATETIME_PATTERN)
|
||||
.transactionAmount(BigDecimal.valueOf(100.0)).locale("en"));
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||
validateLoanSummaryBalances(loanDetails, 90.0, 110.0, 90.0, 110.0, null);
|
||||
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 11, 22), 25.0, 25.0, 0.0, 0.0, 25.0);
|
||||
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 11, 24), 25.0, 10.0, 15.0, 0.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 12, 7), 50.0, 25.0, 25.0, 25.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 12, 22), 50.0, 25.0, 25.0, 25.0, 0.0);
|
||||
validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2024, 1, 6), 50.0, 25.0, 25.0, 25.0, 0.0);
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
|
||||
verifyTransactions(loanResponse.getLoanId(), //
|
||||
transaction(100, "Disbursement", "22 November 2023", 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(110, "Repayment", "23 November 2023", 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 10.0), //
|
||||
transaction(100, "Disbursement", "24 November 2023", 90.0, 0.0, 0.0, 0.0, 0.0, 0.0, 10.0) //
|
||||
);
|
||||
// verify journal entries
|
||||
verifyJournalEntries(loanResponse.getLoanId(), journalEntry(100.0, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100.0, suspenseClearingAccount, "CREDIT"), //
|
||||
journalEntry(100.0, loansReceivableAccount, "CREDIT"), //
|
||||
journalEntry(10.0, overpaymentAccount, "CREDIT"), //
|
||||
journalEntry(110.0, suspenseClearingAccount, "DEBIT"), //
|
||||
journalEntry(90.0, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(10.0, overpaymentAccount, "DEBIT"), //
|
||||
journalEntry(100.0, suspenseClearingAccount, "CREDIT") //
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private static void validateLoanSummaryBalances(GetLoansLoanIdResponse loanDetails, Double totalOutstanding, Double totalRepayment,
|
||||
Double principalOutstanding, Double principalPaid, Double totalOverpaid) {
|
||||
assertEquals(totalOutstanding, loanDetails.getSummary().getTotalOutstanding());
|
||||
|
||||
+9
-9
@@ -66,8 +66,8 @@ public class AdvancedPaymentAllocationWaiveLoanCharges extends BaseLoanIntegrati
|
||||
|
||||
// Then verify
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0) //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0) //
|
||||
);
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
@@ -99,8 +99,8 @@ public class AdvancedPaymentAllocationWaiveLoanCharges extends BaseLoanIntegrati
|
||||
|
||||
// Then verify
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0) //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0) //
|
||||
);
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
@@ -137,8 +137,8 @@ public class AdvancedPaymentAllocationWaiveLoanCharges extends BaseLoanIntegrati
|
||||
|
||||
// Then verify
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "05 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0) //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "05 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0) //
|
||||
);
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||
@@ -151,9 +151,9 @@ public class AdvancedPaymentAllocationWaiveLoanCharges extends BaseLoanIntegrati
|
||||
addRepaymentForLoan(loanId, 200.0, "03 January 2023");
|
||||
|
||||
verifyTransactions(loanId, //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(200, "Repayment", "03 January 2023", 800.0, 200.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "05 January 2023", 800.0, 0.0, 0.0, 0.0, 0.0, 50.0) //
|
||||
transaction(1000, "Disbursement", "01 January 2023", 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(200, "Repayment", "03 January 2023", 800.0, 200.0, 0.0, 0.0, 0.0, 0.0, 0.0), //
|
||||
transaction(50, "Waive loan charges", "05 January 2023", 800.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0) //
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
+3
-2
@@ -489,9 +489,9 @@ public abstract class BaseLoanIntegrationTest {
|
||||
}
|
||||
|
||||
protected TransactionExt transaction(double amount, String type, String date, double outstandingAmount, double principalPortion,
|
||||
double interestPortion, double feePortion, double penaltyPortion, double unrecognizedIncomePortion) {
|
||||
double interestPortion, double feePortion, double penaltyPortion, double unrecognizedIncomePortion, double overpaymentPortion) {
|
||||
return new TransactionExt(amount, type, date, outstandingAmount, principalPortion, interestPortion, feePortion, penaltyPortion,
|
||||
unrecognizedIncomePortion);
|
||||
unrecognizedIncomePortion, overpaymentPortion);
|
||||
}
|
||||
|
||||
protected Installment installment(double principalAmount, Boolean completed, String dueDate) {
|
||||
@@ -530,6 +530,7 @@ public abstract class BaseLoanIntegrationTest {
|
||||
Double feePortion;
|
||||
Double penaltyPortion;
|
||||
Double unrecognizedPortion;
|
||||
Double overpaymentPortion;
|
||||
}
|
||||
|
||||
@ToString
|
||||
|
||||
Reference in New Issue
Block a user