FINERACT-2232: Capitalized income adjustment
This commit is contained in:
+198
@@ -19,12 +19,17 @@
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.integrationtests.common.BusinessStepHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -96,4 +101,197 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCapitalizedIncomeAdjustment() {
|
||||
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
final AtomicReference<Long> capitalizedIncomeIdRef = new AtomicReference<>();
|
||||
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
|
||||
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
|
||||
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
|
||||
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
|
||||
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||
|
||||
runAt("1 April 2024", () -> {
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "1 January 2024",
|
||||
500.0, 7.0, 3, null);
|
||||
loanIdRef.set(loanId);
|
||||
|
||||
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
|
||||
PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = loanTransactionHelper.addCapitalizedIncome(loanId,
|
||||
"1 January 2024", 50.0);
|
||||
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
|
||||
|
||||
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "1 April 2024", 50.0);
|
||||
|
||||
verifyTransactions(loanId, //
|
||||
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||
transaction(50.0, "Capitalized Income", "01 January 2024"), //
|
||||
transaction(50.0, "Capitalized Income Adjustment", "01 April 2024") //
|
||||
);
|
||||
|
||||
verifyJournalEntries(loanId, //
|
||||
journalEntry(100, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100, fundSource, "CREDIT"), //
|
||||
journalEntry(50, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(50, deferredIncomeLiabilityAccount, "CREDIT"), //
|
||||
journalEntry(50.0, deferredIncomeLiabilityAccount, "DEBIT"), //
|
||||
journalEntry(49.71, loansReceivableAccount, "CREDIT"), //
|
||||
journalEntry(0.29, interestReceivableAccount, "CREDIT") //
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCapitalizedIncomeAdjustmentValidations() {
|
||||
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
final AtomicReference<Long> capitalizedIncomeIdRef = new AtomicReference<>();
|
||||
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
|
||||
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
|
||||
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
|
||||
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
|
||||
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||
|
||||
runAt("3 January 2024", () -> {
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "1 January 2024",
|
||||
500.0, 7.0, 3, null);
|
||||
loanIdRef.set(loanId);
|
||||
|
||||
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
|
||||
PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = loanTransactionHelper.addCapitalizedIncome(loanId,
|
||||
"3 January 2024", 50.0);
|
||||
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
|
||||
|
||||
// Amount more than remaining
|
||||
Assertions.assertThrows(RuntimeException.class,
|
||||
() -> loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "3 January 2024", 60.0));
|
||||
|
||||
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "3 January 2024", 30.0);
|
||||
Assertions.assertThrows(RuntimeException.class,
|
||||
() -> loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "3 January 2024", 30.0));
|
||||
|
||||
// Capitalized income transaction with given id doesn't exist for this loan
|
||||
Assertions.assertThrows(RuntimeException.class,
|
||||
() -> loanTransactionHelper.capitalizedIncomeAdjustment(loanId, 1L, "3 January 2024", 30.0));
|
||||
|
||||
// Cannot be earlier than capitalized income transaction
|
||||
Assertions.assertThrows(RuntimeException.class,
|
||||
() -> loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "2 January 2024", 30.0));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCapitalizedIncomeAdjustmentWithAmortizationAccounting() {
|
||||
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||
final AtomicReference<Long> capitalizedIncomeIdRef = new AtomicReference<>();
|
||||
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
|
||||
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
|
||||
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
|
||||
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
|
||||
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||
|
||||
runAt("1 January 2024", () -> {
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "1 January 2024",
|
||||
500.0, 7.0, 3, null);
|
||||
loanIdRef.set(loanId);
|
||||
|
||||
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
|
||||
PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = loanTransactionHelper.addCapitalizedIncome(loanId,
|
||||
"1 January 2024", 100.0);
|
||||
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
|
||||
});
|
||||
runAt("2 January 2024", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
executeInlineCOB(loanId);
|
||||
|
||||
verifyTransactions(loanId, //
|
||||
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||
transaction(1.10, "Capitalized Income Amortization", "01 January 2024") //
|
||||
);
|
||||
});
|
||||
runAt("3 January 2024", () -> {
|
||||
Long loanId = loanIdRef.get();
|
||||
executeInlineCOB(loanId);
|
||||
|
||||
verifyTransactions(loanId, //
|
||||
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||
transaction(1.10, "Capitalized Income Amortization", "01 January 2024"), //
|
||||
transaction(0.04, "Accrual", "02 January 2024"), //
|
||||
transaction(1.10, "Capitalized Income Amortization", "02 January 2024") //
|
||||
);
|
||||
|
||||
verifyJournalEntries(loanId, //
|
||||
journalEntry(100, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100, fundSource, "CREDIT"), //
|
||||
journalEntry(100, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100, deferredIncomeLiabilityAccount, "CREDIT"), //
|
||||
journalEntry(1.10, deferredIncomeLiabilityAccount, "DEBIT"), //
|
||||
journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
|
||||
journalEntry(0.04, interestReceivableAccount, "DEBIT"), //
|
||||
journalEntry(0.04, interestIncomeAccount, "CREDIT"), //
|
||||
journalEntry(1.10, deferredIncomeLiabilityAccount, "DEBIT"), //
|
||||
journalEntry(1.10, feeIncomeAccount, "CREDIT") //
|
||||
);
|
||||
|
||||
loanTransactionHelper.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "3 January 2024", 100.0);
|
||||
|
||||
verifyTransactions(loanId, //
|
||||
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||
transaction(1.10, "Capitalized Income Amortization", "01 January 2024"), //
|
||||
transaction(0.04, "Accrual", "02 January 2024"), //
|
||||
transaction(1.10, "Capitalized Income Amortization", "02 January 2024"), //
|
||||
transaction(100.0, "Capitalized Income Adjustment", "03 January 2024") //
|
||||
);
|
||||
|
||||
verifyJournalEntries(loanId, //
|
||||
journalEntry(100, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100, fundSource, "CREDIT"), //
|
||||
journalEntry(100, loansReceivableAccount, "DEBIT"), //
|
||||
journalEntry(100, deferredIncomeLiabilityAccount, "CREDIT"), //
|
||||
journalEntry(1.10, deferredIncomeLiabilityAccount, "DEBIT"), //
|
||||
journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
|
||||
journalEntry(0.04, interestReceivableAccount, "DEBIT"), //
|
||||
journalEntry(0.04, interestIncomeAccount, "CREDIT"), //
|
||||
journalEntry(1.10, deferredIncomeLiabilityAccount, "DEBIT"), //
|
||||
journalEntry(1.10, feeIncomeAccount, "CREDIT"), //
|
||||
journalEntry(99.92, loansReceivableAccount, "CREDIT"), //
|
||||
journalEntry(0.08, interestReceivableAccount, "CREDIT"), //
|
||||
journalEntry(2.20, feeIncomeAccount, "DEBIT"), //
|
||||
journalEntry(97.80, deferredIncomeLiabilityAccount, "DEBIT") //
|
||||
);
|
||||
|
||||
// Reverse-replay
|
||||
addRepaymentForLoan(loanId, 67.45, "2 January 2024");
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||
Optional<GetLoansLoanIdTransactions> replayedCapitalizedIncomeAdjustmentOpt = loanDetails.getTransactions().stream()
|
||||
.filter(t -> t.getType().getCapitalizedIncomeAdjustment()).findFirst();
|
||||
Assertions.assertTrue(replayedCapitalizedIncomeAdjustmentOpt.isPresent(), "Capitalized income adjustment not found");
|
||||
|
||||
verifyTRJournalEntries(replayedCapitalizedIncomeAdjustmentOpt.get().getId(), //
|
||||
journalEntry(99.98, loansReceivableAccount, "CREDIT"), //
|
||||
journalEntry(0.02, interestReceivableAccount, "CREDIT"), //
|
||||
journalEntry(2.20, feeIncomeAccount, "DEBIT"), //
|
||||
journalEntry(97.80, deferredIncomeLiabilityAccount, "DEBIT") //
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -589,6 +589,12 @@ public class ExternalEventConfigurationHelper {
|
||||
loanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent.put("enabled", false);
|
||||
defaults.add(loanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent);
|
||||
|
||||
Map<String, Object> loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent = new HashMap<>();
|
||||
loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.put("type",
|
||||
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent");
|
||||
loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent.put("enabled", false);
|
||||
defaults.add(loanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent);
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
|
||||
+30
@@ -933,6 +933,36 @@ public class LoanTransactionHelper {
|
||||
new InterestPauseRequestDto().startDate(startDate).endDate(endDate).dateFormat(DATE_FORMAT).locale("en")));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustment(final Long loanId, final Long capitalizedIncomeTransactionId,
|
||||
final PostLoansLoanIdTransactionsTransactionIdRequest request) {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction(loanId,
|
||||
capitalizedIncomeTransactionId, request, "capitalizedIncomeAdjustment"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustment(final String loanExternalId, final Long transactionId,
|
||||
final PostLoansLoanIdTransactionsTransactionIdRequest request) {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction2(loanExternalId, transactionId,
|
||||
request, "capitalizedIncomeAdjustment"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustment(final String loanExternalId, final String transactionExternalId,
|
||||
final PostLoansLoanIdTransactionsTransactionIdRequest request) {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction3(loanExternalId,
|
||||
transactionExternalId, request, "capitalizedIncomeAdjustment"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustment(final Long loanId, final String transactionExternalId,
|
||||
final PostLoansLoanIdTransactionsTransactionIdRequest request) {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.adjustLoanTransaction1(loanId, transactionExternalId,
|
||||
request, "capitalizedIncomeAdjustment"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustment(final Long loanId, final Long capitalizedIncomeTransactionId,
|
||||
final String transactionDate, final double amount) {
|
||||
return capitalizedIncomeAdjustment(loanId, capitalizedIncomeTransactionId, new PostLoansLoanIdTransactionsTransactionIdRequest()
|
||||
.transactionAmount(amount).transactionDate(transactionDate).dateFormat("dd MMMM yyyy").locale("en"));
|
||||
}
|
||||
|
||||
// TODO: Rewrite to use fineract-client instead!
|
||||
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
|
||||
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
|
||||
|
||||
Reference in New Issue
Block a user