FINERACT-2232: Capitalized income and Caplitalized income adjustment in case of loan is overpaid
This commit is contained in:
committed by
Adam Saghy
parent
009d7b71a9
commit
3b5b96a5f4
+8
@@ -41,6 +41,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
|
|||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||||
@@ -65,6 +66,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
private final LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository;
|
private final LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository;
|
||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
private final LoanBalanceService loanBalanceService;
|
private final LoanBalanceService loanBalanceService;
|
||||||
|
private final LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -103,9 +105,12 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
if (noteText != null && !noteText.isEmpty()) {
|
if (noteText != null && !noteText.isEmpty()) {
|
||||||
noteWritePlatformService.createLoanTransactionNote(capitalizedIncomeTransaction.getId(), noteText);
|
noteWritePlatformService.createLoanTransactionNote(capitalizedIncomeTransaction.getId(), noteText);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post journal entries
|
// Post journal entries
|
||||||
journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
|
loanLifecycleStateMachine.determineAndTransition(loan, transactionDate);
|
||||||
|
|
||||||
businessEventNotifierService
|
businessEventNotifierService
|
||||||
.notifyPostBusinessEvent(new LoanCapitalizedIncomeTransactionCreatedBusinessEvent(capitalizedIncomeTransaction));
|
.notifyPostBusinessEvent(new LoanCapitalizedIncomeTransactionCreatedBusinessEvent(capitalizedIncomeTransaction));
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||||
@@ -161,6 +166,8 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
MathUtil.negativeToZero(capitalizedIncomeBalance.getUnrecognizedAmount().subtract(transactionAmount)));
|
MathUtil.negativeToZero(capitalizedIncomeBalance.getUnrecognizedAmount().subtract(transactionAmount)));
|
||||||
capitalizedIncomeBalanceRepository.save(capitalizedIncomeBalance);
|
capitalizedIncomeBalanceRepository.save(capitalizedIncomeBalance);
|
||||||
|
|
||||||
|
loanLifecycleStateMachine.determineAndTransition(loan, transactionDate);
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(
|
businessEventNotifierService.notifyPostBusinessEvent(
|
||||||
new LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent(savedCapitalizedIncomeAdjustment));
|
new LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent(savedCapitalizedIncomeAdjustment));
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||||
@@ -203,4 +210,5 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
capitalizedIncomeBalance.setUnrecognizedAmount(capitalizedIncomeTransaction.getAmount());
|
capitalizedIncomeBalance.setUnrecognizedAmount(capitalizedIncomeTransaction.getAmount());
|
||||||
capitalizedIncomeBalanceRepository.saveAndFlush(capitalizedIncomeBalance);
|
capitalizedIncomeBalanceRepository.saveAndFlush(capitalizedIncomeBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.starter;
|
|||||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||||
@@ -52,10 +53,11 @@ public class ProgressiveLoanAccountConfiguration {
|
|||||||
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
||||||
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
|
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
|
||||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService,
|
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService,
|
||||||
BusinessEventNotifierService businessEventNotifierService) {
|
LoanLifecycleStateMachine loanLifecycleStateMachine, BusinessEventNotifierService businessEventNotifierService) {
|
||||||
return new CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
return new CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
||||||
paymentDetailWritePlatformService, journalEntryPoster, noteWritePlatformService, externalIdFactory,
|
paymentDetailWritePlatformService, journalEntryPoster, noteWritePlatformService, externalIdFactory,
|
||||||
capitalizedIncomeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService, businessEventNotifierService);
|
capitalizedIncomeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService, loanLifecycleStateMachine,
|
||||||
|
businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+227
-1
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
@@ -693,11 +694,19 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
|||||||
|
|
||||||
addRepaymentForLoan(loanId, 50.58, "15 March 2024");
|
addRepaymentForLoan(loanId, 50.58, "15 March 2024");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.59, 0.0, 150.0, 0.15);
|
||||||
|
|
||||||
loanTransactionHelper.makeCreditBalanceRefund(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN)
|
loanTransactionHelper.makeCreditBalanceRefund(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN)
|
||||||
.transactionDate("15 March 2024").locale("en").transactionAmount(0.15));
|
.transactionDate("15 March 2024").locale("en").transactionAmount(0.15));
|
||||||
|
|
||||||
// Validate Loan is Closed
|
// Validate Loan is Closed
|
||||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.59, 0.0, 150.0, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 1), 49.71, 49.71, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 49.99, 49.99, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2024, 4, 1), 50.30, 50.30, 0.0, 50.43, 0.0);
|
||||||
|
|
||||||
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
});
|
});
|
||||||
runAt("16 March 2024", () -> {
|
runAt("16 March 2024", () -> {
|
||||||
@@ -709,6 +718,223 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
|||||||
verifyTRJournalEntries(capitalizedIncomeTransactionId, journalEntry(50, loansReceivableAccount, "DEBIT"), //
|
verifyTRJournalEntries(capitalizedIncomeTransactionId, journalEntry(50, loansReceivableAccount, "DEBIT"), //
|
||||||
journalEntry(50, deferredIncomeLiabilityAccount, "CREDIT") //
|
journalEntry(50, deferredIncomeLiabilityAccount, "CREDIT") //
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 50.15, 151.59, 50.00, 150.00, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 1), 49.71, 49.71, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 49.99, 49.99, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2024, 4, 1), 100.30, 50.3, 50.00, 50.43, 0.0);
|
||||||
|
// Validate Loan is Active
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoanCapitalizedIncomeOnLoanOverpaid() {
|
||||||
|
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
final AtomicReference<Long> capitalizedIncomeTransactionIdRef = 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");
|
||||||
|
Long capitalizedIncomeTransactionId = loanTransactionHelper.addCapitalizedIncome(loanId, "1 January 2024", 50.0)
|
||||||
|
.getResourceId();
|
||||||
|
capitalizedIncomeTransactionIdRef.set(capitalizedIncomeTransactionId);
|
||||||
|
});
|
||||||
|
runAt("1 February 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 February 2024");
|
||||||
|
});
|
||||||
|
runAt("1 March 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 March 2024");
|
||||||
|
});
|
||||||
|
runAt("15 March 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "15 March 2024");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.59, 0.0, 150.0, 0.15);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 1), 49.71, 49.71, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 49.99, 49.99, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2024, 4, 1), 50.30, 50.30, 0.0, 50.43, 0.0);
|
||||||
|
// Validate Loan is Overpaid
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
});
|
||||||
|
runAt("16 March 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
Long capitalizedIncomeTransactionId = loanTransactionHelper.addCapitalizedIncome(loanId, "16 March 2024", 50.0).getResourceId();
|
||||||
|
|
||||||
|
verifyTRJournalEntries(capitalizedIncomeTransactionId, journalEntry(50, loansReceivableAccount, "DEBIT"), //
|
||||||
|
journalEntry(50, deferredIncomeLiabilityAccount, "CREDIT") //
|
||||||
|
);
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 50.0, 151.74, 49.85, 150.15, null);
|
||||||
|
validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2024, 2, 1), 49.71, 49.71, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2024, 3, 1), 49.99, 49.99, 0.0, 0.0, 0.0);
|
||||||
|
validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2024, 4, 1), 100.30, 50.45, 49.85, 50.58, 0.0);
|
||||||
|
|
||||||
|
assertTrue(loanDetails.getStatus().getActive());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoanCapitalizedIncomeAdjustmentOnLoanOverpaid() {
|
||||||
|
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
final AtomicReference<Long> capitalizedIncomeTransactionIdRef = 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");
|
||||||
|
Long capitalizedIncomeTransactionId = loanTransactionHelper.addCapitalizedIncome(loanId, "1 January 2024", 50.0)
|
||||||
|
.getResourceId();
|
||||||
|
capitalizedIncomeTransactionIdRef.set(capitalizedIncomeTransactionId);
|
||||||
|
});
|
||||||
|
runAt("1 February 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 February 2024");
|
||||||
|
});
|
||||||
|
runAt("1 March 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 March 2024");
|
||||||
|
});
|
||||||
|
runAt("1 April 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 60.6, "1 April 2024");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
// Validate Loan is Overpaid
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
});
|
||||||
|
runAt("5 April 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
loanTransactionHelper.makeCreditBalanceRefund(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN)
|
||||||
|
.transactionDate("5 April 2024").locale("en").transactionAmount(10.00));
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
// Validate Loan remains Overpaid
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
});
|
||||||
|
runAt("15 April 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
Long capitalizedIncomeAdjustmentTransactionId = loanTransactionHelper
|
||||||
|
.capitalizedIncomeAdjustment(loanId, capitalizedIncomeTransactionIdRef.get(), "15 April 2024", 15.0).getResourceId();
|
||||||
|
verifyTRJournalEntries(capitalizedIncomeAdjustmentTransactionId, journalEntry(15, feeIncomeAccount, "DEBIT"), //
|
||||||
|
journalEntry(15, overpaymentAccount, "CREDIT") //
|
||||||
|
);
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
// Validate Loan remains Overpaid
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.75, 0.0, 150.00, 15.01);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoanCapitalizedIncomeAdjustmentOnLoanClosed() {
|
||||||
|
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
final AtomicReference<Long> capitalizedIncomeTransactionIdRef = 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");
|
||||||
|
Long capitalizedIncomeTransactionId = loanTransactionHelper.addCapitalizedIncome(loanId, "1 January 2024", 50.0)
|
||||||
|
.getResourceId();
|
||||||
|
capitalizedIncomeTransactionIdRef.set(capitalizedIncomeTransactionId);
|
||||||
|
});
|
||||||
|
runAt("1 February 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 February 2024");
|
||||||
|
});
|
||||||
|
runAt("1 March 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.58, "1 March 2024");
|
||||||
|
});
|
||||||
|
runAt("1 April 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
addRepaymentForLoan(loanId, 50.59, "1 April 2024");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.75, 0.0, 150.00, null);
|
||||||
|
// Validate Loan goes to Closed
|
||||||
|
assertTrue(loanDetails.getStatus().getClosedObligationsMet());
|
||||||
|
});
|
||||||
|
runAt("15 April 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
Long capitalizedIncomeAdjustmentTransactionId = loanTransactionHelper
|
||||||
|
.capitalizedIncomeAdjustment(loanId, capitalizedIncomeTransactionIdRef.get(), "15 April 2024", 15.0).getResourceId();
|
||||||
|
verifyTRJournalEntries(capitalizedIncomeAdjustmentTransactionId, journalEntry(15, feeIncomeAccount, "DEBIT"), //
|
||||||
|
journalEntry(15.00, overpaymentAccount, "CREDIT") //
|
||||||
|
);
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
|
||||||
|
validateLoanSummaryBalances(loanDetails, 0.0, 151.75, 0.0, 150.00, 15.0);
|
||||||
|
// Validate Loan goes to Overpaid
|
||||||
|
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user