FINERACT-2181: Fix validation for add capitalized income to loan transaction
This commit is contained in:
committed by
Adam Saghy
parent
a76c189a04
commit
e4ab6110ff
+3
@@ -2385,6 +2385,9 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
|
||||
.name(name97)//
|
||||
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())//
|
||||
.loanScheduleType("PROGRESSIVE") //
|
||||
.allowApprovedDisbursedAmountsOverApplied(false)//
|
||||
.overAppliedCalculationType(null)//
|
||||
.overAppliedNumber(null)//
|
||||
.paymentAllocation(List.of(//
|
||||
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), //
|
||||
createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), //
|
||||
|
||||
@@ -6994,3 +6994,31 @@ Feature: Capitalized Income
|
||||
When Customer undo "1"th "Capitalized Income" transaction made on "01 January 2024"
|
||||
And Admin sets the business date to "05 January 2024"
|
||||
And Admin runs inline COB job for Loan
|
||||
|
||||
@TestRailId:C3758
|
||||
Scenario: Verify validation of capitalized income amount with disbursement amount not exceed approved over applied amount for multidisbursal progressive loan - failed scenario
|
||||
When Admin sets the business date to "1 January 2024"
|
||||
And Admin creates a client with random data
|
||||
And Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_ADV_PYMNT_INTEREST_DAILY_RECALC_EMI_360_30_MULTIDISB_OVER_APPLIED_PERCENTAGE_CAPITALIZED_INCOME | 01 January 2024 | 1000 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "1 January 2024" with "1000" amount and expected disbursement date on "1 January 2024"
|
||||
And Admin successfully disburse the loan on "1 January 2024" with "1000" EUR transaction amount
|
||||
Then Loan status will be "ACTIVE"
|
||||
When Admin sets the business date to "2 January 2024"
|
||||
And Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount
|
||||
Then Capitalized income with payment type "AUTOPAY" on "2 January 2024" is forbidden with amount "300" while exceed approved amount
|
||||
|
||||
@TestRailId:C3759
|
||||
Scenario: Verify validation of capitalized income amount with disbursement amount not exceed approved over applied amount for multidisbursal progressive loan - successful scenario
|
||||
When Admin sets the business date to "1 January 2024"
|
||||
And Admin creates a client with random data
|
||||
And Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_ADV_PYMNT_INTEREST_DAILY_RECALC_EMI_360_30_MULTIDISB_OVER_APPLIED_PERCENTAGE_CAPITALIZED_INCOME | 01 January 2024 | 1000 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "1 January 2024" with "1000" amount and expected disbursement date on "1 January 2024"
|
||||
And Admin successfully disburse the loan on "1 January 2024" with "1000" EUR transaction amount
|
||||
Then Loan status will be "ACTIVE"
|
||||
When Admin sets the business date to "2 January 2024"
|
||||
And Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount
|
||||
And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "02 January 2024" with "200" EUR transaction amount
|
||||
+28
-8
@@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||
import org.apache.fineract.portfolio.common.service.Validator;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
@@ -54,6 +55,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepositor
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionValidator;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@@ -121,17 +123,23 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
final BigDecimal transactionAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("transactionAmount", element);
|
||||
baseDataValidator.reset().parameter("transactionAmount").value(transactionAmount).notNull().positiveAmount();
|
||||
|
||||
// Validate total disbursement + capitalized income <= approved amount
|
||||
// Validate total disbursement + capitalized income <= applied amount
|
||||
if (transactionAmount != null) {
|
||||
final BigDecimal totalDisbursed = loan.getDisbursedAmount();
|
||||
final BigDecimal existingCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
|
||||
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
final BigDecimal approvedAmount = loan.getApprovedPrincipal();
|
||||
final BigDecimal newTotal = totalDisbursed.add(existingCapitalizedIncomeBalance).add(transactionAmount);
|
||||
final BigDecimal capitalizedIncome = loan.getSummary().getTotalCapitalizedIncome();
|
||||
final BigDecimal newTotal = totalDisbursed.add(capitalizedIncome).add(transactionAmount);
|
||||
|
||||
if (newTotal.compareTo(approvedAmount) > 0) {
|
||||
baseDataValidator.reset().parameter("transactionAmount").failWithCode("exceeds.approved.amount",
|
||||
"Sum of disbursed amount and capitalized income cannot exceed approved amount");
|
||||
if (loan.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
|
||||
final BigDecimal maxAppliedAmount = getOverAppliedMax(loan);
|
||||
if (newTotal.compareTo(maxAppliedAmount) > 0) {
|
||||
baseDataValidator.reset().parameter("transactionAmount").failWithCode("exceeds.approved.amount",
|
||||
"Sum of disbursed amount and capitalized income can't be greater than maximum applied loan amount calculation.");
|
||||
}
|
||||
} else {
|
||||
if (newTotal.compareTo(loan.getApprovedPrincipal()) > 0) {
|
||||
baseDataValidator.reset().parameter("transactionAmount").failWithCode("exceeds.approved.amount",
|
||||
"Sum of disbursed amount and capitalized income can't be greater than approved loan principal.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,4 +436,16 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
private Set<String> getContractTerminationUndoParameters() {
|
||||
return new HashSet<>(Arrays.asList("note", "reversalExternalId"));
|
||||
}
|
||||
|
||||
private BigDecimal getOverAppliedMax(final Loan loan) {
|
||||
final LoanProduct loanProduct = loan.getLoanProduct();
|
||||
if ("percentage".equals(loanProduct.getOverAppliedCalculationType())) {
|
||||
final BigDecimal overAppliedNumber = BigDecimal.valueOf(loanProduct.getOverAppliedNumber());
|
||||
final BigDecimal totalPercentage = BigDecimal.valueOf(1)
|
||||
.add(overAppliedNumber.divide(BigDecimal.valueOf(100L), MoneyHelper.getMathContext()));
|
||||
return loan.getProposedPrincipal().multiply(totalPercentage);
|
||||
} else {
|
||||
return loan.getProposedPrincipal().add(BigDecimal.valueOf(loanProduct.getOverAppliedNumber()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user