http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index c1f91ea..0746522 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -21,7 +21,9 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain; import java.math.BigDecimal; import java.math.MathContext; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; @@ -192,6 +194,25 @@ public final class LoanApplicationTerms { private final boolean isSkipRepaymentOnFirstDayOfMonth; private final HolidayDetailDTO holidayDetailDTO; + + private final Set<Integer> periodNumbersApplicableForPrincipalGrace = new HashSet<>(); + + private final Set<Integer> periodNumbersApplicableForInterestGrace = new HashSet<>(); + + + // used for FLAT loans when interest rate changed + private Integer excludePeriodsForCalculation = 0; + private Money totalPrincipalAccountedForInterestCalcualtion; + + + //used for FLAT loans generation on modifying terms + private Money totalPrincipalAccounted; + private Money totalInterestAccounted; + private int periodsCompleted = 0; + private int extraPeriods = 0; + + + public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency, final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, @@ -482,6 +503,12 @@ public final class LoanApplicationTerms { this.isInterestChargedFromDateSameAsDisbursalDateEnabled = isInterestChargedFromDateSameAsDisbursalDateEnabled; this.holidayDetailDTO = holidayDetailDTO; this.allowCompoundingOnEod = allowCompoundingOnEod; + Integer periodNumber = 1; + updatePeriodNumberApplicableForPrincipalOrInterestGrace(periodNumber); + updateRecurringMoratoriumOnPrincipalPeriods(periodNumber); + this.totalPrincipalAccountedForInterestCalcualtion = principal.zero(); + this.totalInterestAccounted = principal.zero(); + this.totalPrincipalAccounted = principal.zero(); } public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate, @@ -706,7 +733,8 @@ public final class LoanApplicationTerms { switch (this.interestMethod) { case FLAT: final BigDecimal interestRateForLoanTerm = calculateFlatInterestRateForLoanTerm(calculator, mc); - totalInterestDue = this.principal.multiplyRetainScale(interestRateForLoanTerm, mc.getRoundingMode()); + totalInterestDue = this.principal.minus(totalPrincipalAccountedForInterestCalcualtion).multiplyRetainScale(interestRateForLoanTerm, + mc.getRoundingMode()); break; case DECLINING_BALANCE: @@ -715,10 +743,6 @@ public final class LoanApplicationTerms { break; } - if (this.totalInterestDue != null) { - totalInterestDue = this.totalInterestDue; - } - return totalInterestDue; } @@ -844,13 +868,19 @@ public final class LoanApplicationTerms { private Money calculateTotalInterestPerInstallmentWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc); - - return totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments), mc.getRoundingMode()); + Money interestPerInstallment = totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments) - defaultToZeroIfNull(this.excludePeriodsForCalculation), mc.getRoundingMode()); + if (this.excludePeriodsForCalculation < this.periodsCompleted) { + Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted); + interestPerInstallment = interestLeft.dividedBy(Long.valueOf(this.actualNumberOfRepayments) + - defaultToZeroIfNull(this.periodsCompleted), mc.getRoundingMode()); + } + + return interestPerInstallment; } private Money calculateTotalPrincipalPerPeriodWithoutGrace(final MathContext mc, final int periodNumber) { final int totalRepaymentsWithCapitalPayment = calculateNumberOfRepaymentsWithPrincipalPayment(); - Money principalPerPeriod = this.principal.dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus( + Money principalPerPeriod = this.principal.minus(totalPrincipalAccounted).dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus( this.adjustPrincipalForFlatLoans); if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) { principalPerPeriod = principalPerPeriod.zero(); @@ -906,11 +936,30 @@ public final class LoanApplicationTerms { final Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace()); final Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree); - - final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.actualNumberOfRepayments); - + + + + Integer interestPaymentDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments, + this.excludePeriodsForCalculation); interestForInstallment = realTotalInterestForLoan .dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode()); + if (this.excludePeriodsForCalculation < this.periodsCompleted) { + Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted); + Integer interestDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments, + this.periodsCompleted); + interestForInstallment = interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode()); + } + if(!this.periodNumbersApplicableForInterestGrace.isEmpty()){ + int periodsElapsed = calculateLastInterestGracePeriod(periodNumber); + if (periodsElapsed > this.excludePeriodsForCalculation && periodsElapsed > this.periodsCompleted) { + Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted); + Integer interestDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments, + periodsElapsed); + interestForInstallment = interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode()); + } + } + + } return interestForInstallment; @@ -1032,24 +1081,46 @@ public final class LoanApplicationTerms { private int calculateNumberOfRepaymentsWithPrincipalPayment() { int numPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments, - this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), 0); + this.periodsCompleted); +// numPeriods = numPeriods - this.periodsCompleted; return numPeriods; } - - private Integer calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(final Integer totalNumberOfRepaymentPeriods) { - return totalNumberOfRepaymentPeriods - Math.max(getInterestChargingGrace(), getInterestPaymentGrace()); + + private Integer calculateNumberOfRemainingInterestPaymentPeriods(final Integer totalNumberOfRepaymentPeriods, int periodsElapsed) { + int principalFeePeriods = 0; + for (Integer intNumber : this.periodNumbersApplicableForInterestGrace) { + if (intNumber > periodsElapsed) { + principalFeePeriods++; + } + } + Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed - principalFeePeriods; + return periodsRemaining; + } + + private Integer calculateLastInterestGracePeriod(int periodNumber){ + int lastGracePeriod = 0; + for (Integer grace : this.periodNumbersApplicableForInterestGrace) { + if(grace < periodNumber && lastGracePeriod < grace){ + lastGracePeriod = grace; + } + } + return lastGracePeriod; } public boolean isPrincipalGraceApplicableForThisPeriod(final int periodNumber) { - if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) { - return ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this - .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1))); + boolean isPrincipalGraceApplicableForThisPeriod = false; + if (this.periodNumbersApplicableForPrincipalGrace.contains(periodNumber)) { + isPrincipalGraceApplicableForThisPeriod = true; } - return periodNumber > 0 && periodNumber <= getPrincipalGrace(); + return isPrincipalGraceApplicableForThisPeriod; } - private boolean isInterestPaymentGraceApplicableForThisPeriod(final int periodNumber) { - return periodNumber > 0 && periodNumber <= getInterestPaymentGrace(); + public boolean isInterestPaymentGraceApplicableForThisPeriod(final int periodNumber) { + boolean isInterestPaymentGraceApplicableForThisPeriod = false; + if (this.periodNumbersApplicableForInterestGrace.contains(periodNumber)) { + isInterestPaymentGraceApplicableForThisPeriod = true; + } + return isInterestPaymentGraceApplicableForThisPeriod; } private boolean isFirstPeriodAfterInterestPaymentGracePeriod(final int periodNumber) { @@ -1099,7 +1170,7 @@ public final class LoanApplicationTerms { final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue(); final Integer periodsRemaining = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments, - this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodsElapsed); + periodsElapsed); double installmentAmount = FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(), principalDouble, futureValue, false); @@ -1165,7 +1236,7 @@ public final class LoanApplicationTerms { Money principal = this.principal; if (this.fixedPrincipalAmount == null) { final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods( - this.actualNumberOfRepayments, this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodNumber); + this.actualNumberOfRepayments, periodNumber); principal = this.principal.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode()); this.fixedPrincipalAmount = principal.getAmount(); } @@ -1179,21 +1250,19 @@ public final class LoanApplicationTerms { public void updateFixedPrincipalAmount(final MathContext mc, final int periodNumber, final Money outstandingAmount) { final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments, - this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodNumber - 1); + periodNumber - 1); Money principal = outstandingAmount.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode()); this.fixedPrincipalAmount = principal.getAmount(); } - private static Integer calculateNumberOfRemainingPrincipalPaymentPeriods(final Integer totalNumberOfRepaymentPeriods, - final int recurringMoratoriumOnPrincipalPeriods, final int PrincipalGrace, int periodsElapsed) { - if (PrincipalGrace > periodsElapsed) { - periodsElapsed = PrincipalGrace; - } - Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed; - if (recurringMoratoriumOnPrincipalPeriods > 0) { - double periodsRemainingDouble = ((double) periodsRemaining / ((double) (recurringMoratoriumOnPrincipalPeriods + 1))); - periodsRemaining = (int) Math.ceil(periodsRemainingDouble); + private Integer calculateNumberOfRemainingPrincipalPaymentPeriods(final Integer totalNumberOfRepaymentPeriods, int periodsElapsed) { + int principalFeePeriods = 0; + for (Integer intNumber : this.periodNumbersApplicableForPrincipalGrace) { + if (intNumber > periodsElapsed) { + principalFeePeriods++; + } } + Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed - principalFeePeriods; return periodsRemaining; } @@ -1469,10 +1538,7 @@ public final class LoanApplicationTerms { } public void updateTotalInterestDue(Money totalInterestDue) { - - if (totalInterestDue != null) { - this.totalInterestDue = totalInterestDue; - } + this.totalInterestDue = totalInterestDue; } public ApplicationCurrency getApplicationCurrency() { @@ -1576,4 +1642,81 @@ public final class LoanApplicationTerms { } return disbursedAmount; } + + public void updatePeriodNumberApplicableForPrincipalOrInterestGrace(final Integer periodsApplicationForGrace) { + int applicablePeriodNumber = periodsApplicationForGrace; + int graceOnPrincipal = defaultToZeroIfNull(this.principalGrace); + int graceOnInterest = defaultToZeroIfNull(this.interestPaymentGrace); + + while (graceOnPrincipal > 0 || graceOnInterest > 0) { + if (graceOnPrincipal > 0) { + this.periodNumbersApplicableForPrincipalGrace.add(applicablePeriodNumber); + } + if (graceOnInterest > 0) { + this.periodNumbersApplicableForInterestGrace.add(applicablePeriodNumber); + } + applicablePeriodNumber++; + graceOnPrincipal--; + graceOnInterest--; + } + } + + /** + * set the value to zero if the provided value is null + * + * @return integer value equal/greater than 0 + **/ + private Integer defaultToZeroIfNull(Integer value) { + + return (value != null) ? value : 0; + } + + public void updateExcludePeriodsForCalculation(Integer excludePeriodsForCalculation){ + this.excludePeriodsForCalculation = excludePeriodsForCalculation; + this.extraPeriods = 0; + } + + public Integer getActualNoOfRepaymnets() { + return this.actualNumberOfRepayments; + } + + public Money getTotalInterestDue() { + return this.totalInterestDue; + } + + private void updateRecurringMoratoriumOnPrincipalPeriods(Integer periodNumber) { + Boolean isPrincipalGraceApplicableForThisPeriod = false; + Integer numberOfRepayments = this.actualNumberOfRepayments; + if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) { + while (numberOfRepayments > 0) { + isPrincipalGraceApplicableForThisPeriod = ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this + .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1))); + if (isPrincipalGraceApplicableForThisPeriod) { + this.periodNumbersApplicableForPrincipalGrace.add(periodNumber); + } + numberOfRepayments--; + periodNumber++; + } + } + + } + + + public void setTotalPrincipalAccounted(Money totalPrincipalAccounted) { + this.totalPrincipalAccountedForInterestCalcualtion = totalPrincipalAccounted; + } + + + //Used for FLAT loans to calculate principal and interest per installment + public void updateAccountedTillPeriod(int periodNumber, Money totalPrincipalAccounted,Money totalInterestAccounted, int extendPeriods){ + this.periodsCompleted = periodNumber; + this.totalPrincipalAccounted = totalPrincipalAccounted; + this.totalInterestAccounted = totalInterestAccounted; + this.extraPeriods = this.extraPeriods + extendPeriods; + } + + public void updateTotalInterestAccounted(Money totalInterestAccounted){ + this.totalInterestAccounted = totalInterestAccounted; + } + } \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java index ae67451..9583ac4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java @@ -19,22 +19,15 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain; import java.math.MathContext; -import java.util.List; import java.util.Set; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; -import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO; import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest; import org.joda.time.LocalDate; public interface LoanScheduleGenerator { @@ -42,18 +35,12 @@ public interface LoanScheduleGenerator { LoanScheduleModel generate(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO); - LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges, - final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions, - LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, - List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, LocalDate rescheduleFrom); + LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Loan loan, + final HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, + LocalDate rescheduleFrom); LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate, - LoanApplicationTerms loanApplicationTerms, MathContext mc, Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO, - List<LoanTransaction> loanTransactions, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, - List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments); + LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO, + LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor); - LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest, - final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, - CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, FloatingRateDTO floatingRateDTO, - final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index ac4a368..9565ff3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -86,7 +86,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException; import org.apache.fineract.portfolio.loanaccount.exception.MinDaysBetweenDisbursalAndFirstRepaymentViolationException; @@ -621,9 +620,8 @@ public class LoanScheduleAssembler { } public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId, - List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges, - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, - final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom) { + Loan loan, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, + final LocalDate rescheduleFrom) { final RoundingMode roundingMode = MoneyHelper.getRoundingMode(); final MathContext mc = new MathContext(8, roundingMode); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); @@ -634,15 +632,13 @@ public class LoanScheduleAssembler { final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); - return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, detailDTO, transactions, - loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments, rescheduleFrom).getLoanScheduleModel(); + return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loan, detailDTO, + loanRepaymentScheduleTransactionProcessor, rescheduleFrom).getLoanScheduleModel(); } public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate, - LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final Long officeId, - List<LoanTransaction> loanTransactions, - final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, - final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments) { + LoanApplicationTerms loanApplicationTerms, Loan loan, final Long officeId, + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) { final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); final RoundingMode roundingMode = MoneyHelper.getRoundingMode(); final MathContext mc = new MathContext(8, roundingMode); @@ -653,8 +649,8 @@ public class LoanScheduleAssembler { final WorkingDays workingDays = this.workingDaysRepository.findOne(); HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); - return loanScheduleGenerator.calculatePrepaymentAmount(currency, onDate, loanApplicationTerms, mc, loanCharges, holidayDetailDTO, - loanTransactions, loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments); + return loanScheduleGenerator.calculatePrepaymentAmount(currency, onDate, loanApplicationTerms, mc, loan, holidayDetailDTO, + loanRepaymentScheduleTransactionProcessor); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java index 41e8313..a8ea977 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java @@ -171,9 +171,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC } LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(loan); LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(currency, - today, loanApplicationTerms, loan.charges(), loan.getOfficeId(), - loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor, - loan.getRepaymentScheduleInstallments()); + today, loanApplicationTerms, loan, loan.getOfficeId(), + loanRepaymentScheduleTransactionProcessor); Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus( loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency)); Money interestDue = Money.zero(currency); @@ -194,8 +193,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC } LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(), - modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, loan.getRepaymentScheduleInstallments(), - loan.fetchInterestRecalculateFromDate()); + loan, loanRepaymentScheduleTransactionProcessor, loan.fetchInterestRecalculateFromDate()); LoanScheduleData scheduleDate = model.toData(); Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods(); for (LoanSchedulePeriodData periodData : periodDatas) { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java index 2094a05..591e21b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java @@ -42,9 +42,9 @@ import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSeria import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestData; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanReschedulePreviewPlatformService; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; @@ -108,14 +108,14 @@ public class RescheduleLoansApiResource { final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (compareIgnoreCase(command, "previewLoanReschedule")) { - final LoanRescheduleModel loanRescheduleModel = this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId); + final LoanScheduleModel loanRescheduleModel = this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId); return this.loanRescheduleToApiJsonSerializer.serialize(settings, loanRescheduleModel.toData(), new HashSet<String>()); } final LoanRescheduleRequestData loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService .readLoanRescheduleRequest(scheduleId); - + return this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, loanRescheduleRequestData); } @@ -170,4 +170,20 @@ public class RescheduleLoansApiResource { private boolean compareIgnoreCase(String firstString, String secondString) { return StringUtils.isNotBlank(firstString) && firstString.trim().equalsIgnoreCase(secondString); } + + /*@GET + @Path("{scheduleId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveTemplate(@Context final UriInfo uriInfo) { + + this.platformSecurityContext.authenticatedUser().validateHasReadPermission(RescheduleLoansApiConstants.ENTITY_NAME); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + + LoanRescheduleRequestData loanRescheduleReasons = null; + loanRescheduleReasons = this.loanRescheduleRequestReadPlatformService + .retrieveAllRescheduleReasons(RescheduleLoansApiConstants.LOAN_RESCHEDULE_REASON); + + return this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, loanRescheduleReasons); + }*/ } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java index b74388c..2a6dfbd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java @@ -18,10 +18,10 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.data; -import java.math.BigDecimal; import java.util.Collection; import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.joda.time.LocalDate; /** @@ -36,59 +36,55 @@ public class LoanRescheduleRequestData { private final String loanAccountNumber; private final LoanRescheduleRequestStatusEnumData statusEnum; private final Integer rescheduleFromInstallment; - private final Integer graceOnPrincipal; - private final Integer graceOnInterest; private final LocalDate rescheduleFromDate; - private final Integer extraTerms; - private final BigDecimal interestRate; private final Boolean recalculateInterest; private final CodeValueData rescheduleReasonCodeValue; private final LoanRescheduleRequestTimelineData timeline; private final String rescheduleReasonComment; - private final LocalDate adjustedDueDate; + @SuppressWarnings("unused") private final Collection<CodeValueData> rescheduleReasons; + @SuppressWarnings("unused") + private final Collection<LoanTermVariationsData> loanTermVariationsData; /** * LoanRescheduleRequestData constructor + * @param loanTermVariationsData TODO **/ private LoanRescheduleRequestData(Long id, Long loanId, LoanRescheduleRequestStatusEnumData statusEnum, - Integer rescheduleFromInstallment, Integer graceOnPrincipal, Integer graceOnInterest, LocalDate rescheduleFromDate, - LocalDate adjustedDueDate, Integer extraTerms, BigDecimal interestRate, CodeValueData rescheduleReasonCodeValue, + Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, CodeValueData rescheduleReasonCodeValue, String rescheduleReasonComment, LoanRescheduleRequestTimelineData timeline, final String clientName, - final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, Collection<CodeValueData> rescheduleReasons) { + final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, + Collection<CodeValueData> rescheduleReasons, final Collection<LoanTermVariationsData> loanTermVariationsData) { this.id = id; this.loanId = loanId; this.statusEnum = statusEnum; this.rescheduleFromInstallment = rescheduleFromInstallment; - this.graceOnPrincipal = graceOnPrincipal; - this.graceOnInterest = graceOnInterest; this.rescheduleFromDate = rescheduleFromDate; - this.extraTerms = extraTerms; - this.interestRate = interestRate; this.rescheduleReasonCodeValue = rescheduleReasonCodeValue; this.rescheduleReasonComment = rescheduleReasonComment; - this.adjustedDueDate = adjustedDueDate; this.timeline = timeline; this.clientName = clientName; this.loanAccountNumber = loanAccountNumber; this.clientId = clientId; this.recalculateInterest = recalculateInterest; this.rescheduleReasons = rescheduleReasons ; + this.loanTermVariationsData = loanTermVariationsData; } /** + * @param loanTermVariationsData TODO * @return an instance of the LoanRescheduleRequestData class **/ public static LoanRescheduleRequestData instance(Long id, Long loanId, LoanRescheduleRequestStatusEnumData statusEnum, - Integer rescheduleFromInstallment, Integer graceOnPrincipal, Integer graceOnInterest, LocalDate rescheduleFromDate, - LocalDate adjustedDueDate, Integer extraTerms, BigDecimal interestRate, CodeValueData rescheduleReasonCodeValue, + Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, CodeValueData rescheduleReasonCodeValue, String rescheduleReasonComment, LoanRescheduleRequestTimelineData timeline, final String clientName, - final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, Collection<CodeValueData> rescheduleReasons) { + final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, + Collection<CodeValueData> rescheduleReasons, final Collection<LoanTermVariationsData> loanTermVariationsData) { - return new LoanRescheduleRequestData(id, loanId, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest, - rescheduleFromDate, adjustedDueDate, extraTerms, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment, - timeline, clientName, loanAccountNumber, clientId, recalculateInterest, rescheduleReasons); + return new LoanRescheduleRequestData(id, loanId, statusEnum, rescheduleFromInstallment, rescheduleFromDate, + rescheduleReasonCodeValue, rescheduleReasonComment, timeline, clientName, loanAccountNumber, clientId, recalculateInterest, + rescheduleReasons, loanTermVariationsData); } /** @@ -120,20 +116,6 @@ public class LoanRescheduleRequestData { } /** - * @return the graceOnPrincipal - */ - public Integer getGraceOnPrincipal() { - return graceOnPrincipal; - } - - /** - * @return the graceOnInterest - */ - public Integer getGraceOnInterest() { - return graceOnInterest; - } - - /** * @return the reschedule from date */ public LocalDate getRescheduleFromDate() { @@ -141,20 +123,6 @@ public class LoanRescheduleRequestData { } /** - * @return the extraTerms - */ - public Integer getExtraTerms() { - return extraTerms; - } - - /** - * @return the interestRate - */ - public BigDecimal getInterestRate() { - return interestRate; - } - - /** * @return the rescheduleReasonCodeValueId */ public CodeValueData getRescheduleReasonCodeValueId() { @@ -176,13 +144,6 @@ public class LoanRescheduleRequestData { } /** - * @return the adjustedDueDate - */ - public LocalDate getAdjustedDueDate() { - return adjustedDueDate; - } - - /** * @return the clientName */ public String getClientName() { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java index 5254187..67e0f80 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java @@ -32,10 +32,8 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService; import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -47,13 +45,10 @@ import com.google.gson.reflect.TypeToken; public class LoanRescheduleRequestDataValidator { private final FromJsonHelper fromJsonHelper; - private final LoanRescheduleRequestReadPlatformService loanRescheduleRequestReadPlatformService; @Autowired - public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper, - LoanRescheduleRequestReadPlatformService loanRescheduleRequestReadPlatformService) { + public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper) { this.fromJsonHelper = fromJsonHelper; - this.loanRescheduleRequestReadPlatformService = loanRescheduleRequestReadPlatformService; } /** @@ -159,21 +154,8 @@ public class LoanRescheduleRequestDataValidator { .failWithCode("repayment.schedule.installment.obligation.met", "Repayment schedule installment obligation met"); } - if (installment != null && installment.isPartlyPaid()) { - dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName) - .failWithCode("repayment.schedule.installment.partly.paid", "Repayment schedule installment is partly paid"); - } } - if (loanId != null) { - List<LoanRescheduleRequestData> loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService - .readLoanRescheduleRequests(loanId, LoanStatus.APPROVED.getValue()); - - if (loanRescheduleRequestData.size() > 0) { - dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled", - "The loan can only be rescheduled once."); - } - } if(loan.isMultiDisburmentLoan()) { dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(RescheduleLoansApiConstants.resheduleForMultiDisbursementNotSupportedErrorCode, "Loan rescheduling is not supported for multidisbursement loans"); @@ -232,7 +214,6 @@ public class LoanRescheduleRequestDataValidator { final Loan loan = loanRescheduleRequest.getLoan(); if (loan != null) { - Long loanId = loan.getId(); if (!loan.status().isActive()) { dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.is.not.active", "Loan is not active"); @@ -251,16 +232,6 @@ public class LoanRescheduleRequestDataValidator { "loan.repayment.schedule.installment." + "obligation.met", "Repayment schedule installment obligation met"); } } - - if (loanId != null) { - List<LoanRescheduleRequestData> loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService - .readLoanRescheduleRequests(loanId, LoanStatus.APPROVED.getValue()); - - if (loanRescheduleRequestData.size() > 0) { - dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled", - "The loan can only be rescheduled once."); - } - } } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java deleted file mode 100644 index bcb7bc4..0000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain; - -import java.math.MathContext; - -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO; -import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; -import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator; -import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator; -import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod; - -public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory { - - @Override - public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod, - final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency, - final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance, - final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, final FloatingRateDTO floatingRateDTO, - final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) { - - LoanRescheduleModel loanRescheduleModel = null; - - switch (interestMethod) { - case DECLINING_BALANCE: - loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest, - applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar, - floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays); - break; - - case FLAT: - loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest, - applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar, - floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays); - break; - - case INVALID: - break; - } - - return loanRescheduleModel; - } -} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java index 8893054..8a0a844 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java @@ -18,20 +18,27 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain; -import java.math.BigDecimal; import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations; import org.apache.fineract.useradministration.domain.AppUser; import org.joda.time.LocalDate; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -40,116 +47,97 @@ import org.springframework.data.jpa.domain.AbstractPersistable; @Table(name = "m_loan_reschedule_request") public class LoanRescheduleRequest extends AbstractPersistable<Long> { - @ManyToOne + @ManyToOne @JoinColumn(name = "loan_id", nullable = false) private Loan loan; - @Column(name = "status_enum", nullable = false) - private Integer statusEnum; - - @Column(name = "reschedule_from_installment") - private Integer rescheduleFromInstallment; - - @Column(name = "grace_on_principal") - private Integer graceOnPrincipal; - - @Column(name = "grace_on_interest") - private Integer graceOnInterest; - - @Temporal(TemporalType.DATE) + @Column(name = "status_enum", nullable = false) + private Integer statusEnum; + + @Column(name = "reschedule_from_installment") + private Integer rescheduleFromInstallment; + + @Temporal(TemporalType.DATE) @Column(name = "reschedule_from_date") - private Date rescheduleFromDate; - - @Temporal(TemporalType.DATE) - @Column(name = "adjusted_due_date") - private Date adjustedDueDate; - - @Column(name = "extra_terms") - private Integer extraTerms; - - @Column(name = "recalculate_interest") - private Boolean recalculateInterest; - - @Column(name = "interest_rate", scale = 6, precision = 19) - private BigDecimal interestRate; - - @ManyToOne + private Date rescheduleFromDate; + + @Column(name = "recalculate_interest") + private Boolean recalculateInterest; + + @ManyToOne @JoinColumn(name = "reschedule_reason_cv_id") - private CodeValue rescheduleReasonCodeValue; - - @Column(name = "reschedule_reason_comment") - private String rescheduleReasonComment; - - @Temporal(TemporalType.DATE) + private CodeValue rescheduleReasonCodeValue; + + @Column(name = "reschedule_reason_comment") + private String rescheduleReasonComment; + + @Temporal(TemporalType.DATE) @Column(name = "submitted_on_date") - private Date submittedOnDate; - - @ManyToOne + private Date submittedOnDate; + + @ManyToOne @JoinColumn(name = "submitted_by_user_id") - private AppUser submittedByUser; - - @Temporal(TemporalType.DATE) + private AppUser submittedByUser; + + @Temporal(TemporalType.DATE) @Column(name = "approved_on_date") - private Date approvedOnDate; + private Date approvedOnDate; - @ManyToOne + @ManyToOne @JoinColumn(name = "approved_by_user_id") - private AppUser approvedByUser; + private AppUser approvedByUser; - @Temporal(TemporalType.DATE) + @Temporal(TemporalType.DATE) @Column(name = "rejected_on_date") - private Date rejectedOnDate; + private Date rejectedOnDate; - @ManyToOne + @ManyToOne @JoinColumn(name = "rejected_by_user_id") - private AppUser rejectedByUser; - - /** - * LoanRescheduleRequest constructor - **/ - protected LoanRescheduleRequest() {} - - /** - * LoanRescheduleRequest constructor - **/ - private LoanRescheduleRequest(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment, - final Integer graceOnPrincipal, final Integer graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate, - final Integer extraTerms, final Boolean recalculateInterest, final BigDecimal interestRate, final CodeValue rescheduleReasonCodeValue, - final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, - final Date approvedOnDate, final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) { - this.loan = loan; - this.statusEnum = statusEnum; - this.rescheduleFromInstallment = rescheduleFromInstallment; - this.graceOnPrincipal = graceOnPrincipal; - this.graceOnInterest = graceOnInterest; - this.rescheduleFromDate = rescheduleFromDate; - this.extraTerms = extraTerms; - this.interestRate = interestRate; - this.rescheduleReasonCodeValue = rescheduleReasonCodeValue; - this.rescheduleReasonComment = rescheduleReasonComment; - this.submittedOnDate = submittedOnDate; - this.submittedByUser = submittedByUser; - this.approvedOnDate = approvedOnDate; - this.approvedByUser = approvedByUser; - this.rejectedOnDate = rejectedOnDate; - this.rejectedByUser = rejectedByUser; - this.adjustedDueDate = adjustedDueDate; - this.recalculateInterest = recalculateInterest; - } - - /** - * @return a new instance of the LoanRescheduleRequest class - **/ - public static LoanRescheduleRequest instance(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment, - final Integer graceOnPrincipal, final Integer graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate, - final Integer extraTerms, final Boolean recalculateInterest, final BigDecimal interestRate, final CodeValue rescheduleReasonCodeValue, - final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, - final Date approvedOnDate, final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) { - - return new LoanRescheduleRequest(loan, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest, - rescheduleFromDate, adjustedDueDate, extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment, submittedOnDate, - submittedByUser, approvedOnDate, approvedByUser, rejectedOnDate, rejectedByUser); - } + private AppUser rejectedByUser; + + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch=FetchType.EAGER) + @JoinColumn(name = "loan_reschedule_request_id", nullable = false) + private Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = new HashSet<>(); + + /** + * LoanRescheduleRequest constructor + **/ + protected LoanRescheduleRequest() {} + + /** + * LoanRescheduleRequest constructor + **/ + private LoanRescheduleRequest(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment, + final Date rescheduleFromDate, final Boolean recalculateInterest, final CodeValue rescheduleReasonCodeValue, + final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, final Date approvedOnDate, + final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) { + this.loan = loan; + this.statusEnum = statusEnum; + this.rescheduleFromInstallment = rescheduleFromInstallment; + this.rescheduleFromDate = rescheduleFromDate; + this.rescheduleReasonCodeValue = rescheduleReasonCodeValue; + this.rescheduleReasonComment = rescheduleReasonComment; + this.submittedOnDate = submittedOnDate; + this.submittedByUser = submittedByUser; + this.approvedOnDate = approvedOnDate; + this.approvedByUser = approvedByUser; + this.rejectedOnDate = rejectedOnDate; + this.rejectedByUser = rejectedByUser; + this.recalculateInterest = recalculateInterest; + } + + /** + * @return a new instance of the LoanRescheduleRequest class + **/ + public static LoanRescheduleRequest instance(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment, + final Date rescheduleFromDate, final Boolean recalculateInterest, final CodeValue rescheduleReasonCodeValue, + final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, final Date approvedOnDate, + final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) { + + return new LoanRescheduleRequest(loan, statusEnum, rescheduleFromInstallment, rescheduleFromDate, recalculateInterest, + rescheduleReasonCodeValue, rescheduleReasonComment, submittedOnDate, submittedByUser, approvedOnDate, approvedByUser, + rejectedOnDate, rejectedByUser); + } /** * @return the reschedule request loan object @@ -173,20 +161,6 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> { } /** - * @return the grace on principal - **/ - public Integer getGraceOnPrincipal() { - return this.graceOnPrincipal; - } - - /** - * @return the grace on interest - **/ - public Integer getGraceOnInterest() { - return this.graceOnInterest; - } - - /** * @return due date of the rescheduling start point **/ public LocalDate getRescheduleFromDate() { @@ -201,34 +175,6 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> { } /** - * @return due date of the first rescheduled installment - **/ - public LocalDate getAdjustedDueDate() { - - LocalDate localDate = null; - - if(this.adjustedDueDate != null) { - localDate = new LocalDate(this.adjustedDueDate); - } - - return localDate; - } - - /** - * @return extra terms to be added after the last loan installment - **/ - public Integer getExtraTerms() { - return this.extraTerms; - } - - /** - * @return the new interest rate to be applied to unpaid installments - **/ - public BigDecimal getInterestRate() { - return this.interestRate; - } - - /** * @return the reschedule reason code value object **/ public CodeValue getRescheduleReasonCodeValue() { @@ -348,4 +294,24 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> { this.statusEnum = LoanStatus.REJECTED.getValue(); } } + + public void updateLoanRescheduleRequestToTermVariationMappings(final List<LoanRescheduleRequestToTermVariationMapping> mapping) { + this.loanRescheduleRequestToTermVariationMappings.addAll(mapping); + } + + public Set<LoanRescheduleRequestToTermVariationMapping> getLoanRescheduleRequestToTermVariationMappings() { + return this.loanRescheduleRequestToTermVariationMappings; + } + + public LoanTermVariations getDueDateTermVariationIfExists() { + if(this.loanRescheduleRequestToTermVariationMappings != null + && this.loanRescheduleRequestToTermVariationMappings.size() > 0){ + for (LoanRescheduleRequestToTermVariationMapping mapping : this.loanRescheduleRequestToTermVariationMappings) { + if(mapping.getLoanTermVariations().getTermType().isDueDateVariation()){ + return mapping.getLoanTermVariations(); + } + } + } + return null; + } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java deleted file mode 100644 index f2e8bc7..0000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain; - -import java.math.MathContext; - -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO; -import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; -import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod; - -public interface LoanReschedulerFactory { - - public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod, - final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency, - final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, - final Calendar loanCalendar, FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, - final Integer numberofdays); -} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java index b300b4d..f91649e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java @@ -18,9 +18,9 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; public interface LoanReschedulePreviewPlatformService { - public LoanRescheduleModel previewLoanReschedule(Long requestId); + public LoanScheduleModel previewLoanReschedule(Long requestId); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java index 64040af..f6a918d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java @@ -18,41 +18,33 @@ */ package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service; -import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; +import java.util.ArrayList; import java.util.List; +import java.util.Set; -import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.organisation.holiday.domain.Holiday; -import org.apache.fineract.organisation.holiday.domain.HolidayRepository; -import org.apache.fineract.organisation.holiday.domain.HolidayStatusType; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; -import org.apache.fineract.organisation.workingdays.domain.WorkingDays; -import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; -import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; -import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO; -import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData; -import org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoundException; -import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService; -import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; +import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; +import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory; -import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory; -import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel; +import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping; +import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations; +import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository; import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException; import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService; -import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -60,103 +52,94 @@ import org.springframework.stereotype.Service; public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService { private final LoanRescheduleRequestRepository loanRescheduleRequestRepository; - private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; - private final ConfigurationDomainService configurationDomainService; - private final HolidayRepository holidayRepository; - private final WorkingDaysRepositoryWrapper workingDaysRepository; - private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService; - private final CalendarInstanceRepository calendarInstanceRepository; - private final FloatingRatesReadPlatformService floatingRatesReadPlatformService; private final LoanUtilService loanUtilService; + private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; + private final LoanScheduleGeneratorFactory loanScheduleFactory; + private final LoanSummaryWrapper loanSummaryWrapper; + private final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator(); @Autowired public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository, - final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, - final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository, - final WorkingDaysRepositoryWrapper workingDaysRepository, - final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService, - final CalendarInstanceRepository calendarInstanceRepository, - final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService) { + final LoanUtilService loanUtilService, + final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, + final LoanScheduleGeneratorFactory loanScheduleFactory, final LoanSummaryWrapper loanSummaryWrapper) { this.loanRescheduleRequestRepository = loanRescheduleRequestRepository; - this.applicationCurrencyRepository = applicationCurrencyRepository; - this.configurationDomainService = configurationDomainService; - this.holidayRepository = holidayRepository; - this.workingDaysRepository = workingDaysRepository; - this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService; - this.calendarInstanceRepository = calendarInstanceRepository; - this.floatingRatesReadPlatformService = floatingRatesReadPlatformService; this.loanUtilService = loanUtilService; + this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; + this.loanScheduleFactory = loanScheduleFactory; + this.loanSummaryWrapper = loanSummaryWrapper; } @Override - public LoanRescheduleModel previewLoanReschedule(Long requestId) { + public LoanScheduleModel previewLoanReschedule(Long requestId) { final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(requestId); if (loanRescheduleRequest == null) { throw new LoanRescheduleRequestNotFoundException(requestId); } Loan loan = loanRescheduleRequest.getLoan(); - final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); - final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan - .getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue()); - final WorkingDays workingDays = this.workingDaysRepository.findOne(); - final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail(); - final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency(); - final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); - - final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod(); - final RoundingMode roundingMode = MoneyHelper.getRoundingMode(); - final MathContext mathContext = new MathContext(8, roundingMode); - List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive( - loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest); - HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); - CalendarInstance restCalendarInstance = null; - CalendarInstance compoundingCalendarInstance = null; - if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { - restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(), - CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue()); - compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId( - loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue()); + ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, + loanRescheduleRequest.getRescheduleFromDate()); + LocalDate rescheduleFromDate = null; + List<LoanTermVariationsData> removeLoanTermVariationsData = new ArrayList<>(); + final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO); + LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists(); + if(dueDateVariationInCurrentRequest != null){ + for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) { + if (loanTermVariation.getDateValue().equals(dueDateVariationInCurrentRequest.fetchTermApplicaDate())) { + rescheduleFromDate = loanTermVariation.getTermApplicableFrom(); + removeLoanTermVariationsData.add(loanTermVariation); + } + } } - final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(), - CalendarEntityType.LOANS.getValue()); - Calendar loanCalendar = null; - if (loanCalendarInstance != null) { - loanCalendar = loanCalendarInstance.getCalendar(); + loanApplicationTerms.getLoanTermVariations().getDueDateVariation().removeAll(removeLoanTermVariationsData); + if (rescheduleFromDate == null) { + rescheduleFromDate = loanRescheduleRequest.getRescheduleFromDate(); } - final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan); - Boolean isSkipRepaymentOnFirstMonth = false; - Integer numberOfDays = 0; - boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled(); - if(isSkipRepaymentOnFirstMonthEnabled){ - isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar); - if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); } - + List<LoanTermVariationsData> loanTermVariationsData = new ArrayList<>(); + LocalDate adjustedApplicableDate = null; + Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = loanRescheduleRequest.getLoanRescheduleRequestToTermVariationMappings(); + if (!loanRescheduleRequestToTermVariationMappings.isEmpty()) { + for (LoanRescheduleRequestToTermVariationMapping loanRescheduleRequestToTermVariationMapping : loanRescheduleRequestToTermVariationMappings) { + if (loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().getTermType().isDueDateVariation() + && rescheduleFromDate != null) { + adjustedApplicableDate = loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().fetchDateValue(); + loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().setTermApplicableFrom( + rescheduleFromDate.toDate()); + } + loanTermVariationsData.add(loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().toData()); + } } - LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod, - loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, - loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, numberOfDays); - LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel, - oldPeriods); - return loanRescheduleModelWithOldPeriods; - } - - private FloatingRateDTO constructFloatingRateDTO(final Loan loan) { - FloatingRateDTO floatingRateDTO = null; - if (loan.loanProduct().isLinkedToFloatingInterestRate()) { - boolean isFloatingInterestRate = loan.getIsFloatingInterestRate(); - BigDecimal interestRateDiff = loan.getInterestRateDifferential(); - List<FloatingRatePeriodData> baseLendingRatePeriods = null; - try{ - baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate() - .getRatePeriods(); - }catch(final FloatingRateNotFoundException ex){ - // Do not do anything + + for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) { + if (rescheduleFromDate.isBefore(loanTermVariation.getTermApplicableFrom())) { + LocalDate applicableDate = this.scheduledDateGenerator.generateNextRepaymentDate(rescheduleFromDate, loanApplicationTerms, + false, loanApplicationTerms.getHolidayDetailDTO()); + if (loanTermVariation.getTermApplicableFrom().equals(applicableDate)) { + LocalDate adjustedDate = this.scheduledDateGenerator.generateNextRepaymentDate(adjustedApplicableDate, + loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO()); + loanTermVariation.setApplicableFromDate(adjustedDate); + loanTermVariationsData.add(loanTermVariation); + } } - floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff, - baseLendingRatePeriods); } - return floatingRateDTO; + + loanApplicationTerms.getLoanTermVariations().updateLoanTermVariationsData(loanTermVariationsData); + final RoundingMode roundingMode = MoneyHelper.getRoundingMode(); + final MathContext mathContext = new MathContext(8, roundingMode); + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(loan.transactionProcessingStrategy()); + final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); + final LoanLifecycleStateMachine loanLifecycleStateMachine = null; + loan.setHelpers(loanLifecycleStateMachine, this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory); + final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, + loan, loanApplicationTerms.getHolidayDetailDTO(), + loanRepaymentScheduleTransactionProcessor, rescheduleFromDate); + final LoanScheduleModel loanScheduleModel = loanSchedule.getLoanScheduleModel(); + LoanScheduleModel loanScheduleModels = LoanScheduleModel.withLoanScheduleModelPeriods(loanScheduleModel.getPeriods(), + loanScheduleModel); + + return loanScheduleModels; } }
