Merge pull request #1059 from pramodn02/develop
MIFOSX-1526 : added future instalments calculation
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
||||
CREATE TABLE `m_loan_transaction_temp` (
|
||||
`id` BIGINT(20) NOT NULL,
|
||||
`loan_id` BIGINT(20) NOT NULL,
|
||||
`amount` DECIMAL(19,6) NOT NULL DEFAULT '0',
|
||||
`transaction_date` DATE NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO m_loan_transaction_temp(`id`,`loan_id`,`transaction_date`,`amount`) select lt.id, lt.loan_id,lt.transaction_date,if(lt.transaction_type_enum = 1 , IFNULL(lt.amount,0),IFNULL(-lt.principal_portion_derived,0)) from m_loan_transaction lt where lt.is_reversed=0;
|
||||
|
||||
|
||||
UPDATE m_loan_transaction lt SET lt.outstanding_loan_balance_derived = (select sum(ltt.amount) from m_loan_transaction_temp ltt where ltt.id <= lt.id and ltt.transaction_date <= lt.transaction_date and ltt.loan_id = lt.loan_id) where lt.transaction_type_enum != 10 and lt.is_reversed = 0;
|
||||
|
||||
DROP TABLE `m_loan_transaction_temp`;
|
||||
|
||||
+7
-3
@@ -9,7 +9,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -319,8 +318,8 @@ public class LoansApiResource {
|
||||
if (!associationParameters.isEmpty()) {
|
||||
|
||||
if (associationParameters.contains("all")) {
|
||||
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "charges", "guarantors", "collateral",
|
||||
"notes", "linkedAccount", "multiDisburseDetails"));
|
||||
associationParameters.addAll(Arrays.asList("repaymentSchedule", "futureSchedule", "transactions", "charges", "guarantors",
|
||||
"collateral", "notes", "linkedAccount", "multiDisburseDetails"));
|
||||
}
|
||||
|
||||
if (associationParameters.contains("guarantors")) {
|
||||
@@ -356,6 +355,11 @@ public class LoansApiResource {
|
||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
|
||||
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData,
|
||||
disbursementData);
|
||||
|
||||
if (associationParameters.contains("futureSchedule")) {
|
||||
mandatoryResponseParameters.add("futureSchedule");
|
||||
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
|
||||
}
|
||||
}
|
||||
|
||||
if (associationParameters.contains("charges")) {
|
||||
|
||||
+58
-27
@@ -2095,6 +2095,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
chargesPayment.updateComponentsAndTotal(zero, zero, disbursentMoney, zero);
|
||||
chargesPayment.updateLoan(this);
|
||||
this.loanTransactions.add(chargesPayment);
|
||||
updateLoanOutstandingBalaces();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2139,6 +2140,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
chargesPayment.updateComponents(zero, zero, charge.getAmount(getCurrency()), zero);
|
||||
chargesPayment.updateLoan(this);
|
||||
this.loanTransactions.add(chargesPayment);
|
||||
updateLoanOutstandingBalaces();
|
||||
charge.markAsFullyPaid();
|
||||
return chargesPayment;
|
||||
}
|
||||
@@ -2493,7 +2495,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return repaymentsOrWaivers;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursementExcludeAccruals() {
|
||||
public List<LoanTransaction> retreiveListOfTransactionsPostDisbursementExcludeAccruals() {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (!transaction.isDisbursement() && transaction.isNotReversed() && !transaction.isAccrual()) {
|
||||
@@ -4111,14 +4113,54 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, LocalDate recalculateFrom) {
|
||||
|
||||
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled() || isNpa) { return; }
|
||||
final LoanScheduleModel loanSchedule = getRecalculatedSchedule(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation,
|
||||
recalculateFrom);
|
||||
if (loanSchedule == null) { return; }
|
||||
|
||||
updateLoanSchedule(loanSchedule);
|
||||
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
|
||||
Set<LoanCharge> charges = this.charges();
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
if (!loanCharge.isDueAtDisbursement()) {
|
||||
if (loanCharge.getDueLocalDate() == null || !lastRepaymentDate.isBefore(loanCharge.getDueLocalDate())) {
|
||||
recalculateLoanCharge(loanCharge);
|
||||
loanCharge.updateWaivedAmount(getCurrency());
|
||||
} else {
|
||||
loanCharge.setActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
private LoanScheduleModel getRecalculatedSchedule(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, LocalDate recalculateFrom) {
|
||||
|
||||
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled() || isNpa) { return null; }
|
||||
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
||||
final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod);
|
||||
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, calendarInstanceForInterestRecalculation);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, applicationCurrency,
|
||||
loanApplicationTerms, charges(), isHolidayEnabled, holidays, workingDays,
|
||||
retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
|
||||
this.repaymentScheduleInstallments, recalculateFrom);
|
||||
return loanSchedule;
|
||||
}
|
||||
|
||||
public LoanApplicationTerms constructLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||
final Integer loanTermFrequency = this.termFrequency;
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||
@@ -4149,30 +4191,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
||||
loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails,
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, applicationCurrency,
|
||||
loanApplicationTerms, charges(), isHolidayEnabled, holidays, workingDays,
|
||||
retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
|
||||
this.repaymentScheduleInstallments, recalculateFrom);
|
||||
if (loanSchedule == null) { return; }
|
||||
|
||||
updateLoanSchedule(loanSchedule);
|
||||
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
|
||||
Set<LoanCharge> charges = this.charges();
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
if (!loanCharge.isDueAtDisbursement()) {
|
||||
if (loanCharge.getDueLocalDate() == null || !lastRepaymentDate.isBefore(loanCharge.getDueLocalDate())) {
|
||||
recalculateLoanCharge(loanCharge);
|
||||
loanCharge.updateWaivedAmount(getCurrency());
|
||||
} else {
|
||||
loanCharge.setActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
updateLoanSummaryDerivedFields();
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory) {
|
||||
@@ -4182,6 +4201,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
|
||||
final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod);
|
||||
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
|
||||
final Integer loanTermFrequency = this.termFrequency;
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||
@@ -4209,8 +4231,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null, getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate());
|
||||
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
|
||||
loanApplicationTerms, LocalDate.now());
|
||||
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc);
|
||||
} else {
|
||||
installment = this.getTotalOutstandingOnLoan();
|
||||
}
|
||||
@@ -4258,4 +4281,12 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
public LoanTransactionProcessingStrategy transactionProcessingStrategy() {
|
||||
return this.transactionProcessingStrategy;
|
||||
}
|
||||
|
||||
public boolean isNpa() {
|
||||
return this.isNpa;
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -49,6 +49,8 @@ public class LoanScheduleData {
|
||||
*/
|
||||
private final Collection<LoanSchedulePeriodData> periods;
|
||||
|
||||
private Collection<LoanSchedulePeriodData> futurePeriods;
|
||||
|
||||
public LoanScheduleData(final CurrencyData currency, final Collection<LoanSchedulePeriodData> periods, final Integer loanTermInDays,
|
||||
final BigDecimal totalPrincipalDisbursed, final BigDecimal totalPrincipalExpected, final BigDecimal totalPrincipalPaid,
|
||||
final BigDecimal totalInterestCharged, final BigDecimal totalFeeChargesCharged, final BigDecimal totalPenaltyChargesCharged,
|
||||
@@ -76,4 +78,8 @@ public class LoanScheduleData {
|
||||
public Collection<LoanSchedulePeriodData> getPeriods() {
|
||||
return this.periods;
|
||||
}
|
||||
|
||||
public void updateFuturePeriods(Collection<LoanSchedulePeriodData> futurePeriods) {
|
||||
this.futurePeriods = futurePeriods;
|
||||
}
|
||||
}
|
||||
+4
@@ -414,4 +414,8 @@ public class LoanSchedulePeriodData {
|
||||
public BigDecimal totalOverdue() {
|
||||
return defaultToZeroIfNull(this.totalOverdue);
|
||||
}
|
||||
|
||||
public BigDecimal principalLoanBalanceOutstanding() {
|
||||
return this.principalLoanBalanceOutstanding;
|
||||
}
|
||||
}
|
||||
+76
-20
@@ -241,7 +241,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
Money interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||
if (daysCalcForInstallmentNumber == periodNumber) {
|
||||
interestForThisinstallment = interestForThisinstallment.zero().plus(
|
||||
calculateInterestForDays(daysInPeriodApplicableInFullInstallment, interestForThisinstallment,
|
||||
calculateInterestForDays(daysInPeriodApplicableInFullInstallment, interestForThisinstallment.getAmount(),
|
||||
daysInPeriodApplicableForInterest));
|
||||
}
|
||||
Money principalForThisPeriod = principalDisbursed.zero();
|
||||
@@ -481,13 +481,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
daysInPeriodApplicableForInterest, amount);
|
||||
|
||||
int days = Days.daysBetween(startDate, endDate).getDays();
|
||||
double interest = calculateInterestForDays(daysInPeriodApplicableForInterest, principalInterest.interest(), days);
|
||||
double interest = calculateInterestForDays(daysInPeriodApplicableForInterest, principalInterest.interest().getAmount(), days);
|
||||
|
||||
return BigDecimal.valueOf(interest);
|
||||
}
|
||||
|
||||
private double calculateInterestForDays(int daysInPeriodApplicableForInterest, Money interest, int days) {
|
||||
return ((interest.getAmount().doubleValue()) / daysInPeriodApplicableForInterest) * days;
|
||||
private double calculateInterestForDays(int daysInPeriodApplicableForInterest, BigDecimal interest, int days) {
|
||||
if (interest.doubleValue() == 0) { return 0; }
|
||||
return ((interest.doubleValue()) / daysInPeriodApplicableForInterest) * days;
|
||||
}
|
||||
|
||||
public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
|
||||
@@ -671,7 +672,7 @@ 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);
|
||||
LoanTransaction preCloseTransaction = getPreclosureTransaction(transactions, installments, currency, loanApplicationTerms, mc);
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (installment.isRecalculatedInterestComponent() && recalculateFrom != null
|
||||
&& !recalculateFrom.isAfter(installment.getDueDate())) {
|
||||
@@ -846,7 +847,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (recalculatedSchedule.getLoanScheduleModel() != null) {
|
||||
loanScheduleModel = recalculatedSchedule.getLoanScheduleModel();
|
||||
installments = retrieveRepaymentSchedule(loanScheduleModel);
|
||||
lastInstallmentNumber = installments.size() - 1;
|
||||
lastInstallmentNumber = installments.size();
|
||||
}
|
||||
}
|
||||
return loanScheduleModel;
|
||||
@@ -963,7 +964,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
}
|
||||
|
||||
if (!diffAmt.isEmpty() && skipRecalculation <= installment.getInstallmentNumber()) {
|
||||
if ((!diffAmt.isEmpty() && skipRecalculation < installment.getInstallmentNumber())
|
||||
|| skipRecalculation == installment.getInstallmentNumber()) {
|
||||
processRecalculate = true;
|
||||
}
|
||||
break;
|
||||
@@ -1039,15 +1041,19 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
*/
|
||||
@Override
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, final LoanApplicationTerms applicationTerms, final LocalDate onDate) {
|
||||
Money outstandingPrincipal = Money.zero(currency);
|
||||
MonetaryCurrency currency, final LocalDate onDate, LocalDate interestChargedFromLocalDate,
|
||||
LoanApplicationTerms loanApplicationTerms, MathContext mc) {
|
||||
Money feeCharges = Money.zero(currency);
|
||||
Money penaltyCharges = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
Money totalInterest = Money.zero(currency);
|
||||
LocalDate calculateInterestFrom = onDate;
|
||||
LocalDate dueDate = onDate;
|
||||
Money inerestForCurrentInstallment = null;
|
||||
LocalDate repaymentDueDate = null;
|
||||
boolean isInterestRepayment = false;
|
||||
Money inerestForCurrentInstallment = Money.zero(currency);
|
||||
Money principalOutstanding = Money.zero(currency);
|
||||
Integer periodNumber = 0;
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (!currentInstallment.getDueDate().isAfter(onDate)) {
|
||||
@@ -1056,7 +1062,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
feeCharges = feeCharges.plus(currentInstallment.getFeeChargesOutstanding(currency));
|
||||
penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
|
||||
} else {
|
||||
outstandingPrincipal = outstandingPrincipal.plus(currentInstallment.getPrincipal(currency));
|
||||
principalOutstanding = principalOutstanding.plus(currentInstallment.getPrincipal(currency));
|
||||
totalPrincipal = totalPrincipal.minus(currentInstallment.getPrincipalCompleted(currency));
|
||||
totalInterest = totalInterest.minus(currentInstallment.getInterestPaid(currency)).minus(
|
||||
currentInstallment.getInterestWaived(currency));
|
||||
@@ -1064,25 +1070,74 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
calculateInterestFrom = currentInstallment.getFromDate();
|
||||
dueDate = currentInstallment.getDueDate();
|
||||
inerestForCurrentInstallment = currentInstallment.getInterestCharged(currency);
|
||||
if (currentInstallment.isRecalculatedInterestComponent()) {
|
||||
isInterestRepayment = true;
|
||||
} else {
|
||||
isInterestRepayment = false;
|
||||
}
|
||||
repaymentDueDate = null;
|
||||
periodNumber = currentInstallment.getInstallmentNumber();
|
||||
}
|
||||
if (isInterestRepayment && repaymentDueDate == null && !currentInstallment.isRecalculatedInterestComponent()) {
|
||||
repaymentDueDate = currentInstallment.getDueDate();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (applicationTerms.getInterestChargedFromLocalDate() != null
|
||||
&& calculateInterestFrom.isBefore(applicationTerms.getInterestChargedFromLocalDate())) {
|
||||
calculateInterestFrom = applicationTerms.getInterestChargedFromLocalDate();
|
||||
if (interestChargedFromLocalDate != null && calculateInterestFrom.isBefore(interestChargedFromLocalDate)) {
|
||||
calculateInterestFrom = interestChargedFromLocalDate;
|
||||
}
|
||||
Money interest = Money.zero(currency);
|
||||
;
|
||||
|
||||
if (calculateInterestFrom.isBefore(onDate)) {
|
||||
int daysInPeriodApplicableForInterest = Days.daysBetween(calculateInterestFrom, dueDate).getDays();
|
||||
boolean useDailyInterest = false;
|
||||
if (repaymentDueDate == null) {
|
||||
if (isInterestRepayment) {
|
||||
useDailyInterest = true;
|
||||
}
|
||||
repaymentDueDate = dueDate;
|
||||
}
|
||||
int daysInPeriodApplicableForInterest = Days.daysBetween(calculateInterestFrom, repaymentDueDate).getDays();
|
||||
int days = Days.daysBetween(calculateInterestFrom, onDate).getDays();
|
||||
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, inerestForCurrentInstallment, days));
|
||||
BigDecimal interestForInstallment = BigDecimal.ZERO;
|
||||
if (useDailyInterest) {
|
||||
interestForInstallment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
||||
principalOutstanding, calculateInterestFrom, repaymentDueDate);
|
||||
|
||||
} 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) {
|
||||
periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate();
|
||||
} else {
|
||||
periodStartDateApplicableForInterest = idealDisbursementDate;
|
||||
}
|
||||
daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDateApplicableForInterest, repaymentDueDate).getDays();
|
||||
}
|
||||
Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
|
||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest, repaymentDueDate,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(),
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
||||
|
||||
PrincipalInterest principalInterest = loanApplicationTerms.calculateTotalInterestForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc,
|
||||
totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, principalOutstanding);
|
||||
interestForInstallment = principalInterest.interest().getAmount();
|
||||
}
|
||||
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment));
|
||||
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, interestForInstallment, days));
|
||||
|
||||
}
|
||||
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
totalPrincipal = totalPrincipal.plus(outstandingPrincipal);
|
||||
totalPrincipal = totalPrincipal.plus(principalOutstanding);
|
||||
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
|
||||
feeCharges.getAmount(), penaltyCharges.getAmount(), false);
|
||||
@@ -1131,7 +1186,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
private LoanTransaction getPreclosureTransaction(List<LoanTransaction> loanTransactions,
|
||||
List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency, final LoanApplicationTerms applicationTerms) {
|
||||
List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency, final LoanApplicationTerms applicationTerms,
|
||||
MathContext mc) {
|
||||
LoanTransaction precloseTransaction = null;
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
if (precloseTransaction == null || precloseTransaction.getTransactionDate().isBefore(loanTransaction.getTransactionDate())) {
|
||||
@@ -1140,7 +1196,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
if (precloseTransaction != null) {
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = calculatePrepaymentAmount(installments, currency,
|
||||
applicationTerms, precloseTransaction.getTransactionDate());
|
||||
precloseTransaction.getTransactionDate(), applicationTerms.getInterestChargedFromLocalDate(), applicationTerms, mc);
|
||||
if (precloseTransaction.getAmount(currency).isLessThan(loanRepaymentScheduleInstallment.getTotalOutstanding(currency))) {
|
||||
precloseTransaction = null;
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,5 +31,5 @@ public interface LoanScheduleGenerator {
|
||||
List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency,
|
||||
LoanApplicationTerms applicationTerms, LocalDate onDate);
|
||||
LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MathContext mc);
|
||||
}
|
||||
+49
@@ -29,6 +29,7 @@ import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchException;
|
||||
@@ -44,13 +45,18 @@ import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeAssembler;
|
||||
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
@@ -358,6 +364,49 @@ public class LoanScheduleAssembler {
|
||||
workingDays);
|
||||
}
|
||||
|
||||
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
|
||||
final List<LoanRepaymentScheduleInstallment> previousSchedule,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, LocalDate recalculateFrom) {
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository
|
||||
.findOneWithNotFoundDetection(loanApplicationTerms.getCurrency());
|
||||
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, loanApplicationTerms
|
||||
.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
return loanScheduleGenerator.rescheduleNextInstallments(mc, applicationCurrency, loanApplicationTerms, loanCharges,
|
||||
isHolidayEnabled, holidays, workingDays, transactions, loanRepaymentScheduleTransactionProcessor, previousSchedule,
|
||||
recalculateFrom);
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms,final Long officeId) {
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, loanApplicationTerms
|
||||
.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||
|
||||
CalendarInstance calendarInstance = loanApplicationTerms.getRestCalendarInstance();
|
||||
LocalDate nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), onDate);
|
||||
if (loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) {
|
||||
nextScheduleDate = scheduledDateGenerator.adjustRepaymentDate(nextScheduleDate, loanApplicationTerms, isHolidayEnabled,
|
||||
holidays, workingDays);
|
||||
}
|
||||
|
||||
return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, nextScheduleDate,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc);
|
||||
}
|
||||
|
||||
private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) {
|
||||
if (!WorkingDaysUtil.isWorkingDay(workingDays, disbursementDate)) {
|
||||
final String errorMessage = "The expected disbursement date cannot be on a non working day";
|
||||
|
||||
+3
@@ -6,9 +6,12 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
|
||||
public interface LoanScheduleCalculationPlatformService {
|
||||
|
||||
LoanScheduleModel calculateLoanSchedule(JsonQuery query, Boolean validateParams);
|
||||
|
||||
void updateFutureSchedule(LoanScheduleData loanScheduleData, Long loanId);
|
||||
}
|
||||
|
||||
+106
-1
@@ -6,17 +6,36 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonQuery;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
@@ -35,12 +54,20 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
private final LoanProductDataValidator loanProductCommandFromApiJsonDeserializer;
|
||||
private final LoanReadPlatformService loanReadPlatformService;
|
||||
private final LoanApplicationCommandFromApiJsonHelper loanApiJsonDeserializer;
|
||||
private final LoanAssembler loanAssembler;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||
private final LoanAccountDomainService accountDomainService;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanScheduleCalculationPlatformServiceImpl(final CalculateLoanScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final FromJsonHelper fromJsonHelper,
|
||||
final LoanProductRepository loanProductRepository, final LoanProductDataValidator loanProductCommandFromApiJsonDeserializer,
|
||||
final LoanReadPlatformService loanReadPlatformService, final LoanApplicationCommandFromApiJsonHelper loanApiJsonDeserializer) {
|
||||
final LoanReadPlatformService loanReadPlatformService, final LoanApplicationCommandFromApiJsonHelper loanApiJsonDeserializer,
|
||||
final LoanAssembler loanAssembler, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
||||
final LoanAccountDomainService accountDomainService, final CalendarInstanceRepository calendarInstanceRepository,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
@@ -48,6 +75,11 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
|
||||
this.loanReadPlatformService = loanReadPlatformService;
|
||||
this.loanApiJsonDeserializer = loanApiJsonDeserializer;
|
||||
this.loanAssembler = loanAssembler;
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
this.accountDomainService = accountDomainService;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,4 +115,77 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
|
||||
return this.loanScheduleAssembler.assembleLoanScheduleFrom(query.parsedJson());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFutureSchedule(LoanScheduleData loanScheduleData, final Long loanId) {
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
|
||||
if (!loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || loan.isNpa() || !loan.status().isActive()
|
||||
|| !loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) { return; }
|
||||
|
||||
MonetaryCurrency currency = loan.getCurrency();
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
final List<LoanSchedulePeriodData> futureInstallments = new ArrayList<>();
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : loan.fetchRepaymentScheduleInstallments()) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (!currentInstallment.getDueDate().isAfter(LocalDate.now())) {
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
}
|
||||
}
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||
CalendarEntityType.LOANS.getValue());
|
||||
final CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
LocalDate calculatedRepaymentsStartingFromDate = accountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||
loan.getDisbursementDate(), loan, calendarInstance);
|
||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.getOfficeId());
|
||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
Money interestDue = Money.zero(currency);
|
||||
if (loanRepaymentScheduleInstallment.isInterestDue(currency)) {
|
||||
interestDue = loanRepaymentScheduleInstallment.getInterestOutstanding(currency);
|
||||
totalAmount = totalAmount.plus(interestDue);
|
||||
}
|
||||
boolean isNewPaymentRequired = loanRepaymentScheduleInstallment.isInterestDue(currency) || totalPrincipal.isGreaterThanZero();
|
||||
final List<LoanTransaction> modifiedTransactions = new ArrayList<>();
|
||||
List<LoanTransaction> transactions = loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals();
|
||||
for (LoanTransaction loanTransaction : transactions) {
|
||||
modifiedTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
||||
}
|
||||
if (isNewPaymentRequired) {
|
||||
LoanTransaction ondayPaymentTransaction = LoanTransaction.repayment(null, totalAmount, null, LocalDate.now(), null);
|
||||
modifiedTransactions.add(ondayPaymentTransaction);
|
||||
}
|
||||
|
||||
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
|
||||
modifiedTransactions, loan.charges(), loan.fetchRepaymentScheduleInstallments(), loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate.now());
|
||||
LoanScheduleData scheduleDate = model.toData();
|
||||
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
|
||||
for (LoanSchedulePeriodData periodData : periodDatas) {
|
||||
if ((periodData.periodDueDate().isEqual(LocalDate.now()) || periodData.periodDueDate().isAfter(LocalDate.now()))
|
||||
&& isNewPaymentRequired) {
|
||||
LoanSchedulePeriodData loanSchedulePeriodData = LoanSchedulePeriodData.repaymentOnlyPeriod(periodData.periodNumber(),
|
||||
periodData.periodFromDate(), periodData.periodDueDate(), totalPrincipal.getAmount(), periodData
|
||||
.principalLoanBalanceOutstanding(), interestDue.getAmount(), loanRepaymentScheduleInstallment
|
||||
.getFeeChargesCharged(currency).getAmount(),
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount(), totalAmount.getAmount());
|
||||
futureInstallments.add(loanSchedulePeriodData);
|
||||
isNewPaymentRequired = false;
|
||||
} else if (periodData.periodDueDate().isAfter(LocalDate.now())) {
|
||||
futureInstallments.add(periodData);
|
||||
}
|
||||
|
||||
}
|
||||
loanScheduleData.updateFuturePeriods(futureInstallments);
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -614,8 +614,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.loanRepository.save(existingLoanApplication);
|
||||
|
||||
if (productRelatedDetail.isInterestRecalculationEnabled()) {
|
||||
LocalDate recalculationFrequencyDate = existingLoanApplication.loanProduct().getProductInterestRecalculationDetails()
|
||||
LocalDate recalculationFrequencyDate = existingLoanApplication.loanInterestRecalculationDetails()
|
||||
.getRestFrequencyLocalDate();
|
||||
if (recalculationFrequencyDate == null) {
|
||||
recalculationFrequencyDate = existingLoanApplication.loanProduct().getProductInterestRecalculationDetails()
|
||||
.getRestFrequencyLocalDate();
|
||||
}
|
||||
if (this.fromJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson())) {
|
||||
recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson());
|
||||
|
||||
+2
-1
@@ -358,7 +358,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
private void updateRecurringCalendarDatesForInterestRecalculation(final Loan loan) {
|
||||
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||
&& loan.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment() && !loan.isDisbursed()) {
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation = this.calendarInstanceRepository
|
||||
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
|
||||
Reference in New Issue
Block a user