FINERACT-1981: Fix Disbursement on overpaid loan (Cumulative)
This commit is contained in:
+26
-7
@@ -2967,8 +2967,24 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
Money downPaymentMoney = Money.of(getCurrency(),
|
||||
MathUtil.percentageOf(disbursementTransaction.getAmount(), disbursedAmountPercentageForDownPayment, 19));
|
||||
|
||||
Money adjustedDownPaymentMoney = MathUtil
|
||||
.negativeToZero(downPaymentMoney.minus(disbursementTransaction.getOverPaymentPortion(getCurrency())));
|
||||
Money adjustedDownPaymentMoney = switch (getLoanProductRelatedDetail().getLoanScheduleType()) {
|
||||
// For Cumulative loan: To check whether the loan was overpaid when the disbursement happened and to get the
|
||||
// proper amount after the disbursement we are using two balances:
|
||||
// 1. Whether the loan is still overpaid after the disbursement,
|
||||
// 2. if the loan is not overpaid anymore after the disbursement, but was it more overpaid than the
|
||||
// calculated down-payment amount?
|
||||
case CUMULATIVE -> {
|
||||
if (getTotalOverpaidAsMoney().isGreaterThanZero()) {
|
||||
yield Money.zero(getCurrency());
|
||||
}
|
||||
yield MathUtil.negativeToZero(downPaymentMoney.minus(MathUtil.negativeToZero(disbursementTransaction
|
||||
.getAmount(getCurrency()).minus(disbursementTransaction.getOutstandingLoanBalanceMoney(getCurrency())))));
|
||||
}
|
||||
// For Progressive loan: Disbursement transaction portion balances are enough to see whether the overpayment
|
||||
// amount was more than the calculated down-payment amount
|
||||
case PROGRESSIVE ->
|
||||
MathUtil.negativeToZero(downPaymentMoney.minus(disbursementTransaction.getOverPaymentPortion(getCurrency())));
|
||||
};
|
||||
if (adjustedDownPaymentMoney.isGreaterThanZero()) {
|
||||
LoanTransaction downPaymentTransaction = LoanTransaction.downPayment(getOffice(), adjustedDownPaymentMoney, null, disbursedOn,
|
||||
externalId);
|
||||
@@ -3602,7 +3618,11 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
final LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
||||
for (final LoanTransaction previousTransaction : loanTransactions) {
|
||||
if (!previousTransaction.isDisbursement() && previousTransaction.isNotReversed()
|
||||
&& !DateUtils.isAfter(currentTransactionDate, previousTransaction.getTransactionDate())) {
|
||||
&& (DateUtils.isBefore(currentTransactionDate, previousTransaction.getTransactionDate())
|
||||
|| (DateUtils.isEqual(currentTransactionDate, previousTransaction.getTransactionDate())
|
||||
&& ((loanTransaction.getId() == null && previousTransaction.getId() == null)
|
||||
|| (loanTransaction.getId() != null && (previousTransaction.getId() == null
|
||||
|| loanTransaction.getId().compareTo(previousTransaction.getId()) < 0)))))) {
|
||||
isChronologicallyLatestRepaymentOrWaiver = false;
|
||||
break;
|
||||
}
|
||||
@@ -5958,7 +5978,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
if (loanTransaction.isDisbursement() || loanTransaction.isIncomePosting()) {
|
||||
outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency()))
|
||||
.minus(loanTransaction.getOverPaymentPortion(getCurrency()));
|
||||
loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
|
||||
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
|
||||
} else if (loanTransaction.isChargeback() || loanTransaction.isCreditBalanceRefund()) {
|
||||
Money transactionOutstanding = loanTransaction.getPrincipalPortion(getCurrency());
|
||||
if (!loanTransaction.getOverPaymentPortion(getCurrency()).isZero()) {
|
||||
@@ -5977,8 +5997,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
}
|
||||
}
|
||||
outstanding = outstanding.plus(transactionOutstanding);
|
||||
loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
|
||||
|
||||
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
|
||||
} else {
|
||||
if (this.loanInterestRecalculationDetails != null
|
||||
&& this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
|
||||
@@ -5987,7 +6006,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
} else {
|
||||
outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
|
||||
}
|
||||
loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
|
||||
loanTransaction.updateOutstandingLoanBalance(MathUtil.negativeToZero(outstanding.getAmount()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-4
@@ -46,6 +46,7 @@ import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.portfolio.account.data.AccountTransferData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
@@ -147,14 +148,16 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId);
|
||||
}
|
||||
|
||||
public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
public static LoanTransaction disbursement(final Loan loan, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate disbursementDate, final ExternalId externalId, final Money loanTotalOverpaid) {
|
||||
// We need to set the overpayment amount because it could happen the transaction got saved before the proper
|
||||
// portion calculation and side effect would be reverse-replay
|
||||
Money overPaymentPortion = amount.isGreaterThan(loanTotalOverpaid) ? loanTotalOverpaid : amount;
|
||||
LoanTransaction disbursement = new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail,
|
||||
LoanTransaction disbursement = new LoanTransaction(null, loan.getOffice(), LoanTransactionType.DISBURSEMENT, paymentDetail,
|
||||
amount.getAmount(), disbursementDate, externalId);
|
||||
disbursement.setOverPayments(overPaymentPortion);
|
||||
if (LoanScheduleType.PROGRESSIVE.equals(loan.getLoanProductRelatedDetail().getLoanScheduleType())) {
|
||||
Money overPaymentPortion = amount.isGreaterThan(loanTotalOverpaid) ? loanTotalOverpaid : amount;
|
||||
disbursement.setOverPayments(overPaymentPortion);
|
||||
}
|
||||
return disbursement;
|
||||
}
|
||||
|
||||
@@ -911,6 +914,10 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
return outstandingLoanBalance;
|
||||
}
|
||||
|
||||
public Money getOutstandingLoanBalanceMoney(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.outstandingLoanBalance);
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user