FINERACT-2081: Fix Fineract writer hung infinte loop after merchant issued refund
This commit is contained in:
+1
@@ -2250,6 +2250,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest));
|
||||
|
||||
emiCalculator.calculateRateFactorForRepaymentPeriod(lastPeriod, transactionCtx.getModel());
|
||||
transactionCtx.getModel().disableEMIRecalculation();
|
||||
|
||||
for (LoanTransaction processTransaction : transactionsToBeReprocessed) {
|
||||
emiCalculator.addBalanceCorrection(transactionCtx.getModel(), processTransaction.getTransactionDate(),
|
||||
|
||||
+14
-10
@@ -182,20 +182,25 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
return;
|
||||
}
|
||||
Optional<RepaymentPeriod> repaymentPeriod = findRepaymentPeriod(scheduleModel, repaymentPeriodDueDate);
|
||||
boolean transactionDateIsBefore = transactionDate.isBefore(repaymentPeriod.get().getFromDate());
|
||||
repaymentPeriod.ifPresent(rp -> rp.addPaidPrincipalAmount(principalAmount));
|
||||
// If it is paid late, we need to calculate with the period due date
|
||||
LocalDate balanceCorrectionDate = DateUtils.isBefore(repaymentPeriodDueDate, transactionDate) ? repaymentPeriodDueDate
|
||||
: transactionDate;
|
||||
addBalanceCorrection(scheduleModel, balanceCorrectionDate, principalAmount.negated());
|
||||
|
||||
repaymentPeriod.ifPresent(rp -> {
|
||||
// If any period total paid > calculated EMI, then set EMI to total paid -> effectively it is marked as
|
||||
// fully paid
|
||||
if (rp.getTotalPaidAmount().isGreaterThan(rp.getEmiPlusChargeback())) {
|
||||
rp.setEmi(rp.getTotalPaidAmount().minus(rp.getTotalChargebackAmount()));
|
||||
if (scheduleModel.isEMIRecalculationEnabled()) {
|
||||
repaymentPeriod.ifPresent(rp -> {
|
||||
// If any period total paid > calculated EMI, then set EMI to total paid -> effectively it is marked as
|
||||
// fully paid
|
||||
if (transactionDateIsBefore && rp.getTotalPaidAmount().isGreaterThan(rp.getEmiPlusChargeback())) {
|
||||
rp.setEmi(rp.getTotalPaidAmount().minus(rp.getTotalChargebackAmount()));
|
||||
} else if (transactionDateIsBefore
|
||||
&& rp.getTotalPaidAmount().isEqualTo(rp.getOriginalEmi().add(rp.getTotalChargebackAmount()))) {
|
||||
rp.setEmi(rp.getTotalPaidAmount().minus(rp.getTotalChargebackAmount()));
|
||||
}
|
||||
calculateLastUnpaidRepaymentPeriodEMI(scheduleModel);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addChargebackAmountsToInterestPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate transactionDate,
|
||||
@@ -357,7 +362,6 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
interestPeriod.addChargebackPrincipalAmount(nextInterestPeriod.getChargebackPrincipal());
|
||||
interestPeriod.addChargebackInterestAmount(nextInterestPeriod.getChargebackInterest());
|
||||
}
|
||||
|
||||
repaymentPeriod.getInterestPeriods().subList(nextIdx, repaymentPeriod.getInterestPeriods().size()).clear();
|
||||
scheduleModelCopy.repaymentPeriods().forEach(rp -> rp.getInterestPeriods().removeIf(ip -> ip.getDueDate().isAfter(targetDate)));
|
||||
calculateRateFactorForPeriods(scheduleModelCopy.repaymentPeriods(), scheduleModelCopy);
|
||||
@@ -374,7 +378,7 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
final ProgressiveLoanInterestScheduleModel scheduleModel, final EmiChangeOperation operation) {
|
||||
final List<RepaymentPeriod> relatedRepaymentPeriods = scheduleModel.getRelatedRepaymentPeriods(calculateFromRepaymentPeriodDueDate);
|
||||
final boolean onlyOnActualModelShouldApply = scheduleModel.isEmpty()
|
||||
|| operation.getAction() == EmiChangeOperation.Action.INTEREST_RATE_CHANGE || scheduleModel.isCopiedForCalculation();
|
||||
|| operation.getAction() == EmiChangeOperation.Action.INTEREST_RATE_CHANGE || scheduleModel.isCopy();
|
||||
|
||||
calculateRateFactorForPeriods(relatedRepaymentPeriods, scheduleModel);
|
||||
calculateOutstandingBalance(scheduleModel);
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.calc.data;
|
||||
|
||||
public enum LoanInterestScheduleModelModifiers {
|
||||
EMI_RECALCULATION, COPY,
|
||||
}
|
||||
+17
-3
@@ -19,6 +19,8 @@
|
||||
package org.apache.fineract.portfolio.loanproduct.calc.data;
|
||||
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper.isInPeriod;
|
||||
import static org.apache.fineract.portfolio.loanproduct.calc.data.LoanInterestScheduleModelModifiers.COPY;
|
||||
import static org.apache.fineract.portfolio.loanproduct.calc.data.LoanInterestScheduleModelModifiers.EMI_RECALCULATION;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
@@ -56,7 +58,7 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
private final Integer installmentAmountInMultiplesOf;
|
||||
private final MathContext mc;
|
||||
private final Money zero;
|
||||
private final boolean isCopiedForCalculation;
|
||||
private final Map<LoanInterestScheduleModelModifiers, Boolean> modifiers;
|
||||
|
||||
public ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> repaymentPeriods,
|
||||
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail,
|
||||
@@ -68,7 +70,7 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
this.mc = mc;
|
||||
this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
|
||||
this.isCopiedForCalculation = false;
|
||||
modifiers = new HashMap<>(Map.of(EMI_RECALCULATION, true, COPY, false));
|
||||
}
|
||||
|
||||
private ProgressiveLoanInterestScheduleModel(final List<RepaymentPeriod> repaymentPeriods, final TreeSet<InterestRate> interestRates,
|
||||
@@ -83,7 +85,7 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
this.loanTermVariations = loanTermVariations;
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc);
|
||||
this.isCopiedForCalculation = isCopiedForCalculation;
|
||||
modifiers = new HashMap<>(Map.of(EMI_RECALCULATION, true, COPY, isCopiedForCalculation));
|
||||
}
|
||||
|
||||
public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) {
|
||||
@@ -405,4 +407,16 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
return loanTermVariationsData.stream()
|
||||
.collect(Collectors.groupingBy(ltvd -> LoanTermVariationType.fromInt(ltvd.getTermType().getId().intValue())));
|
||||
}
|
||||
|
||||
public void disableEMIRecalculation() {
|
||||
this.modifiers.put(EMI_RECALCULATION, false);
|
||||
}
|
||||
|
||||
public boolean isEMIRecalculationEnabled() {
|
||||
return this.modifiers.get(EMI_RECALCULATION);
|
||||
}
|
||||
|
||||
public boolean isCopy() {
|
||||
return this.modifiers.get(COPY);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user