FINERACT-2124: Fix final income accrual calculation with multiple fee charges
This commit is contained in:
committed by
Adam Saghy
parent
68f20c29e9
commit
0daf42ec33
+2
-1
@@ -1541,7 +1541,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
|
||||
int numberOfInstallments = 0;
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (!installment.isRecalculatedInterestComponent()) {
|
||||
if (!installment.isRecalculatedInterestComponent() && !installment.isAdditional() && !installment.isDownPayment()
|
||||
&& !installment.isReAged()) {
|
||||
numberOfInstallments++;
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -281,6 +281,19 @@ public interface LoanTransactionRepository extends JpaRepository<LoanTransaction
|
||||
""")
|
||||
BigDecimal findChargeAccrualAmount(@Param("loanCharge") LoanCharge loanCharge);
|
||||
|
||||
@Query("""
|
||||
SELECT COALESCE(SUM(CASE WHEN lt.typeOf = org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL THEN lcpb.amount
|
||||
WHEN lt.typeOf = org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType.ACCRUAL_ADJUSTMENT THEN -lcpb.amount
|
||||
ELSE 0 END), 0)
|
||||
FROM LoanChargePaidBy lcpb
|
||||
JOIN lcpb.loanTransaction lt
|
||||
WHERE lcpb.loanCharge = :loanCharge
|
||||
AND lcpb.installmentNumber = :installmentNumber
|
||||
AND lt.reversed = false
|
||||
""")
|
||||
BigDecimal findChargeAccrualAmountByInstallment(@Param("loanCharge") LoanCharge loanCharge,
|
||||
@Param("installmentNumber") Integer installmentNumber);
|
||||
|
||||
@Query("""
|
||||
SELECT COALESCE(SUM(lt.unrecognizedIncomePortion), 0)
|
||||
FROM LoanChargePaidBy lcpb
|
||||
|
||||
+11
@@ -725,6 +725,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
final Integer installmentNumber) {
|
||||
|
||||
Money amountRemaining = chargeAmount;
|
||||
final Set<LoanCharge> chargesThatCannotBeFullyPaidByOneInstallment = new HashSet<>();
|
||||
|
||||
while (amountRemaining.isGreaterThanZero()) {
|
||||
final LoanCharge unpaidCharge = findEarliestUnpaidChargeFromUnOrderedSet(charges, chargeAmount.getCurrency());
|
||||
Money feeAmount = chargeAmount.zero();
|
||||
@@ -734,6 +736,12 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
if (unpaidCharge == null) {
|
||||
break; // All are trache charges
|
||||
}
|
||||
|
||||
// If we've already determined this charge cannot be fully paid by one installment, skip it
|
||||
if (chargesThatCannotBeFullyPaidByOneInstallment.contains(unpaidCharge)) {
|
||||
charges.remove(unpaidCharge);
|
||||
}
|
||||
|
||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
||||
if (!amountPaidTowardsCharge.isZero()) {
|
||||
Set<LoanChargePaidBy> chargesPaidBies = loanTransaction.getLoanChargesPaid();
|
||||
@@ -750,6 +758,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
chargesPaidBies.add(loanChargePaidBy);
|
||||
}
|
||||
amountRemaining = amountRemaining.minus(amountPaidTowardsCharge);
|
||||
} else {
|
||||
chargesThatCannotBeFullyPaidByOneInstallment.add(unpaidCharge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,6 +796,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (earliestUnpaidCharge == null || (chargePerInstallment != null && DateUtils.isAfter(earliestUnpaidCharge.getDueLocalDate(),
|
||||
chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
|
||||
earliestUnpaidCharge = installemntCharge;
|
||||
|
||||
+2
-1
@@ -655,7 +655,8 @@ public class LoanChargeService {
|
||||
private List<LoanInstallmentCharge> generateInstallmentLoanCharges(final Loan loan, final LoanCharge loanCharge) {
|
||||
final List<LoanInstallmentCharge> loanChargePerInstallments = new ArrayList<>();
|
||||
if (loanCharge.isInstalmentFee()) {
|
||||
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
|
||||
final List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments().stream()
|
||||
.filter(i -> !i.isDownPayment() && !i.isAdditional() && !i.isReAged()).toList();
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
BigDecimal amount;
|
||||
if (loanCharge.getChargeCalculation().isFlat()) {
|
||||
|
||||
Reference in New Issue
Block a user