MIFOSX-1524 : corrected Interest waiver
This commit is contained in:
+2
-2
@@ -1991,7 +1991,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return isDisbursementMissed;
|
||||
}
|
||||
|
||||
private BigDecimal getDisbursedAmount() {
|
||||
public BigDecimal getDisbursedAmount() {
|
||||
BigDecimal principal = BigDecimal.ZERO;
|
||||
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
|
||||
if (disbursementDetail.actualDisbursementDate() != null) {
|
||||
@@ -4282,7 +4282,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate());
|
||||
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
|
||||
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc);
|
||||
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges());
|
||||
} else {
|
||||
installment = this.getTotalOutstandingOnLoan();
|
||||
}
|
||||
|
||||
+1
-1
@@ -436,7 +436,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||
Money waivedFeeChargesPortionOfTransaction = Money.zero(currency);
|
||||
|
||||
final Money feesDue = getPenaltyChargesOutstanding(currency);
|
||||
final Money feesDue = getFeeChargesOutstanding(currency);
|
||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
|
||||
this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount();
|
||||
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue);
|
||||
|
||||
+5
@@ -301,4 +301,9 @@ public final class LoanSummary {
|
||||
public BigDecimal getTotalPenaltyChargesCharged() {
|
||||
return this.totalPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalPrincipalWrittenOff() {
|
||||
return this.totalPrincipalWrittenOff;
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -123,7 +123,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
transactionstoBeProcessed.add(loanTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (final LoanTransaction loanTransaction : transactionstoBeProcessed) {
|
||||
|
||||
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
@@ -451,11 +451,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
transactionDate = recalculationDates.get(transactionDate);
|
||||
}
|
||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) {
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
}
|
||||
Money unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
|
||||
if (transactionDate.isAfter(installment.getFromDate()) && transactionDate.isBefore(installment.getDueDate())) {
|
||||
Money earlyPayment = currentInstallmentOutstanding.minus(installment.getTotalOutstanding(currency));
|
||||
if (earlyPayment.isGreaterThanZero()) {
|
||||
if (earlyPayment.isGreaterThanZero() && (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment())) {
|
||||
earlypaymentDetail.add(new RecalculationDetail(false, transactionDate, null, earlyPayment, false));
|
||||
}
|
||||
currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
|
||||
|
||||
+97
-64
@@ -53,12 +53,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
||||
final List<Holiday> holidays, final WorkingDays workingDays) {
|
||||
final List<RecalculationDetail> diffAmt = null;
|
||||
return generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays, diffAmt);
|
||||
final LocalDate prepayDate = null;
|
||||
return generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays, diffAmt,
|
||||
prepayDate);
|
||||
}
|
||||
|
||||
private LoanScheduleModel generate(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
||||
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, List<RecalculationDetail> diffAmt) {
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, List<RecalculationDetail> diffAmt, LocalDate prepayDate) {
|
||||
|
||||
// 1. generate list of proposed schedule due dates
|
||||
final LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, isHolidayEnabled, holidays,
|
||||
@@ -191,8 +193,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate);
|
||||
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||
disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, scheduledDueDate, disbursementDatas,
|
||||
diffAmt != null);
|
||||
LocalDate tillDate = scheduledDueDate;
|
||||
if (prepayDate != null && prepayDate.isBefore(tillDate)) {
|
||||
tillDate = prepayDate;
|
||||
}
|
||||
disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, tillDate, disbursementDatas, diffAmt != null);
|
||||
principalDisbursed = principalDisbursed.plus(disburseAmt);
|
||||
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseAmt));
|
||||
outstandingBalance = outstandingBalance.plus(disburseAmt);
|
||||
@@ -207,11 +212,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod.disbursement(
|
||||
disbursementData.disbursementDate(), disbursedAmt, chargesDueAtTimeOfDisbursement);
|
||||
periods.add(disbursementPeriod);
|
||||
if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)) {
|
||||
|
||||
if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)
|
||||
&& (prepayDate == null || prepayDate.isAfter(disbursementData.disbursementDate()) || disbursementData
|
||||
.isDisbursed())) {
|
||||
interestToBeAdded = interestToBeAdded.add(calculateInterestForSpecificDays(mc, loanApplicationTerms, periodNumber,
|
||||
totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableInFullInstallment,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, disbursementData.disbursementDate(),
|
||||
scheduledDueDate));
|
||||
tillDate));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,14 +232,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
case REDUCE_EMI_AMOUNT:
|
||||
loanApplicationTerms.setFixedEmiAmount(null);
|
||||
outstandingBalance = outstandingBalance.minus(reducePrincipal);
|
||||
balanceForcalculation = outstandingBalance;
|
||||
balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
|
||||
reducePrincipal = reducePrincipal.zero();
|
||||
break;
|
||||
case REDUCE_NUMBER_OF_INSTALLMENTS:
|
||||
loanApplicationTerms.setFixedEmiAmount(fixedEmiAmount.getAmount());
|
||||
outstandingBalance = outstandingBalance.minus(reducePrincipal);
|
||||
balanceForcalculation = outstandingBalance;
|
||||
balanceForcalculation = balanceForcalculation.minus(reducePrincipal);
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal);
|
||||
reducePrincipal = reducePrincipal.zero();
|
||||
break;
|
||||
@@ -1022,11 +1030,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
List<LoanRepaymentScheduleInstallment> installments = previousSchedule;
|
||||
List<LoanRepaymentScheduleInstallment> removeInstallments = new ArrayList<>();
|
||||
MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
|
||||
LoanTransaction preCloseTransaction = getPreclosureTransaction(transactions, installments, currency, loanApplicationTerms, mc);
|
||||
LoanTransaction preCloseTransaction = getPreclosureTransaction(transactions, installments, currency, loanApplicationTerms, mc,
|
||||
loanCharges);
|
||||
Integer updatedInstallmentNumber = 1;
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (installment.isRecalculatedInterestComponent() && recalculateFrom != null
|
||||
&& !recalculateFrom.isAfter(installment.getDueDate())) {
|
||||
removeInstallments.add(installment);
|
||||
} else {
|
||||
installment.updateInstallmentNumber(updatedInstallmentNumber++);
|
||||
}
|
||||
}
|
||||
installments.removeAll(removeInstallments);
|
||||
@@ -1097,12 +1109,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final List<RecalculationDetail> recalculationDetails, final Map<LocalDate, RecalculationDetail> retainRecalculationDetails,
|
||||
boolean recalculate, int installmentNumber, List<LoanTransaction> processTransactions, LoanTransaction preCloseTransaction) {
|
||||
LoanTransaction loanTransaction = processTransactions.remove(processTransactions.size() - 1);
|
||||
if (loanTransaction == preCloseTransaction) {
|
||||
if (!(loanTransaction.isRepayment() || loanTransaction.isInterestWaiver())) {
|
||||
processTransactions.add(loanTransaction);
|
||||
return loanScheduleModel;
|
||||
}
|
||||
LocalDate processTransactionsForInterestCompound = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
|
||||
loanApplicationTerms, isHolidayEnabled, holidays, workingDays);
|
||||
LocalDate processTransactionsForInterestCompound = loanTransaction.getTransactionDate();
|
||||
if (loanTransaction != preCloseTransaction) {
|
||||
processTransactionsForInterestCompound = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
|
||||
loanApplicationTerms, isHolidayEnabled, holidays, workingDays);
|
||||
}
|
||||
List<LoanRepaymentScheduleInstallment> scheduleInstallments = getInstallmentsForInterestCompound(installments,
|
||||
processTransactionsForInterestCompound, retainRecalculationDetails.keySet());
|
||||
|
||||
@@ -1214,7 +1229,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final int installmentNumber,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final List<RecalculationDetail> recalculationDetails,
|
||||
final int skipRecalculation, LoanTransaction preCloseTransaction) {
|
||||
final int skipRecalculation, final LoanTransaction preCloseTransaction) {
|
||||
boolean processRecalculate = false;
|
||||
int processedInstallmentNumber = installmentNumber;
|
||||
|
||||
@@ -1324,8 +1339,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LoanScheduleModel model = null;
|
||||
recalculationDetails.addAll(diffAmt);
|
||||
if (processRecalculate) {
|
||||
LocalDate prepayDate = null;
|
||||
if (preCloseTransaction != null) {
|
||||
prepayDate = preCloseTransaction.getTransactionDate();
|
||||
}
|
||||
model = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays,
|
||||
recalculationDetails);
|
||||
recalculationDetails, prepayDate);
|
||||
}
|
||||
return new RecalculatedSchedule(model, processedInstallmentNumber);
|
||||
}
|
||||
@@ -1392,7 +1411,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
@Override
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, final LocalDate onDate, LocalDate interestChargedFromLocalDate,
|
||||
LoanApplicationTerms loanApplicationTerms, MathContext mc) {
|
||||
LoanApplicationTerms loanApplicationTerms, MathContext mc, Set<LoanCharge> charges) {
|
||||
Money feeCharges = Money.zero(currency);
|
||||
Money penaltyCharges = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
@@ -1400,12 +1419,21 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LocalDate calculateInterestFrom = onDate;
|
||||
LocalDate dueDate = onDate;
|
||||
LocalDate repaymentDueDate = null;
|
||||
LocalDate periodStartDate = onDate;
|
||||
boolean isInterestRepayment = false;
|
||||
Money inerestForCurrentInstallment = Money.zero(currency);
|
||||
Money principalOutstanding = Money.zero(currency);
|
||||
Integer periodNumber = 0;
|
||||
LocalDate lastDueDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
if (!currentInstallment.getDueDate().isAfter(LocalDate.now())) {
|
||||
calculateInterestFrom = currentInstallment.getFromDate();
|
||||
if (currentInstallment.isRecalculatedInterestComponent()) {
|
||||
isInterestRepayment = true;
|
||||
} else {
|
||||
isInterestRepayment = false;
|
||||
}
|
||||
}
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (!currentInstallment.getDueDate().isAfter(onDate)) {
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
@@ -1417,8 +1445,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalPrincipal = totalPrincipal.minus(currentInstallment.getPrincipalCompleted(currency));
|
||||
totalInterest = totalInterest.minus(currentInstallment.getInterestPaid(currency)).minus(
|
||||
currentInstallment.getInterestWaived(currency));
|
||||
if (currentInstallment.getFromDate().isBefore(calculateInterestFrom)) {
|
||||
calculateInterestFrom = currentInstallment.getFromDate();
|
||||
if (currentInstallment.getFromDate().isBefore(periodStartDate)) {
|
||||
if (!isInterestRepayment) {
|
||||
calculateInterestFrom = currentInstallment.getFromDate();
|
||||
}
|
||||
periodStartDate = currentInstallment.getFromDate();
|
||||
dueDate = currentInstallment.getDueDate();
|
||||
inerestForCurrentInstallment = currentInstallment.getInterestCharged(currency);
|
||||
if (currentInstallment.isRecalculatedInterestComponent()) {
|
||||
@@ -1443,8 +1474,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
calculateInterestFrom = interestChargedFromLocalDate;
|
||||
}
|
||||
Money interest = Money.zero(currency);
|
||||
|
||||
if (calculateInterestFrom.isBefore(onDate)) {
|
||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
||||
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, true);
|
||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
|
||||
if (calculateInterestFrom.isBefore(onDate) && !periodStartDate.isBefore(idealDisbursementDate)) {
|
||||
boolean useDailyInterest = false;
|
||||
if (repaymentDueDate == null) {
|
||||
if (isInterestRepayment) {
|
||||
@@ -1453,7 +1487,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
repaymentDueDate = dueDate;
|
||||
}
|
||||
int daysInPeriodApplicableForInterest = Days.daysBetween(calculateInterestFrom, repaymentDueDate).getDays();
|
||||
int days = Days.daysBetween(calculateInterestFrom, onDate).getDays();
|
||||
int days = Days.daysBetween(periodStartDate, onDate).getDays();
|
||||
int actualPeriodDays = Days.daysBetween(periodStartDate, repaymentDueDate).getDays();
|
||||
BigDecimal interestForInstallment = BigDecimal.ZERO;
|
||||
if (useDailyInterest) {
|
||||
interestForInstallment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
||||
@@ -1462,11 +1497,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, interestForInstallment, days));
|
||||
|
||||
} else {
|
||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
||||
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, true);
|
||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator
|
||||
.idealDisbursementDateBasedOnFirstRepaymentDate(loanApplicationTerms.getLoanTermPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
|
||||
|
||||
LocalDate periodStartDateApplicableForInterest = calculateInterestFrom;
|
||||
if (calculateInterestFrom.isBefore(idealDisbursementDate)) {
|
||||
if (loanApplicationTerms.getInterestChargedFromLocalDate() != null) {
|
||||
@@ -1481,58 +1512,48 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, repaymentDueDate,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(),
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
||||
|
||||
Money calculateInterestOnPrincipal = principalOutstanding;
|
||||
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
BigDecimal reducePrincipal = disbursementAfterPeriod(loanApplicationTerms, repaymentDueDate, lastDueDate);
|
||||
principalOutstanding = principalOutstanding.minus(reducePrincipal);
|
||||
calculateInterestOnPrincipal = principalOutstanding;
|
||||
BigDecimal currentPeriodDisbursal = disbursementForPeriod(loanApplicationTerms, periodStartDate, repaymentDueDate,
|
||||
disbursementDatas, true);
|
||||
calculateInterestOnPrincipal = calculateInterestOnPrincipal.minus(currentPeriodDisbursal);
|
||||
}
|
||||
|
||||
PrincipalInterest principalInterest = loanApplicationTerms.calculateTotalInterestForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc,
|
||||
totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, principalOutstanding);
|
||||
interestForInstallment = principalInterest.interest().getAmount();
|
||||
Money alteredPrincipal = principalOutstanding;
|
||||
Money reducePricipal = principalOutstanding.zero();
|
||||
totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, calculateInterestOnPrincipal);
|
||||
interestForInstallment = BigDecimal.valueOf(calculateInterestForDays(daysInPeriodApplicableForInterest, principalInterest
|
||||
.interest().getAmount(), actualPeriodDays));
|
||||
BigDecimal interestToBeAdded = BigDecimal.ZERO;
|
||||
BigDecimal interestToBeReduced = BigDecimal.ZERO;
|
||||
BigDecimal interestForExtraPrincipal = BigDecimal.ZERO;
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||
BigDecimal addedPrincipal = disbursementForPeriod(loanApplicationTerms, calculateInterestFrom, repaymentDueDate,
|
||||
disbursementDatas, true);
|
||||
alteredPrincipal = alteredPrincipal.minus(addedPrincipal);
|
||||
for (DisbursementData disbursementData : disbursementDatas) {
|
||||
Money disbursedAmt = Money.of(currency, disbursementData.amount());
|
||||
if (disbursementData.disbursementDate().isAfter(calculateInterestFrom)) {
|
||||
LocalDate calculateTill = disbursementData.disbursementDate();
|
||||
LocalDate calculateTill = disbursementData.disbursementDate();
|
||||
if (!onDate.isAfter(calculateTill)) {
|
||||
principalOutstanding = principalOutstanding.minus(disbursedAmt);
|
||||
} else {
|
||||
interestToBeAdded = interestToBeAdded.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
|
||||
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateTill, onDate));
|
||||
}
|
||||
|
||||
if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)) {
|
||||
interestToBeReduced = interestToBeReduced.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
|
||||
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateInterestFrom, calculateTill));
|
||||
|
||||
if (onDate.isAfter(calculateTill)) {
|
||||
interestForExtraPrincipal = interestForExtraPrincipal.add(calculateInterestForSpecificDays(mc,
|
||||
loanApplicationTerms, periodNumber, totalOutstandingInterestPaymentDueToGrace,
|
||||
daysInPeriodApplicableForInterest, interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt,
|
||||
calculateTill, onDate));
|
||||
} else {
|
||||
reducePricipal = reducePricipal.plus(disbursedAmt);
|
||||
}
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateTill, repaymentDueDate));
|
||||
}
|
||||
}
|
||||
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment).plus(interestToBeReduced));
|
||||
BigDecimal interestForCloseDate = BigDecimal.ZERO;
|
||||
if (alteredPrincipal.isNotEqualTo(principalOutstanding)) {
|
||||
interestForCloseDate = interestForExtraPrincipal;
|
||||
interestForCloseDate = interestForCloseDate.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
|
||||
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, alteredPrincipal, calculateInterestFrom, onDate));
|
||||
} else {
|
||||
interestForCloseDate = interestForCloseDate.add(BigDecimal.valueOf(calculateInterestForDays(
|
||||
daysInPeriodApplicableForInterest, interestForInstallment, days)));
|
||||
}
|
||||
interest = interest.plus(interestForCloseDate);
|
||||
principalOutstanding = principalOutstanding.minus(reducePricipal);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment).minus(interestToBeReduced));
|
||||
BigDecimal interestForCloseDate = BigDecimal.valueOf(calculateInterestForDays(actualPeriodDays, interestForInstallment,
|
||||
days));
|
||||
interest = interest.plus(interestForCloseDate).plus(interestToBeAdded);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1540,6 +1561,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
totalPrincipal = totalPrincipal.plus(principalOutstanding);
|
||||
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
if (loanCharge.isActive() && loanCharge.isNotFullyPaid() && !loanCharge.isWaived()
|
||||
&& loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStartDate, onDate)) {
|
||||
if (loanCharge.isFeeCharge()) {
|
||||
feeCharges = feeCharges.plus(loanCharge.amountOutstanding());
|
||||
} else {
|
||||
penaltyCharges = penaltyCharges.plus(loanCharge.amountOutstanding());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
|
||||
feeCharges.getAmount(), penaltyCharges.getAmount(), false);
|
||||
}
|
||||
@@ -1588,7 +1620,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
private LoanTransaction getPreclosureTransaction(List<LoanTransaction> loanTransactions,
|
||||
List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency, final LoanApplicationTerms applicationTerms,
|
||||
MathContext mc) {
|
||||
MathContext mc, final Set<LoanCharge> loanCharges) {
|
||||
LoanTransaction precloseTransaction = null;
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
if (precloseTransaction == null || precloseTransaction.getTransactionDate().isBefore(loanTransaction.getTransactionDate())) {
|
||||
@@ -1597,7 +1629,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
if (precloseTransaction != null) {
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = calculatePrepaymentAmount(installments, currency,
|
||||
precloseTransaction.getTransactionDate(), applicationTerms.getInterestChargedFromLocalDate(), applicationTerms, mc);
|
||||
precloseTransaction.getTransactionDate(), applicationTerms.getInterestChargedFromLocalDate(), applicationTerms, mc,
|
||||
loanCharges);
|
||||
if (precloseTransaction.getAmount(currency).isLessThan(loanRepaymentScheduleInstallment.getTotalOutstanding(currency))) {
|
||||
precloseTransaction = null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public interface LoanScheduleGenerator {
|
||||
List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency,
|
||||
LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MathContext mc);
|
||||
LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MathContext mc, Set<LoanCharge> charges);
|
||||
|
||||
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||
final ApplicationCurrency applicationCurrency, final boolean isHolidayEnabled,
|
||||
|
||||
+3
-2
@@ -385,7 +385,8 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms,final Long officeId) {
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
final Set<LoanCharge> loanCharges) {
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
@@ -404,7 +405,7 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
|
||||
return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, nextScheduleDate,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc);
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc, loanCharges);
|
||||
}
|
||||
|
||||
private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) {
|
||||
|
||||
+9
-1
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -127,6 +128,12 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
if (!loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || loan.isNpa() || !loan.status().isActive()
|
||||
|| !loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) { return; }
|
||||
|
||||
if (loan.loanProduct().isMultiDisburseLoan()) {
|
||||
BigDecimal disbursedAmount = loan.getDisbursedAmount();
|
||||
BigDecimal principalRepaid = loan.getLoanSummary().getTotalPrincipalRepaid();
|
||||
BigDecimal principalWrittenOff = loan.getLoanSummary().getTotalPrincipalWrittenOff();
|
||||
if (disbursedAmount.subtract(principalWrittenOff).subtract(principalRepaid).compareTo(BigDecimal.ZERO) != 1) { return; }
|
||||
}
|
||||
MonetaryCurrency currency = loan.getCurrency();
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
final List<LoanSchedulePeriodData> futureInstallments = new ArrayList<>();
|
||||
@@ -147,7 +154,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.getOfficeId());
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.getOfficeId(),
|
||||
loan.charges());
|
||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
Money interestDue = Money.zero(currency);
|
||||
|
||||
Reference in New Issue
Block a user