FINERACT-1958: Fix down-payment for loan reschedule and for interest bearing loans
This commit is contained in:
+3
-3
@@ -1082,7 +1082,7 @@ final class LoansApiResourceSwagger {
|
||||
public Integer repaymentEvery;
|
||||
public GetLoansLoanIdRepaymentFrequencyType repaymentFrequencyType;
|
||||
@Schema(example = "24")
|
||||
public Integer interestRatePerPeriod;
|
||||
public BigDecimal interestRatePerPeriod;
|
||||
public GetLoansLoanIdInterestRateFrequencyType interestRateFrequencyType;
|
||||
@Schema(example = "24")
|
||||
public Integer annualInterestRate;
|
||||
@@ -1180,7 +1180,7 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(example = "2")
|
||||
public Integer repaymentFrequencyType;
|
||||
@Schema(example = "2")
|
||||
public Integer interestRatePerPeriod;
|
||||
public BigDecimal interestRatePerPeriod;
|
||||
@Schema(example = "1")
|
||||
public Integer amortizationType;
|
||||
@Schema(example = "5.5")
|
||||
@@ -1318,7 +1318,7 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(example = "0")
|
||||
public Integer repaymentFrequencyType;
|
||||
@Schema(example = "2")
|
||||
public Integer interestRatePerPeriod;
|
||||
public BigDecimal interestRatePerPeriod;
|
||||
@Schema(example = "0")
|
||||
public Integer interestType;
|
||||
@Schema(example = "0")
|
||||
|
||||
+93
-45
@@ -180,7 +180,7 @@ public final class LoanScheduleParams {
|
||||
final Money principalToBeScheduled = null;
|
||||
final Money outstandingBalance = null;
|
||||
final Money outstandingBalanceAsPerRest = null;
|
||||
final List<LoanRepaymentScheduleInstallment> installments = null;
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
final boolean partialUpdate = false;
|
||||
final int loanTermInDays = 0;
|
||||
final Money totalOutstandingInterestPaymentDueToGrace = null;
|
||||
@@ -266,6 +266,10 @@ public final class LoanScheduleParams {
|
||||
return this.periodNumber;
|
||||
}
|
||||
|
||||
public void setPeriodNumber(int periodNumber) {
|
||||
this.periodNumber = periodNumber;
|
||||
}
|
||||
|
||||
public int getInstalmentNumber() {
|
||||
return this.instalmentNumber;
|
||||
}
|
||||
@@ -274,12 +278,20 @@ public final class LoanScheduleParams {
|
||||
return this.actualRepaymentDate;
|
||||
}
|
||||
|
||||
public void setActualRepaymentDate(LocalDate actualRepaymentDate) {
|
||||
this.actualRepaymentDate = actualRepaymentDate;
|
||||
}
|
||||
|
||||
public Money getTotalCumulativePrincipal() {
|
||||
return this.totalCumulativePrincipal;
|
||||
}
|
||||
|
||||
public void addTotalCumulativePrincipal(final Money totalCumulativePrincipal) {
|
||||
this.totalCumulativePrincipal = this.totalCumulativePrincipal.plus(totalCumulativePrincipal);
|
||||
if (this.totalCumulativePrincipal != null) {
|
||||
this.totalCumulativePrincipal = this.totalCumulativePrincipal.plus(totalCumulativePrincipal);
|
||||
} else {
|
||||
this.totalCumulativePrincipal = totalCumulativePrincipal;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalCumulativeInterest() {
|
||||
@@ -287,7 +299,11 @@ public final class LoanScheduleParams {
|
||||
}
|
||||
|
||||
public void addTotalCumulativeInterest(final Money totalCumulativeInterest) {
|
||||
this.totalCumulativeInterest = this.totalCumulativeInterest.plus(totalCumulativeInterest);
|
||||
if (this.totalCumulativeInterest != null) {
|
||||
this.totalCumulativeInterest = this.totalCumulativeInterest.plus(totalCumulativeInterest);
|
||||
} else {
|
||||
this.totalCumulativeInterest = totalCumulativeInterest;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalFeeChargesCharged() {
|
||||
@@ -295,7 +311,11 @@ public final class LoanScheduleParams {
|
||||
}
|
||||
|
||||
public void addTotalFeeChargesCharged(final Money totalFeeChargesCharged) {
|
||||
this.totalFeeChargesCharged = this.totalFeeChargesCharged.plus(totalFeeChargesCharged);
|
||||
if (this.totalFeeChargesCharged != null) {
|
||||
this.totalFeeChargesCharged = this.totalFeeChargesCharged.plus(totalFeeChargesCharged);
|
||||
} else {
|
||||
this.totalFeeChargesCharged = totalFeeChargesCharged;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalPenaltyChargesCharged() {
|
||||
@@ -303,7 +323,11 @@ public final class LoanScheduleParams {
|
||||
}
|
||||
|
||||
public void addTotalPenaltyChargesCharged(final Money totalPenaltyChargesCharged) {
|
||||
this.totalPenaltyChargesCharged = this.totalPenaltyChargesCharged.plus(totalPenaltyChargesCharged);
|
||||
if (this.totalPenaltyChargesCharged != null) {
|
||||
this.totalPenaltyChargesCharged = this.totalPenaltyChargesCharged.plus(totalPenaltyChargesCharged);
|
||||
} else {
|
||||
this.totalPenaltyChargesCharged = totalPenaltyChargesCharged;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getTotalRepaymentExpected() {
|
||||
@@ -311,13 +335,21 @@ public final class LoanScheduleParams {
|
||||
}
|
||||
|
||||
public void addTotalRepaymentExpected(final Money totalRepaymentExpected) {
|
||||
this.totalRepaymentExpected = this.totalRepaymentExpected.plus(totalRepaymentExpected);
|
||||
if (this.totalRepaymentExpected != null) {
|
||||
this.totalRepaymentExpected = this.totalRepaymentExpected.plus(totalRepaymentExpected);
|
||||
} else {
|
||||
this.totalRepaymentExpected = totalRepaymentExpected;
|
||||
}
|
||||
}
|
||||
|
||||
public Money getReducePrincipal() {
|
||||
return this.reducePrincipal;
|
||||
}
|
||||
|
||||
public void setReducePrincipal(Money reducePrincipal) {
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
}
|
||||
|
||||
public Map<LocalDate, Money> getPrincipalPortionMap() {
|
||||
return this.principalPortionMap;
|
||||
}
|
||||
@@ -338,10 +370,18 @@ public final class LoanScheduleParams {
|
||||
return this.outstandingBalance;
|
||||
}
|
||||
|
||||
public void setOutstandingBalance(Money outstandingBalance) {
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
}
|
||||
|
||||
public Money getOutstandingBalanceAsPerRest() {
|
||||
return this.outstandingBalanceAsPerRest;
|
||||
}
|
||||
|
||||
public void setOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> getInstallments() {
|
||||
return this.installments;
|
||||
}
|
||||
@@ -366,12 +406,16 @@ public final class LoanScheduleParams {
|
||||
return this.periodStartDate;
|
||||
}
|
||||
|
||||
public void setPeriodStartDate(LocalDate periodStartDate) {
|
||||
this.periodStartDate = periodStartDate;
|
||||
}
|
||||
|
||||
public Money getPrincipalToBeScheduled() {
|
||||
return this.principalToBeScheduled;
|
||||
}
|
||||
|
||||
public void setPeriodNumber(int periodNumber) {
|
||||
this.periodNumber = periodNumber;
|
||||
public void setPrincipalToBeScheduled(Money principalToBeScheduled) {
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
}
|
||||
|
||||
public void incrementPeriodNumber() {
|
||||
@@ -382,56 +426,54 @@ public final class LoanScheduleParams {
|
||||
this.instalmentNumber++;
|
||||
}
|
||||
|
||||
public void setPeriodStartDate(LocalDate periodStartDate) {
|
||||
this.periodStartDate = periodStartDate;
|
||||
}
|
||||
|
||||
public void setActualRepaymentDate(LocalDate actualRepaymentDate) {
|
||||
this.actualRepaymentDate = actualRepaymentDate;
|
||||
}
|
||||
|
||||
public void setReducePrincipal(Money reducePrincipal) {
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
}
|
||||
|
||||
public void addReducePrincipal(Money reducePrincipal) {
|
||||
this.reducePrincipal = this.reducePrincipal.plus(reducePrincipal);
|
||||
if (this.reducePrincipal != null) {
|
||||
this.reducePrincipal = this.reducePrincipal.plus(reducePrincipal);
|
||||
} else {
|
||||
this.reducePrincipal = reducePrincipal;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceReducePrincipal(Money reducePrincipal) {
|
||||
this.reducePrincipal = this.reducePrincipal.minus(reducePrincipal);
|
||||
}
|
||||
|
||||
public void setPrincipalToBeScheduled(Money principalToBeScheduled) {
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
if (this.reducePrincipal != null) {
|
||||
this.reducePrincipal = this.reducePrincipal.minus(reducePrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPrincipalToBeScheduled(Money principalToBeScheduled) {
|
||||
this.principalToBeScheduled = this.principalToBeScheduled.plus(principalToBeScheduled);
|
||||
}
|
||||
|
||||
public void setOutstandingBalance(Money outstandingBalance) {
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
if (this.principalToBeScheduled != null) {
|
||||
this.principalToBeScheduled = this.principalToBeScheduled.plus(principalToBeScheduled);
|
||||
} else {
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
}
|
||||
}
|
||||
|
||||
public void addOutstandingBalance(Money outstandingBalance) {
|
||||
this.outstandingBalance = this.outstandingBalance.plus(outstandingBalance);
|
||||
if (this.outstandingBalance != null) {
|
||||
this.outstandingBalance = this.outstandingBalance.plus(outstandingBalance);
|
||||
} else {
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceOutstandingBalance(Money outstandingBalance) {
|
||||
this.outstandingBalance = this.outstandingBalance.minus(outstandingBalance);
|
||||
}
|
||||
|
||||
public void setOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
if (this.outstandingBalance != null) {
|
||||
this.outstandingBalance = this.outstandingBalance.minus(outstandingBalance);
|
||||
}
|
||||
}
|
||||
|
||||
public void addOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.plus(outstandingBalanceAsPerRest);
|
||||
if (this.outstandingBalanceAsPerRest != null) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.plus(outstandingBalanceAsPerRest);
|
||||
} else {
|
||||
this.outstandingBalanceAsPerRest = outstandingBalanceAsPerRest;
|
||||
}
|
||||
}
|
||||
|
||||
public void reduceOutstandingBalanceAsPerRest(Money outstandingBalanceAsPerRest) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.minus(outstandingBalanceAsPerRest);
|
||||
if (this.outstandingBalanceAsPerRest != null) {
|
||||
this.outstandingBalanceAsPerRest = this.outstandingBalanceAsPerRest.minus(outstandingBalanceAsPerRest);
|
||||
}
|
||||
}
|
||||
|
||||
public int getLoanTermInDays() {
|
||||
@@ -466,16 +508,22 @@ public final class LoanScheduleParams {
|
||||
return this.unCompoundedAmount;
|
||||
}
|
||||
|
||||
public void setUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
}
|
||||
|
||||
public void addUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.plus(unCompoundedAmount);
|
||||
if (this.unCompoundedAmount != null) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.plus(unCompoundedAmount);
|
||||
} else {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
}
|
||||
}
|
||||
|
||||
public void minusUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
|
||||
}
|
||||
|
||||
public void setUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
if (this.unCompoundedAmount != null) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFirstPeriod() {
|
||||
|
||||
+97
-66
@@ -132,18 +132,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms);
|
||||
|
||||
if (!scheduleParams.isPartialUpdate()) {
|
||||
Money downPaymentAmount = Money.zero(currency);
|
||||
if (loanApplicationTerms.isDownPaymentEnabled()) {
|
||||
downPaymentAmount = Money.of(currency, MathUtil.percentageOf(scheduleParams.getOutstandingBalance().getAmount(),
|
||||
loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
|
||||
if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
|
||||
downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount,
|
||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf());
|
||||
}
|
||||
|
||||
}
|
||||
Money calculatedAmortizableAmount = loanApplicationTerms.getPrincipal().minus(downPaymentAmount);
|
||||
scheduleParams.reduceOutstandingBalance(downPaymentAmount);
|
||||
Money calculatedAmortizableAmount = loanApplicationTerms.getPrincipal().minus(loanApplicationTerms.getDownPaymentAmount());
|
||||
// Set Fixed Principal Amount
|
||||
updateAmortization(mc, loanApplicationTerms, scheduleParams.getPeriodNumber(), calculatedAmortizableAmount);
|
||||
|
||||
@@ -161,9 +150,9 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
}
|
||||
Money remainingPrincipalAmt = disburseAmt.minus(downPaymentAmt);
|
||||
scheduleParams.setPrincipalToBeScheduled(remainingPrincipalAmt);
|
||||
loanApplicationTerms.setPrincipal(remainingPrincipalAmt);
|
||||
scheduleParams.setOutstandingBalance(remainingPrincipalAmt);
|
||||
scheduleParams.setOutstandingBalanceAsPerRest(remainingPrincipalAmt);
|
||||
loanApplicationTerms.setPrincipal(remainingPrincipalAmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +294,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
scheduleParams.getTotalCumulativePrincipal().minus(scheduleParams.getReducePrincipal()),
|
||||
scheduleParams.getTotalCumulativeInterest(), loanApplicationTerms.getTotalInterestDue(),
|
||||
scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(), scheduleParams.getOutstandingBalanceAsPerRest(),
|
||||
loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams),
|
||||
loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(loanApplicationTerms, scheduleParams),
|
||||
scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, scheduledDueDate, interestRates);
|
||||
|
||||
// will check for EMI amount greater than interest calculated
|
||||
@@ -427,10 +416,11 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
|
||||
updateCompoundingDetails(periods, scheduleParams, loanApplicationTerms);
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
|
||||
scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativePrincipal().getAmount(), totalPrincipalPaid,
|
||||
scheduleParams.getTotalCumulativeInterest().getAmount(), scheduleParams.getTotalFeeChargesCharged().getAmount(),
|
||||
scheduleParams.getTotalPenaltyChargesCharged().getAmount(), scheduleParams.getTotalRepaymentExpected().getAmount(),
|
||||
totalOutstanding);
|
||||
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount()),
|
||||
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount()).getAmount(),
|
||||
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
||||
scheduleParams.getTotalFeeChargesCharged().getAmount(), scheduleParams.getTotalPenaltyChargesCharged().getAmount(),
|
||||
scheduleParams.getTotalRepaymentExpected().getAmount(), totalOutstanding);
|
||||
}
|
||||
|
||||
private void updateCompoundingDetails(final Collection<LoanScheduleModelPeriod> periods, final LoanScheduleParams params,
|
||||
@@ -510,7 +500,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
|
||||
|
||||
// update outstanding balance for interest calculation
|
||||
updateOutstandingBalanceAsPerRest(scheduleParams, scheduledDueDate);
|
||||
updateOutstandingBalanceAsPerRest(loanApplicationTerms, scheduleParams, scheduledDueDate);
|
||||
}
|
||||
|
||||
private LoanScheduleModelPeriod handleRecalculationForTransactions(final MathContext mc,
|
||||
@@ -630,8 +620,8 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, scheduleParams.getTotalCumulativePrincipal(),
|
||||
scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm,
|
||||
lastTotalOutstandingInterestPaymentDueToGrace, scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms,
|
||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams), scheduleParams.getCompoundingMap(),
|
||||
periodStartDateApplicableForInterest, calculateTill, interestRates);
|
||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(loanApplicationTerms, scheduleParams),
|
||||
scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, calculateTill, interestRates);
|
||||
loanApplicationTerms.updateAnnualNominalInterestRate(currentInterestRate);
|
||||
|
||||
// applies charges for the period
|
||||
@@ -767,7 +757,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm,
|
||||
scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(),
|
||||
scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms,
|
||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams),
|
||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(loanApplicationTerms, scheduleParams),
|
||||
scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, transactionDate,
|
||||
interestRates);
|
||||
interestForCurrentInstallment = principalInterestForThisPeriod.interest();
|
||||
@@ -805,7 +795,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
|
||||
// update outstanding balance for interest
|
||||
// calculation as per the rest
|
||||
updateOutstandingBalanceAsPerRest(scheduleParams, transactionDate);
|
||||
updateOutstandingBalanceAsPerRest(loanApplicationTerms, scheduleParams, transactionDate);
|
||||
|
||||
// handle cumulative fields
|
||||
scheduleParams.addLoanTermInDays(periodDays);
|
||||
@@ -898,9 +888,9 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm,
|
||||
scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(),
|
||||
scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms,
|
||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams),
|
||||
scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, transactionDate,
|
||||
interestRates);
|
||||
scheduleParams.getPeriodNumber(), mc,
|
||||
mergeVariationsToMap(loanApplicationTerms, scheduleParams), scheduleParams.getCompoundingMap(),
|
||||
periodStartDateApplicableForInterest, transactionDate, interestRates);
|
||||
if (!principalInterestForThisPeriod.interest()
|
||||
.plus(principalInterestForThisPeriod.interestPaymentDueToGrace())
|
||||
.plus(scheduleParams.getOutstandingBalance()).isGreaterThan(unprocessed)) {
|
||||
@@ -971,11 +961,37 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
scheduleParams.addTotalCumulativePrincipal(unprocessed.plus(addToPrincipal));
|
||||
}
|
||||
|
||||
private void updateOutstandingBalanceAsPerRest(final LoanScheduleParams scheduleParams, final LocalDate scheduledDueDate) {
|
||||
private void updateOutstandingBalanceAsPerRest(LoanApplicationTerms loanApplicationTerms, final LoanScheduleParams scheduleParams,
|
||||
final LocalDate scheduledDueDate) {
|
||||
scheduleParams.setOutstandingBalanceAsPerRest(updateBalanceForInterestCalculation(scheduleParams.getPrincipalPortionMap(),
|
||||
scheduledDueDate, scheduleParams.getOutstandingBalanceAsPerRest(), false));
|
||||
scheduleParams.setOutstandingBalanceAsPerRest(updateBalanceForInterestCalculation(scheduleParams.getDisburseDetailMap(),
|
||||
scheduledDueDate, scheduleParams.getOutstandingBalanceAsPerRest(), true));
|
||||
scheduledDueDate, scheduleParams.getOutstandingBalanceAsPerRest()));
|
||||
scheduleParams.setOutstandingBalanceAsPerRest(calculateOutstandingBalanceAsPerRest(loanApplicationTerms,
|
||||
scheduleParams.getDisburseDetailMap(), scheduledDueDate, scheduleParams.getOutstandingBalanceAsPerRest()));
|
||||
}
|
||||
|
||||
private Money calculateOutstandingBalanceAsPerRest(LoanApplicationTerms loanApplicationTerms, Map<LocalDate, Money> disburseDetailMap,
|
||||
LocalDate scheduledDueDate, Money outstandingBalance) {
|
||||
List<LocalDate> removeFromMap = new ArrayList<>();
|
||||
for (Map.Entry<LocalDate, Money> entry : disburseDetailMap.entrySet()) {
|
||||
if (!DateUtils.isAfter(entry.getKey(), scheduledDueDate)) {
|
||||
Money downPaymentAmount = Money.zero(loanApplicationTerms.getCurrency());
|
||||
if (loanApplicationTerms.isDownPaymentEnabled()) {
|
||||
downPaymentAmount = Money.of(loanApplicationTerms.getCurrency(), MathUtil.percentageOf(entry.getValue().getAmount(),
|
||||
loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
|
||||
if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
|
||||
downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount,
|
||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf());
|
||||
}
|
||||
}
|
||||
outstandingBalance = outstandingBalance.plus(entry.getValue()).minus(downPaymentAmount);
|
||||
|
||||
removeFromMap.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
for (LocalDate date : removeFromMap) {
|
||||
disburseDetailMap.remove(date);
|
||||
}
|
||||
return outstandingBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1305,7 +1321,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
} else {
|
||||
principalToBeScheduled = loanApplicationTerms.getPrincipal();
|
||||
}
|
||||
return principalToBeScheduled;
|
||||
return principalToBeScheduled.minus(loanApplicationTerms.getDownPaymentAmount());
|
||||
}
|
||||
|
||||
private boolean updateFixedInstallmentAmount(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, int periodNumber,
|
||||
@@ -1389,8 +1405,8 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
getPaymentPeriodsInOneYearCalculator(), interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
||||
periodNumberTemp, mc, mergeVariationsToMap(params), params.getCompoundingMap(), params.getPeriodStartDate(),
|
||||
transactionDate, applicableVariations);
|
||||
periodNumberTemp, mc, mergeVariationsToMap(loanApplicationTerms, params), params.getCompoundingMap(),
|
||||
params.getPeriodStartDate(), transactionDate, applicableVariations);
|
||||
|
||||
Money interest = principalInterestForThisPeriod.interest();
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
@@ -1421,7 +1437,7 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
outstanding = outstanding.zero();
|
||||
} else {
|
||||
outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(),
|
||||
outstanding, false);
|
||||
outstanding);
|
||||
}
|
||||
if (params.getLatePaymentMap().isEmpty() && outstanding.isZero()) {
|
||||
break;
|
||||
@@ -1432,8 +1448,8 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
getPaymentPeriodsInOneYearCalculator(), interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
||||
periodNumberTemp, mc, mergeVariationsToMap(params), params.getCompoundingMap(), params.getPeriodStartDate(),
|
||||
params.getActualRepaymentDate(), applicableVariations);
|
||||
periodNumberTemp, mc, mergeVariationsToMap(loanApplicationTerms, params), params.getCompoundingMap(),
|
||||
params.getPeriodStartDate(), params.getActualRepaymentDate(), applicableVariations);
|
||||
Money interest = principalInterestForThisPeriod.interest();
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
|
||||
@@ -1562,16 +1578,12 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
* Identifies all the past date principal changes and apply them on outstanding balance for future calculations
|
||||
*/
|
||||
private Money updateBalanceForInterestCalculation(final Map<LocalDate, Money> principalPortionMap, final LocalDate scheduledDueDate,
|
||||
final Money outstandingBalanceAsPerRest, boolean addMapDetails) {
|
||||
final Money outstandingBalanceAsPerRest) {
|
||||
List<LocalDate> removeFromPrincipalPortionMap = new ArrayList<>();
|
||||
Money outstandingBalance = outstandingBalanceAsPerRest;
|
||||
for (Map.Entry<LocalDate, Money> principal : principalPortionMap.entrySet()) {
|
||||
if (!DateUtils.isAfter(principal.getKey(), scheduledDueDate)) {
|
||||
if (addMapDetails) {
|
||||
outstandingBalance = outstandingBalance.plus(principal.getValue());
|
||||
} else {
|
||||
outstandingBalance = outstandingBalance.minus(principal.getValue());
|
||||
}
|
||||
outstandingBalance = outstandingBalance.minus(principal.getValue());
|
||||
removeFromPrincipalPortionMap.add(principal.getKey());
|
||||
}
|
||||
}
|
||||
@@ -1852,13 +1864,22 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
* as per rest) changes to single map for interest calculation
|
||||
*
|
||||
*/
|
||||
private TreeMap<LocalDate, Money> mergeVariationsToMap(final LoanScheduleParams params) {
|
||||
private TreeMap<LocalDate, Money> mergeVariationsToMap(LoanApplicationTerms loanApplicationTerms, final LoanScheduleParams params) {
|
||||
TreeMap<LocalDate, Money> map = new TreeMap<>(params.getLatePaymentMap());
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : params.getDisburseDetailMap().entrySet()) {
|
||||
Money value = mapEntry.getValue();
|
||||
if (map.containsKey(mapEntry.getKey())) {
|
||||
value = value.plus(map.get(mapEntry.getKey()));
|
||||
}
|
||||
if (loanApplicationTerms.isDownPaymentEnabled()) {
|
||||
Money downPaymentAmount = Money.of(loanApplicationTerms.getCurrency(),
|
||||
MathUtil.percentageOf(value.getAmount(), loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
|
||||
if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
|
||||
downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount,
|
||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf());
|
||||
}
|
||||
value = value.minus(downPaymentAmount);
|
||||
}
|
||||
map.put(mapEntry.getKey(), value);
|
||||
}
|
||||
|
||||
@@ -2235,33 +2256,30 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
LocalDate periodStartDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(loanApplicationTerms.getRepaymentStartDateType())
|
||||
? loanApplicationTerms.getExpectedDisbursementDate()
|
||||
: loanApplicationTerms.getSubmittedOnDate();
|
||||
Money downPaymentAmount = Money.zero(currency);
|
||||
if (loanApplicationTerms.isDownPaymentEnabled()) {
|
||||
downPaymentAmount = Money.of(currency, MathUtil.percentageOf(loanScheduleParams.getOutstandingBalance().getAmount(),
|
||||
loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
|
||||
if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
|
||||
downPaymentAmount = Money.roundToMultiplesOf(downPaymentAmount,
|
||||
loanApplicationTerms.getInstallmentAmountInMultiplesOf());
|
||||
}
|
||||
}
|
||||
Money calculatedAmortizableAmount = principalToBeScheduled.minus(downPaymentAmount);
|
||||
loanScheduleParams.setOutstandingBalance(calculatedAmortizableAmount);
|
||||
// Set fixed Amortization Amounts(either EMI or Principal )
|
||||
updateAmortization(mc, loanApplicationTerms, periodNumber, calculatedAmortizableAmount);
|
||||
updateAmortization(mc, loanApplicationTerms, periodNumber, outstandingBalance);
|
||||
|
||||
// count periods without interest grace to exclude for flat loan
|
||||
// calculations
|
||||
|
||||
final Map<LocalDate, Money> disburseDetailMap = new HashMap<>();
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
// fetches the first tranche amount and also updates other
|
||||
// tranche
|
||||
// details to map
|
||||
BigDecimal disburseAmt = getDisbursementAmount(loanApplicationTerms, loanApplicationTerms.getExpectedDisbursementDate(),
|
||||
disburseDetailMap, true);
|
||||
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
|
||||
outstandingBalanceAsPerRest = outstandingBalance;
|
||||
principalToBeScheduled = principalToBeScheduled.zero().plus(disburseAmt);
|
||||
/* fetches the first tranche amount and also updates other tranche details to map */
|
||||
Money disburseAmt = Money.of(currency,
|
||||
getDisbursementAmount(loanApplicationTerms, loanApplicationTerms.getExpectedDisbursementDate(), disburseDetailMap,
|
||||
loanScheduleParams.applyInterestRecalculation()));
|
||||
Money downPaymentAmt = Money.zero(currency);
|
||||
if (loanApplicationTerms.isDownPaymentEnabled()) {
|
||||
downPaymentAmt = Money.of(currency, MathUtil.percentageOf(disburseAmt.getAmount(),
|
||||
loanApplicationTerms.getDisbursedAmountPercentageForDownPayment(), 19));
|
||||
if (loanApplicationTerms.getInstallmentAmountInMultiplesOf() != null) {
|
||||
downPaymentAmt = Money.roundToMultiplesOf(downPaymentAmt, loanApplicationTerms.getInstallmentAmountInMultiplesOf());
|
||||
}
|
||||
}
|
||||
Money remainingPrincipalAmt = disburseAmt.minus(downPaymentAmt);
|
||||
outstandingBalance = remainingPrincipalAmt;
|
||||
outstandingBalanceAsPerRest = remainingPrincipalAmt;
|
||||
principalToBeScheduled = remainingPrincipalAmt;
|
||||
}
|
||||
int loanTermInDays = 0;
|
||||
|
||||
@@ -2279,6 +2297,12 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
// This will create the recalculation details by applying the
|
||||
// transactions
|
||||
for (LoanRepaymentScheduleInstallment installment : processInstallmentsInstallments) {
|
||||
if (installment.isDownPayment()) {
|
||||
instalmentNumber++;
|
||||
periods.add(createLoanScheduleModelDownPaymentPeriod(installment, outstandingBalance));
|
||||
newRepaymentScheduleInstallments.add(installment);
|
||||
continue;
|
||||
}
|
||||
// this will generate the next schedule due date and allows to
|
||||
// process the installment only if recalculate from date is
|
||||
// greater than due date
|
||||
@@ -2442,9 +2466,9 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
|
||||
// update outstanding balance for interest calculation
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, installment.getDueDate(),
|
||||
outstandingBalanceAsPerRest, false);
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap, installment.getDueDate(),
|
||||
outstandingBalanceAsPerRest, true);
|
||||
outstandingBalanceAsPerRest);
|
||||
outstandingBalanceAsPerRest = calculateOutstandingBalanceAsPerRest(loanApplicationTerms, disburseDetailMap,
|
||||
installment.getDueDate(), outstandingBalanceAsPerRest);
|
||||
// updates the map with over due amounts
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, lastInstallmentDate,
|
||||
newRepaymentScheduleInstallments, true, lastRestDate);
|
||||
@@ -2692,6 +2716,13 @@ public abstract class AbstractCumulativeLoanScheduleGenerator implements LoanSch
|
||||
return installment;
|
||||
}
|
||||
|
||||
private LoanScheduleModelPeriod createLoanScheduleModelDownPaymentPeriod(final LoanRepaymentScheduleInstallment installment,
|
||||
final Money outstandingPrincipal) {
|
||||
final MonetaryCurrency currency = outstandingPrincipal.getCurrency();
|
||||
return LoanScheduleModelDownPaymentPeriod.downPayment(installment.getInstallmentNumber(), installment.getDueDate(),
|
||||
installment.getPrincipal(currency), outstandingPrincipal);
|
||||
}
|
||||
|
||||
private LoanScheduleModelPeriod createLoanScheduleModelPeriod(final LoanRepaymentScheduleInstallment installment,
|
||||
final Money outstandingPrincipal) {
|
||||
final MonetaryCurrency currency = outstandingPrincipal.getCurrency();
|
||||
|
||||
+5
-4
@@ -188,10 +188,11 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc
|
||||
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
|
||||
scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativePrincipal().getAmount(), totalPrincipalPaid,
|
||||
scheduleParams.getTotalCumulativeInterest().getAmount(), scheduleParams.getTotalFeeChargesCharged().getAmount(),
|
||||
scheduleParams.getTotalPenaltyChargesCharged().getAmount(), scheduleParams.getTotalRepaymentExpected().getAmount(),
|
||||
totalOutstanding);
|
||||
scheduleParams.getPrincipalToBeScheduled().plus(loanApplicationTerms.getDownPaymentAmount()),
|
||||
scheduleParams.getTotalCumulativePrincipal().plus(loanApplicationTerms.getDownPaymentAmount()).getAmount(),
|
||||
totalPrincipalPaid, scheduleParams.getTotalCumulativeInterest().getAmount(),
|
||||
scheduleParams.getTotalFeeChargesCharged().getAmount(), scheduleParams.getTotalPenaltyChargesCharged().getAmount(),
|
||||
scheduleParams.getTotalRepaymentExpected().getAmount(), totalOutstanding);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-7
@@ -23,7 +23,6 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
@@ -675,8 +674,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element, disbursementDetails);
|
||||
|
||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
|
||||
LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getLoanScheduleType(),
|
||||
@@ -703,8 +701,8 @@ public class LoanScheduleAssembler {
|
||||
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
Loan loan, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
final LocalDate rescheduleFrom) {
|
||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId,
|
||||
@@ -723,8 +721,8 @@ public class LoanScheduleAssembler {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getLoanScheduleType(),
|
||||
loanApplicationTerms.getInterestMethod());
|
||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId,
|
||||
|
||||
+2
-3
@@ -19,7 +19,6 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
|
||||
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -127,8 +126,8 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
||||
}
|
||||
|
||||
loanApplicationTerms.getLoanTermVariations().updateLoanTermVariationsData(loanTermVariationsData);
|
||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||
final MathContext mathContext = new MathContext(8, roundingMode);
|
||||
|
||||
final MathContext mathContext = MoneyHelper.getMathContext();
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getLoanScheduleType(),
|
||||
|
||||
+1
-3
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
@@ -432,8 +431,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
* loanTermVariation.setApplicableFromDate(adjustedDate); } } }
|
||||
*/
|
||||
|
||||
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
|
||||
final MathContext mathContext = new MathContext(8, roundingMode);
|
||||
final MathContext mathContext = MoneyHelper.getMathContext();
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getLoanScheduleType(),
|
||||
|
||||
Reference in New Issue
Block a user