FINERACT-1971: Fix when waived N+1 installment's obligationsMet and obligationsMetOnDate is not or wrongly set

This commit is contained in:
Arnold Galovics
2023-12-04 14:09:10 +01:00
committed by Arnold Gálovics
parent 8505145fde
commit 646d7738c2
6 changed files with 258 additions and 5 deletions
@@ -1436,6 +1436,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
this.charges);
updateLoanOutstandingBalances();
}
}
public void updateLoanSummaryAndStatus() {
@@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
@@ -199,7 +200,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
recalculateChargeOffTransaction(changedTransactionDetail, loanTransaction, currency, installments);
}
}
reprocessInstallments(installments, currency);
reprocessInstallments(disbursementDate, transactionsToBeProcessed, installments, currency);
return changedTransactionDetail;
}
@@ -385,11 +386,28 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
}
}
protected void reprocessInstallments(List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency) {
protected void reprocessInstallments(LocalDate disbursementDate, List<LoanTransaction> transactions,
List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency) {
LoanRepaymentScheduleInstallment lastInstallment = installments.get(installments.size() - 1);
if (lastInstallment.isAdditional() && lastInstallment.getDue(currency).isZero()) {
installments.remove(lastInstallment);
}
if (isNotObligationsMet(lastInstallment) || isObligationsMetOnDisbursementDate(disbursementDate, lastInstallment)) {
Optional<LoanTransaction> optWaiverTx = transactions.stream().filter(lt -> {
LocalDate fromDate = lastInstallment.getFromDate();
return lt.getTransactionDate().isAfter(fromDate);
}).filter(LoanTransaction::isChargesWaiver).max(Comparator.comparing(LoanTransaction::getTransactionDate));
if (optWaiverTx.isPresent()) {
LoanTransaction waiverTx = optWaiverTx.get();
LocalDate waiverTxDate = waiverTx.getTransactionDate();
if (isNotObligationsMet(lastInstallment) || isTransactionAfterObligationsMetOnDate(waiverTxDate, lastInstallment)) {
lastInstallment.updateObligationMet(true);
lastInstallment.updateObligationMetOnDate(waiverTxDate);
}
}
}
// TODO: rewrite and handle it at the proper place when disbursement handling got fixed
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
if (loanRepaymentScheduleInstallment.getTotalOutstanding(currency).isGreaterThanZero()) {
@@ -399,6 +417,20 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
}
}
private boolean isTransactionAfterObligationsMetOnDate(LocalDate waiverTxDate, LoanRepaymentScheduleInstallment lastInstallment) {
return lastInstallment.getObligationsMetOnDate() != null && lastInstallment.getObligationsMetOnDate().isBefore(waiverTxDate);
}
private boolean isObligationsMetOnDisbursementDate(LocalDate disbursementDate,
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
return loanRepaymentScheduleInstallment.isObligationsMet()
&& disbursementDate.equals(loanRepaymentScheduleInstallment.getObligationsMetOnDate());
}
private boolean isNotObligationsMet(LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
return !loanRepaymentScheduleInstallment.isObligationsMet() && loanRepaymentScheduleInstallment.getObligationsMetOnDate() == null;
}
private void recalculateCreditTransaction(ChangedTransactionDetail changedTransactionDetail, LoanTransaction loanTransaction,
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
List<LoanTransaction> transactionsToBeProcessed) {
@@ -30,6 +30,7 @@ import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -139,7 +140,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
chargeOrTransaction.getLoanCharge()
.ifPresent(loanCharge -> processSingleCharge(loanCharge, currency, installments, disbursementDate));
}
reprocessInstallments(installments, currency);
List<LoanTransaction> txs = chargeOrTransactions.stream().map(ChargeOrTransaction::getLoanTransaction).filter(Optional::isPresent)
.map(Optional::get).toList();
reprocessInstallments(disbursementDate, txs, installments, currency);
return changedTransactionDetail;
}