interest recalculation performance issue fixes

This commit is contained in:
Pramod Nuthakki
2015-03-08 15:56:10 +05:30
parent eaa32e9465
commit 4e7f9031be
27 changed files with 1319 additions and 1472 deletions
@@ -3389,18 +3389,20 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.55", "46.36", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
loanSchedule = this.loanTransactionHelper.getLoanFutureRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); loanSchedule = this.loanTransactionHelper.getLoanFutureRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, 0, "4965.31", "92.51", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 0, "4965.3", "92.52", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues, 0); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues, 0);
@@ -3495,9 +3497,10 @@ public class ClientLoanIntegrationTest {
List<Map<String, Object>> expectedvalues = new ArrayList<>(); List<Map<String, Object>> expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2508.98", "19.93", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "24.72", "8.38", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
@@ -3513,9 +3516,10 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2490.75", "38.16", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.57", "46.34", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.71", "23.2", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2497.49", "31.42", "200", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.28", "11.63", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2508.96", "19.95", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "28.22", "8.4", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
@@ -3529,9 +3533,10 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2508.98", "19.93", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "24.72", "8.38", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
Float earlyPayment = new Float("5100"); Float earlyPayment = new Float("5100");
@@ -3544,9 +3549,10 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "5100", "27.96", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "5057.13", "42.87", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "0", "11.16", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "0", "19.55", "200", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2417.24", "11.16", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2349.13", "11.35", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "110.98", "8.26", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID); HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
@@ -3614,11 +3620,14 @@ public class ClientLoanIntegrationTest {
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.55", "46.36", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.33", "46.58", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.33", "46.58", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.13", "11.78", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.13", "11.78", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "35.24", "0.16", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
String JobName = "Apply penalty to overdue loans"; String JobName = "Apply penalty to overdue loans";
@@ -3813,9 +3822,10 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.55", "46.36", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
@@ -3889,9 +3899,10 @@ public class ClientLoanIntegrationTest {
expectedvalues = new ArrayList<>(); expectedvalues = new ArrayList<>();
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.55", "46.36", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.24", "11.67", "0.0", "0.0");
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
todaysDate = Calendar.getInstance(); todaysDate = Calendar.getInstance();
@@ -22,12 +22,13 @@ public class ScheduleGeneratorDTO {
LocalDate lastTransactionDate; LocalDate lastTransactionDate;
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency, public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO) { final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
final CalendarInstance calendarInstanceForInterestRecalculation) {
this.loanScheduleFactory = loanScheduleFactory; this.loanScheduleFactory = loanScheduleFactory;
this.applicationCurrency = applicationCurrency; this.applicationCurrency = applicationCurrency;
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate; this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
this.calendarInstanceForInterestRecalculation = null; this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
this.recalculateFrom = null; this.recalculateFrom = null;
this.overdurPenaltyWaitPeriod = null; this.overdurPenaltyWaitPeriod = null;
this.lastTransactionDate = null; this.lastTransactionDate = null;
@@ -102,6 +102,7 @@ import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
@@ -2363,12 +2364,23 @@ public class Loan extends AbstractPersistable<Long> {
loanVariationTermsData.add(data); loanVariationTermsData.add(data);
} }
CalendarInstance restCalendarInstance = null;
RecalculationFrequencyType recalculationFrequencyType = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct.getProductInterestRecalculationDetails()
.getInterestRecalculationCompoundingMethod());
}
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(), final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(),
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(), getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf()); this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(), final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
scheduleGeneratorDTO.getHolidayDetailDTO()); scheduleGeneratorDTO.getHolidayDetailDTO());
@@ -4300,17 +4312,15 @@ public class Loan extends AbstractPersistable<Long> {
final Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<>(); final Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<>();
if (loanCharge.isInstalmentFee()) { if (loanCharge.isInstalmentFee()) {
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
if (!installment.isRecalculatedInterestComponent()) { BigDecimal amount = BigDecimal.ZERO;
BigDecimal amount = BigDecimal.ZERO; if (loanCharge.getChargeCalculation().isFlat()) {
if (loanCharge.getChargeCalculation().isFlat()) { amount = loanCharge.amount().divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments()));
amount = loanCharge.amount().divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments())); } else {
} else { amount = calculateInstallmentChargeAmount(loanCharge.getChargeCalculation(), loanCharge.getPercentage(), installment)
amount = calculateInstallmentChargeAmount(loanCharge.getChargeCalculation(), loanCharge.getPercentage(), .getAmount();
installment).getAmount();
}
final LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
loanChargePerInstallments.add(loanInstallmentCharge);
} }
final LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
loanChargePerInstallments.add(loanInstallmentCharge);
} }
} }
return loanChargePerInstallments; return loanChargePerInstallments;
@@ -4636,17 +4646,6 @@ public class Loan extends AbstractPersistable<Long> {
if (loanSchedule == null) { return; } if (loanSchedule == null) { return; }
updateLoanSchedule(loanSchedule, currentUser); updateLoanSchedule(loanSchedule, currentUser);
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate(); LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
final List<LoanTransaction> copyTransactions = new ArrayList<>();
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
}
loanRepaymentScheduleTransactionProcessor.populateDerivedFeildsWithoutReprocess(getDisbursementDate(), copyTransactions,
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
Set<LoanCharge> charges = this.charges(); Set<LoanCharge> charges = this.charges();
for (LoanCharge loanCharge : charges) { for (LoanCharge loanCharge : charges) {
if (!loanCharge.isDueAtDisbursement()) { if (!loanCharge.isDueAtDisbursement()) {
@@ -4662,6 +4661,17 @@ public class Loan extends AbstractPersistable<Long> {
} }
} }
} }
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
final List<LoanTransaction> copyTransactions = new ArrayList<>();
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
}
loanRepaymentScheduleTransactionProcessor.populateDerivedFeildsWithoutReprocess(getDisbursementDate(), copyTransactions,
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
updateLoanSummaryDerivedFields(); updateLoanSummaryDerivedFields();
} }
@@ -4682,8 +4692,7 @@ public class Loan extends AbstractPersistable<Long> {
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(), final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(),
generatorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(), generatorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
loanRepaymentScheduleTransactionProcessor, this.repaymentScheduleInstallments, generatorDTO.getRecalculateFrom(), loanRepaymentScheduleTransactionProcessor, generatorDTO.getLastTransactionDate());
generatorDTO.getLastTransactionDate(), generatorDTO.getPenaltyWaitPeriod());
return loanSchedule; return loanSchedule;
} }
@@ -4723,7 +4732,8 @@ public class Loan extends AbstractPersistable<Long> {
return loanApplicationTerms; return loanApplicationTerms;
} }
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory) { public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory,
CalendarInstance restCalendarInstance, HolidayDetailDTO holidayDetailDTO) {
LoanRepaymentScheduleInstallment installment = null; LoanRepaymentScheduleInstallment installment = null;
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) { if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
@@ -4759,14 +4769,23 @@ public class Loan extends AbstractPersistable<Long> {
loanVariationTermsData.add(data); loanVariationTermsData.add(data);
} }
RecalculationFrequencyType recalculationFrequencyType = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod());
}
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency, final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency,
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null,
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf()); this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(), installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges()); DateUtils.getLocalDateOfTenant(), loanApplicationTerms, mc, charges(), holidayDetailDTO);
} else { } else {
installment = this.getTotalOutstandingOnLoan(); installment = this.getTotalOutstandingOnLoan();
} }
@@ -4903,12 +4922,15 @@ public class Loan extends AbstractPersistable<Long> {
} }
/** /**
* @param restCalendarInstance
* TODO
* @param loan * @param loan
* the Loan object * the Loan object
* @return application terms of the Loan object * @return application terms of the Loan object
**/ **/
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency) { public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
final CalendarInstance restCalendarInstance) {
LoanProduct loanProduct = loanProduct(); LoanProduct loanProduct = loanProduct();
// LoanProductRelatedDetail loanProductRelatedDetail = // LoanProductRelatedDetail loanProductRelatedDetail =
// getLoanRepaymentScheduleDetail(); // getLoanRepaymentScheduleDetail();
@@ -4961,11 +4983,20 @@ public class Loan extends AbstractPersistable<Long> {
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount); LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
loanVariationTermsData.add(data); loanVariationTermsData.add(data);
RecalculationFrequencyType recalculationFrequencyType = null;
InterestRecalculationCompoundingMethod compoundingMethod = null;
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct.getProductInterestRecalculationDetails()
.getInterestRecalculationCompoundingMethod());
}
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData, inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate, maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf()); this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
} }
/** /**
@@ -546,9 +546,13 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday, HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
allowTransactionsOnNonWorkingDay); allowTransactionsOnNonWorkingDay);
CalendarInstance restCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency, ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, holidayDetailDTO); calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
return scheduleGeneratorDTO; return scheduleGeneratorDTO;
} }
@@ -33,20 +33,20 @@ public class LoanRepaymentScheduleProcessingWrapper {
for (final LoanRepaymentScheduleInstallment period : repaymentPeriods) { for (final LoanRepaymentScheduleInstallment period : repaymentPeriods) {
final Money feeChargesDueForRepaymentPeriod = cumulativeFeeChargesDueWithin(startDate, period.getDueDate(), loanCharges, final Money feeChargesDueForRepaymentPeriod = cumulativeFeeChargesDueWithin(startDate, period.getDueDate(), loanCharges,
currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, !period.isRecalculatedInterestComponent(), currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, true,
lastTransactionDate); lastTransactionDate);
final Money feeChargesWaivedForRepaymentPeriod = cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges, final Money feeChargesWaivedForRepaymentPeriod = cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges,
currency, !period.isRecalculatedInterestComponent()); currency, true);
final Money feeChargesWrittenOffForRepaymentPeriod = cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(), final Money feeChargesWrittenOffForRepaymentPeriod = cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(),
loanCharges, currency, !period.isRecalculatedInterestComponent()); loanCharges, currency, true);
final Money penaltyChargesDueForRepaymentPeriod = cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(), final Money penaltyChargesDueForRepaymentPeriod = cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(),
loanCharges, currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, loanCharges, currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest,
!period.isRecalculatedInterestComponent(), lastTransactionDate); true, lastTransactionDate);
final Money penaltyChargesWaivedForRepaymentPeriod = cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(), final Money penaltyChargesWaivedForRepaymentPeriod = cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(),
loanCharges, currency, !period.isRecalculatedInterestComponent()); loanCharges, currency, true);
final Money penaltyChargesWrittenOffForRepaymentPeriod = cumulativePenaltyChargesWrittenOffWithin(startDate, final Money penaltyChargesWrittenOffForRepaymentPeriod = cumulativePenaltyChargesWrittenOffWithin(startDate,
period.getDueDate(), loanCharges, currency, !period.isRecalculatedInterestComponent()); period.getDueDate(), loanCharges, currency, true);
period.updateChargePortion(feeChargesDueForRepaymentPeriod, feeChargesWaivedForRepaymentPeriod, period.updateChargePortion(feeChargesDueForRepaymentPeriod, feeChargesWaivedForRepaymentPeriod,
feeChargesWrittenOffForRepaymentPeriod, penaltyChargesDueForRepaymentPeriod, penaltyChargesWaivedForRepaymentPeriod, feeChargesWrittenOffForRepaymentPeriod, penaltyChargesDueForRepaymentPeriod, penaltyChargesWaivedForRepaymentPeriod,
@@ -11,7 +11,6 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@@ -29,7 +28,6 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor; import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor; import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.RecalculationDetail;
/** /**
* Abstract implementation of {@link LoanRepaymentScheduleTransactionProcessor} * Abstract implementation of {@link LoanRepaymentScheduleTransactionProcessor}
@@ -140,16 +138,17 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
} }
for (final LoanTransaction loanTransaction : transactionstoBeProcessed) { for (final LoanTransaction loanTransaction : transactionstoBeProcessed) {
if(!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) { if (!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) {
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() { final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
@Override
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) { @Override
return ord1.getDueDate().compareTo(ord2.getDueDate()); public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
} return ord1.getDueDate().compareTo(ord2.getDueDate());
}; }
Collections.sort(installments,byDate); };
} Collections.sort(installments, byDate);
}
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) { if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
// pass through for new transactions // pass through for new transactions
@@ -183,12 +182,11 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
} else if (loanTransaction.isWriteOff()) { } else if (loanTransaction.isWriteOff()) {
loanTransaction.resetDerivedComponents(); loanTransaction.resetDerivedComponents();
handleWriteOff(loanTransaction, currency, installments); handleWriteOff(loanTransaction, currency, installments);
} } else if (loanTransaction.isRefundForActiveLoan()) {
else if(loanTransaction.isRefundForActiveLoan()) {
loanTransaction.resetDerivedComponents(); loanTransaction.resetDerivedComponents();
handleRefund(loanTransaction, currency, installments,charges); handleRefund(loanTransaction, currency, installments, charges);
} }
} }
return changedTransactionDetail; return changedTransactionDetail;
} }
@@ -470,47 +468,18 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
} }
@Override @Override
public List<RecalculationDetail> handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement, public Money handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments, final List<LoanRepaymentScheduleInstallment> installments) {
final LoanRepaymentScheduleInstallment installment, final Map<LocalDate, LocalDate> recalculationDates, Money unProcessed = Money.zero(currency);
final LoanTransaction preCloseTransaction) {
List<RecalculationDetail> earlypaymentDetail = new ArrayList<>();
Money currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
LocalDate maxTransactionDate = null;
Set<LocalDate> transaDates = recalculationDates.keySet();
for (LocalDate transactionDate : transaDates) {
if (maxTransactionDate == null || transactionDate.isAfter(maxTransactionDate)) {
maxTransactionDate = transactionDate;
}
}
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) { for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
Money amountToProcess = null; Money amountToProcess = null;
LocalDate transactionDate = loanTransaction.getTransactionDate();
if (loanTransaction != preCloseTransaction) {
transactionDate = recalculationDates.get(transactionDate);
}
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction); final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) { if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) {
newLoanTransaction.resetDerivedComponents(); newLoanTransaction.resetDerivedComponents();
} }
unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
Money unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
if (loanTransaction.getTransactionDate().isEqual(maxTransactionDate) && transactionDate.isAfter(installment.getFromDate())
&& transactionDate.isBefore(installment.getDueDate())) {
Money earlyPayment = currentInstallmentOutstanding.minus(installment.getTotalOutstanding(currency));
if (earlyPayment.isGreaterThanZero()
&& (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction
.isRecoveryRepayment())) {
earlypaymentDetail.add(new RecalculationDetail(false, transactionDate, null, earlyPayment, false));
}
currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
}
if (unProcessed.isGreaterThanZero()) {
earlypaymentDetail.add(new RecalculationDetail(false, transactionDate, null, unProcessed, false));
}
} }
return earlypaymentDetail; return unProcessed;
} }
@Override @Override
@@ -519,114 +488,85 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
} }
@Override @Override
public void applyTransaction(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency, public void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments) { List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) { // TODO Auto-generated method stub
Money amountToProcess = null;
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction); final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
newLoanTransaction.resetDerivedComponents();
processTransaction(newLoanTransaction, currency, installments, amountToProcess); @Override
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
return ord1.getDueDate().compareTo(ord2.getDueDate());
}
};
Collections.sort(installments, Collections.reverseOrder(byDate));
Money transactionAmountUnprocessed = loanTransaction.getAmount(currency);
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
Money outstanding = currentInstallment.getTotalOutstanding(currency);
Money due = currentInstallment.getDue(currency);
if (outstanding.isLessThan(due)) {
transactionAmountUnprocessed = handleRefundTransactionPaymentOfInstallment(currentInstallment, loanTransaction,
transactionAmountUnprocessed);
}
if (transactionAmountUnprocessed.isZero()) break;
} }
final Set<LoanCharge> loanFees = extractFeeCharges(charges);
final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges);
Integer installmentNumber = null;
final Money feeCharges = loanTransaction.getFeeChargesPortion(currency);
if (feeCharges.isGreaterThanZero()) {
undoChargesPaidAmountBy(loanTransaction, feeCharges, loanFees, installmentNumber);
}
final Money penaltyCharges = loanTransaction.getPenaltyChargesPortion(currency);
if (penaltyCharges.isGreaterThanZero()) {
undoChargesPaidAmountBy(loanTransaction, penaltyCharges, loanPenalties, installmentNumber);
}
} }
@Override
public void handleRefund(LoanTransaction loanTransaction,
MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments,
final Set<LoanCharge> charges) {
// TODO Auto-generated method stub
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() { /**
@Override * Invoked when a there is a refund of an active loan or undo of an active
public int compare(LoanRepaymentScheduleInstallment ord1, * loan
LoanRepaymentScheduleInstallment ord2) { *
return ord1.getDueDate().compareTo(ord2.getDueDate()); * Undoes principal, interest, fees and charges of this transaction based on
} * the repayment strategy
}; *
Collections.sort(installments, Collections.reverseOrder(byDate)); */
Money transactionAmountUnprocessed = loanTransaction protected abstract Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
.getAmount(currency); final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed);
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) { private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
Money outstanding = currentInstallment final Integer installmentNumber) {
.getTotalOutstanding(currency);
Money due = currentInstallment.getDue(currency);
if (outstanding.isLessThan(due)) { Money amountRemaining = feeCharges;
transactionAmountUnprocessed = handleRefundTransactionPaymentOfInstallment( while (amountRemaining.isGreaterThanZero()) {
currentInstallment, loanTransaction, final LoanCharge paidCharge = findLatestPaidChargeFromUnOrderedSet(charges, feeCharges.getCurrency());
transactionAmountUnprocessed);
} if (paidCharge != null) {
Money feeAmount = feeCharges.zero();
if (transactionAmountUnprocessed.isZero()) final Money amountDeductedTowardsCharge = paidCharge.undoPaidOrPartiallyAmountBy(amountRemaining, installmentNumber,
break; feeAmount);
if (amountDeductedTowardsCharge.isGreaterThanZero()) {
} final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, paidCharge, amountDeductedTowardsCharge
.getAmount().multiply(new BigDecimal(-1)), null);
loanTransaction.getLoanChargesPaid().add(loanChargePaidBy);
final Set<LoanCharge> loanFees = extractFeeCharges(charges); amountRemaining = amountRemaining.minus(amountDeductedTowardsCharge);
final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges); }
Integer installmentNumber = null; }
}
final Money feeCharges = loanTransaction.getFeeChargesPortion(currency); }
if (feeCharges.isGreaterThanZero()) {
undoChargesPaidAmountBy(loanTransaction, feeCharges, loanFees,
installmentNumber);
}
final Money penaltyCharges = loanTransaction
.getPenaltyChargesPortion(currency);
if (penaltyCharges.isGreaterThanZero()) {
undoChargesPaidAmountBy(loanTransaction, penaltyCharges,
loanPenalties, installmentNumber);
}
}
/**
* Invoked when a there is a refund of an active loan or undo of an active
* loan
*
* Undoes principal, interest, fees and charges of this transaction based on
* the repayment strategy
*
*/
protected abstract Money handleRefundTransactionPaymentOfInstallment(
final LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction,
final Money transactionAmountUnprocessed);
private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction,
final Money feeCharges, final Set<LoanCharge> charges,
final Integer installmentNumber) {
Money amountRemaining = feeCharges;
while (amountRemaining.isGreaterThanZero()) {
final LoanCharge paidCharge = findLatestPaidChargeFromUnOrderedSet(
charges, feeCharges.getCurrency());
if (paidCharge != null) {
Money feeAmount = feeCharges.zero();
final Money amountDeductedTowardsCharge = paidCharge
.undoPaidOrPartiallyAmountBy(amountRemaining,
installmentNumber, feeAmount);
if (amountDeductedTowardsCharge.isGreaterThanZero()) {
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(
loanTransaction, paidCharge,
amountDeductedTowardsCharge.getAmount().multiply(
new BigDecimal(-1)), null);
loanTransaction.getLoanChargesPaid().add(loanChargePaidBy);
amountRemaining = amountRemaining
.minus(amountDeductedTowardsCharge);
}
}
}
}
@Override @Override
public ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(final LocalDate disbursementDate, public ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(final LocalDate disbursementDate,
@@ -636,48 +576,36 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, recalculateChargesFrom, return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, recalculateChargesFrom,
reprocessCharges); reprocessCharges);
} }
private LoanCharge findLatestPaidChargeFromUnOrderedSet(
final Set<LoanCharge> charges, MonetaryCurrency currency) {
LoanCharge latestPaidCharge = null;
LoanCharge installemntCharge = null;
LoanInstallmentCharge chargePerInstallment = null;
for (final LoanCharge loanCharge : charges) {
boolean isPaidOrPartiallyPaid = loanCharge
.isPaidOrPartiallyPaid(currency);
if (isPaidOrPartiallyPaid && !loanCharge.isDueAtDisbursement()) {
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge paidLoanChargePerInstallment = loanCharge
.getLastPaidOrPartiallyPaidInstallmentLoanCharge(currency);
if (chargePerInstallment == null
|| (paidLoanChargePerInstallment != null && chargePerInstallment
.getRepaymentInstallment()
.getDueDate()
.isBefore(
paidLoanChargePerInstallment
.getRepaymentInstallment()
.getDueDate()))) {
installemntCharge = loanCharge;
chargePerInstallment = paidLoanChargePerInstallment;
}
} else if (latestPaidCharge == null
|| (loanCharge.isPaidOrPartiallyPaid(currency))
&& loanCharge.getDueLocalDate().isAfter(
latestPaidCharge.getDueLocalDate())) {
latestPaidCharge = loanCharge;
}
}
}
if (latestPaidCharge == null
|| (chargePerInstallment != null && latestPaidCharge
.getDueLocalDate().isAfter(
chargePerInstallment.getRepaymentInstallment()
.getDueDate()))) {
latestPaidCharge = installemntCharge;
}
return latestPaidCharge; private LoanCharge findLatestPaidChargeFromUnOrderedSet(final Set<LoanCharge> charges, MonetaryCurrency currency) {
} LoanCharge latestPaidCharge = null;
LoanCharge installemntCharge = null;
LoanInstallmentCharge chargePerInstallment = null;
for (final LoanCharge loanCharge : charges) {
boolean isPaidOrPartiallyPaid = loanCharge.isPaidOrPartiallyPaid(currency);
if (isPaidOrPartiallyPaid && !loanCharge.isDueAtDisbursement()) {
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge paidLoanChargePerInstallment = loanCharge
.getLastPaidOrPartiallyPaidInstallmentLoanCharge(currency);
if (chargePerInstallment == null
|| (paidLoanChargePerInstallment != null && chargePerInstallment.getRepaymentInstallment().getDueDate()
.isBefore(paidLoanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
installemntCharge = loanCharge;
chargePerInstallment = paidLoanChargePerInstallment;
}
} else if (latestPaidCharge == null || (loanCharge.isPaidOrPartiallyPaid(currency))
&& loanCharge.getDueLocalDate().isAfter(latestPaidCharge.getDueLocalDate())) {
latestPaidCharge = loanCharge;
}
}
}
if (latestPaidCharge == null
|| (chargePerInstallment != null && latestPaidCharge.getDueLocalDate().isAfter(
chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
latestPaidCharge = installemntCharge;
}
return latestPaidCharge;
}
} }
@@ -6,16 +6,15 @@
package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor; package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail; import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.RecalculationDetail;
public interface LoanRepaymentScheduleTransactionProcessor { public interface LoanRepaymentScheduleTransactionProcessor {
@@ -29,9 +28,8 @@ public interface LoanRepaymentScheduleTransactionProcessor {
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency, void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments); List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
List<RecalculationDetail> handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency, Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentInstallment, List<LoanRepaymentScheduleInstallment> installments);
Map<LocalDate, LocalDate> recalculationDates, LoanTransaction preCloseTransaction);
/** /**
* Used in interest recalculation to introduce new interest only * Used in interest recalculation to introduce new interest only
@@ -39,16 +37,11 @@ public interface LoanRepaymentScheduleTransactionProcessor {
*/ */
boolean isInterestFirstRepaymentScheduleTransactionProcessor(); boolean isInterestFirstRepaymentScheduleTransactionProcessor();
void applyTransaction(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments);
ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(LocalDate disbursementDate, ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(LocalDate disbursementDate,
List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency, List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, LocalDate recalculateChargesFrom); List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, LocalDate recalculateChargesFrom);
void handleRefund(LoanTransaction loanTransaction, void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
MonetaryCurrency currency, final Set<LoanCharge> charges);
List<LoanRepaymentScheduleInstallment> installments,
final Set<LoanCharge> charges);
} }
@@ -110,7 +110,7 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion); transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
final Money principalPortion = Money.zero(currency); final Money principalPortion = Money.zero(currency);
loanTransaction.updateComponents(principalPortion, interestPortion, Money.zero(currency), Money.zero(currency)); loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion,penaltyChargesPortion);
} }
} }
@@ -6,7 +6,10 @@
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain; package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import java.math.MathContext; import java.math.MathContext;
import java.util.Map;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
@@ -42,14 +45,48 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal, final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
@SuppressWarnings("unused") final Money totalCumulativeInterest, @SuppressWarnings("unused") final Money totalCumulativeInterest,
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace, @SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
final int periodNumber, final MathContext mc) { final Map<LocalDate, Money> principalVariation, final LocalDate periodStartDate, final LocalDate periodEndDate,
final int daysForInterestInFullPeriod) {
LocalDate interestStartDate = periodStartDate;
Money interestForThisInstallment = totalCumulativePrincipal.zero();
Money balanceForInterestCalculation = outstandingBalance;
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
if(principalVariation != null){
for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
if (!principal.getKey().isAfter(periodEndDate)) {
int interestForDays = Days.daysBetween(interestStartDate, principal.getKey()).getDays();
if (interestForDays > 0) {
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestDueToGrace,
interestForDays, balanceForInterestCalculation);
if (loanApplicationTerms.getInterestCalculationPeriodMethod().isDaily()) {
interestForThisInstallment = interestForThisInstallment.plus(result.interest());
} else {
interestForThisInstallment = interestForThisInstallment.plus(calculateInterestForDays(daysForInterestInFullPeriod,
result.interest().getAmount(), interestForDays));
}
cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
interestStartDate = principal.getKey();
}
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue());
}
}
}
int interestForDays = Days.daysBetween(interestStartDate, periodEndDate).getDays();
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator, final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestDueToGrace, interestForDays,
daysInPeriodApplicableForInterest, outstandingBalance); balanceForInterestCalculation);
if (loanApplicationTerms.getInterestCalculationPeriodMethod().isDaily()) {
final Money interestForThisInstallment = result.interest(); interestForThisInstallment = interestForThisInstallment.plus(result.interest());
} else {
interestForThisInstallment = interestForThisInstallment.plus(calculateInterestForDays(daysForInterestInFullPeriod, result
.interest().getAmount(), interestForDays));
}
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc); daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc);
@@ -6,7 +6,10 @@
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain; package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import java.math.MathContext; import java.math.MathContext;
import java.util.Map;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGenerator { public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGenerator {
@@ -15,9 +18,10 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final PaymentPeriodsInOneYearCalculator calculator, public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final PaymentPeriodsInOneYearCalculator calculator,
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal, final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace, final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
final int periodNumber, final MathContext mc) { @SuppressWarnings("unused") Map<LocalDate, Money> principalVariation, LocalDate periodStartDate, LocalDate periodEndDate,
@SuppressWarnings("unused") int daysForInterestInFullPeriod) {
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc); daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc);
@@ -150,12 +150,11 @@ public final class LoanApplicationTerms {
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance, final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
final List<LoanTermVariationsData> emiAmountVariations, final Integer graceOnArrearsAgeing, final List<LoanTermVariationsData> emiAmountVariations, final Integer graceOnArrearsAgeing,
final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled,
BigDecimal principalThresholdForLastInstalment, Integer installmentAmountInMultiplesOf) { final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
final CalendarInstance restCalendarInstance = null;
final RecalculationFrequencyType recalculationFrequencyType = null;
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney,
@@ -173,7 +172,9 @@ public final class LoanApplicationTerms {
final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount, final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance, final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate, final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
final BigDecimal principalThresholdForLastInstalment, Integer installmentAmountInMultiplesOf) { final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
final InterestRecalculationCompoundingMethod compoundingMethod) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery(); final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -197,9 +198,6 @@ public final class LoanApplicationTerms {
final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType(); final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType();
final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled(); final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled();
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
final CalendarInstance restCalendarInstance = null;
final RecalculationFrequencyType recalculationFrequencyType = null;
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod, repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod,
@@ -208,7 +206,7 @@ public final class LoanApplicationTerms {
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance,
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType,
principalThresholdForLastInstalment, installmentAmountInMultiplesOf); principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
} }
@@ -1170,4 +1168,8 @@ public final class LoanApplicationTerms {
public ApplicationCurrency getApplicationCurrency() { public ApplicationCurrency getApplicationCurrency() {
return this.currency; return this.currency;
} }
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
return this.interestCalculationPeriodMethod;
}
} }
@@ -12,6 +12,7 @@ import java.util.Set;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO; import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
@@ -28,13 +29,12 @@ public interface LoanScheduleGenerator {
LoanScheduleModel rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges, LoanScheduleModel rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions, final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions,
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom, LocalDate lastTransactionDate, LocalDate lastTransactionDate);
int penaltyWaitPeriod);
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
MonetaryCurrency currency, LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms, MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, MathContext mc,
MathContext mc, Set<LoanCharge> charges); Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO);
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest, LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO); final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
} }
@@ -99,4 +99,9 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
public boolean isRecalculatedInterestComponent() { public boolean isRecalculatedInterestComponent() {
return false; return false;
} }
@Override
public void addPrincipalAmount(@SuppressWarnings("unused") Money principalDue) {
return;
}
} }
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
public interface LoanScheduleModelPeriod { public interface LoanScheduleModelPeriod {
@@ -33,4 +34,6 @@ public interface LoanScheduleModelPeriod {
void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge); void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge);
boolean isRecalculatedInterestComponent(); boolean isRecalculatedInterestComponent();
void addPrincipalAmount(Money principalDue);
} }
@@ -20,7 +20,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
private final int periodNumber; private final int periodNumber;
private final LocalDate fromDate; private final LocalDate fromDate;
private final LocalDate dueDate; private final LocalDate dueDate;
private final Money principalDue; private Money principalDue;
private final Money outstandingLoanBalance; private final Money outstandingLoanBalance;
private final Money interestDue; private final Money interestDue;
private Money feeChargesDue; private Money feeChargesDue;
@@ -124,6 +124,12 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
this.penaltyChargesDue = this.penaltyChargesDue.plus(penaltyCharge); this.penaltyChargesDue = this.penaltyChargesDue.plus(penaltyCharge);
this.totalDue = this.totalDue.plus(feeCharge).plus(penaltyCharge); this.totalDue = this.totalDue.plus(feeCharge).plus(penaltyCharge);
} }
@Override
public void addPrincipalAmount(final Money principalDue){
this.principalDue = this.principalDue.plus(principalDue);
this.totalDue = this.totalDue.plus(principalDue);
}
@Override @Override
public boolean isRecalculatedInterestComponent() { public boolean isRecalculatedInterestComponent() {
@@ -6,55 +6,32 @@
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain; package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
public class RecalculationDetail { public class RecalculationDetail {
private boolean isLatePayment; private LocalDate transactionDate;
private boolean isInterestompound; private boolean isProcessed;
private LocalDate startDate; private LoanTransaction transaction;
private LocalDate toDate;
private Money amount;
public RecalculationDetail(final boolean isLatePayment, final LocalDate startDate, final LocalDate toDate, final Money amount, public RecalculationDetail(final LocalDate transactionDate, final LoanTransaction transaction) {
final boolean isInterestompound) { this.transactionDate = transactionDate;
this.isLatePayment = isLatePayment; this.transaction = transaction;
this.startDate = startDate;
this.toDate = toDate;
this.amount = amount;
this.isInterestompound = isInterestompound;
} }
public boolean isLatePayment() { public LocalDate getTransactionDate() {
return this.isLatePayment; return this.transactionDate;
} }
public LocalDate getStartDate() { public LoanTransaction getTransaction() {
return this.startDate; return this.transaction;
} }
public LocalDate getToDate() { public boolean isProcessed() {
return this.toDate; return this.isProcessed;
} }
public Money getAmount() { public void setProcessed(boolean isProcessed) {
return this.amount; this.isProcessed = isProcessed;
}
public boolean isOverlapping(LocalDate startDate, LocalDate endDate) {
return !this.startDate.isAfter(endDate) && !startDate.isAfter(this.toDate);
}
public void updateAmount(Money amount) {
this.amount = amount;
}
public boolean isInterestompound() {
return this.isInterestompound;
}
public void updateStartDate(LocalDate startDate) {
this.startDate = startDate;
} }
} }
@@ -30,7 +30,11 @@ import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWr
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil; import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.calendar.domain.Calendar; import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository; import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException; import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchException; import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchException;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils; import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
@@ -66,6 +70,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -249,9 +254,24 @@ public class LoanScheduleAssembler {
final DaysInYearType daysInYearType = loanProduct.fetchDaysInYearType(); final DaysInYearType daysInYearType = loanProduct.fetchDaysInYearType();
final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled(); final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
RecalculationFrequencyType recalculationFrequencyType = null;
CalendarInstance restCalendarInstance = null;
if (isInterestRecalculationEnabled) {
recalculationFrequencyType = loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
if (!recalculationFrequencyType.isSameAsRepayment()) {
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
if (calendarStartDate == null) {
calendarStartDate = expectedDisbursementDate;
}
restCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, recalculationFrequencyType,
loanProduct.getProductInterestRecalculationDetails().getRestInterval());
}
}
final BigDecimal principalThresholdForLastInstalment = loanProduct.getPrincipalThresholdForLastInstalment(); final BigDecimal principalThresholdForLastInstalment = loanProduct.getPrincipalThresholdForLastInstalment();
final Integer installmentAmountInMultiplesOf= loanProduct.getInstallmentAmountInMultiplesOf(); final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
@@ -259,8 +279,33 @@ public class LoanScheduleAssembler {
principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, principalThresholdForLastInstalment, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
installmentAmountInMultiplesOf); restCalendarInstance, principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
}
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
final RecalculationFrequencyType recalculationFrequencyType, final Integer frequency) {
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
switch (recalculationFrequencyType) {
case DAILY:
calendarFrequencyType = CalendarFrequencyType.DAILY;
break;
case MONTHLY:
calendarFrequencyType = CalendarFrequencyType.MONTHLY;
break;
case WEEKLY:
calendarFrequencyType = CalendarFrequencyType.WEEKLY;
break;
default:
break;
}
final String title = "loan_recalculation_detail";
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
calendarFrequencyType, frequency, repeatsOnDay);
return CalendarInstance.from(calendar, null, CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
} }
private List<DisbursementData> fetchDisbursementData(final JsonObject command) { private List<DisbursementData> fetchDisbursementData(final JsonObject command) {
@@ -387,8 +432,7 @@ public class LoanScheduleAssembler {
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId, public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges, List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
final List<LoanRepaymentScheduleInstallment> previousSchedule, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, LocalDate recalculateFrom,
LocalDate recalculateDueDateChargesFrom) { LocalDate recalculateDueDateChargesFrom) {
final RoundingMode roundingMode = RoundingMode.HALF_EVEN; final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final MathContext mc = new MathContext(8, roundingMode); final MathContext mc = new MathContext(8, roundingMode);
@@ -400,24 +444,25 @@ public class LoanScheduleAssembler {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
final Long waitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
int penaltyWaitPeriod = 0;
if (waitPeriod != null) {
penaltyWaitPeriod = waitPeriod.intValue();
}
return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, detailDTO, transactions, return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, detailDTO, transactions,
loanRepaymentScheduleTransactionProcessor, previousSchedule, recalculateFrom, recalculateDueDateChargesFrom, loanRepaymentScheduleTransactionProcessor, recalculateDueDateChargesFrom);
penaltyWaitPeriod);
} }
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges) { MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges,
final Long officeId) {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod()); final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
final RoundingMode roundingMode = RoundingMode.HALF_EVEN; final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final MathContext mc = new MathContext(8, roundingMode); final MathContext mc = new MathContext(8, roundingMode);
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();
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, onDate, return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, onDate,
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc, loanCharges); loanApplicationTerms, mc, loanCharges, holidayDetailDTO);
} }
private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) { private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) {
@@ -164,7 +164,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency, LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
calculatedRepaymentsStartingFromDate, restCalendarInstance); calculatedRepaymentsStartingFromDate, restCalendarInstance);
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount( LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.charges()); loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.charges(),
loan.getOfficeId());
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus( Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency)); loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
Money interestDue = Money.zero(currency); Money interestDue = Money.zero(currency);
@@ -185,8 +186,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
} }
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(), LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
modifiedTransactions, loan.charges(), loan.fetchRepaymentScheduleInstallments(), loanRepaymentScheduleTransactionProcessor, modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, LocalDate.now());
LocalDate.now(), LocalDate.now());
LoanScheduleData scheduleDate = model.toData(); LoanScheduleData scheduleDate = model.toData();
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods(); Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
for (LoanSchedulePeriodData periodData : periodDatas) { for (LoanSchedulePeriodData periodData : periodDatas) {
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
import java.math.MathContext; import java.math.MathContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO; import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
@@ -18,19 +19,19 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
@Override @Override
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod, public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency, final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO) { final HolidayDetailDTO holidayDetailDTO,final CalendarInstance restCalendarInstance) {
LoanRescheduleModel loanRescheduleModel = null; LoanRescheduleModel loanRescheduleModel = null;
switch (interestMethod) { switch (interestMethod) {
case DECLINING_BALANCE: case DECLINING_BALANCE:
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest, loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO); applicationCurrency, holidayDetailDTO, restCalendarInstance);
break; break;
case FLAT: case FLAT:
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest, loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO); applicationCurrency, holidayDetailDTO, restCalendarInstance);
break; break;
case INVALID: case INVALID:
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
import java.math.MathContext; import java.math.MathContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO; import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
@@ -15,5 +16,5 @@ public interface LoanReschedulerFactory {
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod, public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency, final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO); final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
} }
@@ -18,6 +18,9 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays; import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
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.data.HolidayDetailDTO; import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
@@ -41,19 +44,22 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
private final HolidayRepository holidayRepository; private final HolidayRepository holidayRepository;
private final WorkingDaysRepositoryWrapper workingDaysRepository; private final WorkingDaysRepositoryWrapper workingDaysRepository;
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService; private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired @Autowired
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository, public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
final WorkingDaysRepositoryWrapper workingDaysRepository, final WorkingDaysRepositoryWrapper workingDaysRepository,
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) { final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
final CalendarInstanceRepository calendarInstanceRepository) {
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository; this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository; this.applicationCurrencyRepository = applicationCurrencyRepository;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.holidayRepository = holidayRepository; this.holidayRepository = holidayRepository;
this.workingDaysRepository = workingDaysRepository; this.workingDaysRepository = workingDaysRepository;
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService; this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
this.calendarInstanceRepository = calendarInstanceRepository;
} }
@Override @Override
@@ -78,8 +84,14 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive( List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest); loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
CalendarInstance restCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod, LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO); loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel, LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
oldPeriods); oldPeriods);
return loanRescheduleModelWithOldPeriods; return loanRescheduleModelWithOldPeriods;
@@ -321,8 +321,13 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest); .createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
CalendarInstance restCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod, LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO); loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods(); final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments(); List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
@@ -24,6 +24,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.accounting.common.AccountingRuleType; import org.mifosplatform.accounting.common.AccountingRuleType;
import org.mifosplatform.infrastructure.codes.data.CodeValueData; import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService; import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
@@ -32,6 +33,9 @@ import org.mifosplatform.infrastructure.core.service.PaginationHelper;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.infrastructure.core.service.SearchParameters; import org.mifosplatform.infrastructure.core.service.SearchParameters;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.holiday.domain.Holiday;
import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
@@ -39,11 +43,15 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.staff.data.StaffData; import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService; import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.account.data.AccountTransferData; import org.mifosplatform.portfolio.account.data.AccountTransferData;
import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations; import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations;
import org.mifosplatform.portfolio.calendar.data.CalendarData; import org.mifosplatform.portfolio.calendar.data.CalendarData;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType; 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.calendar.service.CalendarReadPlatformService; import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType; import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
@@ -59,6 +67,7 @@ import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.group.data.GroupRoleData; import org.mifosplatform.portfolio.group.data.GroupRoleData;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService; import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData; import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData; import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData; import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData;
import org.mifosplatform.portfolio.loanaccount.data.LoanApprovalData; import org.mifosplatform.portfolio.loanaccount.data.LoanApprovalData;
@@ -125,6 +134,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
private final LoanScheduleGeneratorFactory loanScheduleFactory; private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final CalendarInstanceRepository calendarInstanceRepository;
private final HolidayRepository holidayRepository;
private final ConfigurationDomainService configurationDomainService;
private final WorkingDaysRepositoryWrapper workingDaysRepository;
@Autowired @Autowired
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository, public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
@@ -135,7 +148,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final FundReadPlatformService fundReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService, final FundReadPlatformService fundReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService, final RoutingDataSource dataSource, final CodeValueReadPlatformService codeValueReadPlatformService, final RoutingDataSource dataSource,
final CalendarReadPlatformService calendarReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final CalendarReadPlatformService calendarReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final LoanScheduleGeneratorFactory loanScheduleFactory) { final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
final WorkingDaysRepositoryWrapper workingDaysRepository) {
this.context = context; this.context = context;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository; this.loanTransactionRepository = loanTransactionRepository;
@@ -152,6 +167,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.loanScheduleFactory = loanScheduleFactory; this.loanScheduleFactory = loanScheduleFactory;
this.calendarInstanceRepository = calendarInstanceRepository;
this.holidayRepository = holidayRepository;
this.configurationDomainService = configurationDomainService;
this.workingDaysRepository = workingDaysRepository;
} }
@Override @Override
@@ -391,7 +410,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final LocalDate earliestUnpaidInstallmentDate = LocalDate.now(); final LocalDate earliestUnpaidInstallmentDate = LocalDate.now();
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(this.loanScheduleFactory); CalendarInstance restCalendarInstance = null;
HolidayDetailDTO holidayDetailDTO = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
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();
holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
}
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(this.loanScheduleFactory,
restCalendarInstance, holidayDetailDTO);
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
final Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService final Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
@@ -838,8 +870,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount,
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement); isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
} }
} }
@@ -907,7 +939,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData(); this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement(); this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
this.lastDueDate = this.disbursement.disbursementDate(); this.lastDueDate = this.disbursement.disbursementDate();
this.outstandingLoanPrincipalBalance = this.disbursement.amount(); this.outstandingLoanPrincipalBalance = this.disbursement.amount();
this.disbursementData = disbursementData; this.disbursementData = disbursementData;
this.excludePastUndisbursed = isInterestRecalculationEnabled; this.excludePastUndisbursed = isInterestRecalculationEnabled;
} }
@@ -981,8 +1013,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed()); data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
periods.add(periodData); periods.add(periodData);
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount()); this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
} else if (data.isDueForDisbursement(fromDate, dueDate) } else if (data.isDueForDisbursement(fromDate, dueDate)) {
&& this.outstandingLoanPrincipalBalance.compareTo(BigDecimal.ZERO) == 1) {
if (!excludePastUndisbursed if (!excludePastUndisbursed
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) { || (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
principal = principal.add(data.amount()); principal = principal.add(data.amount());
@@ -695,8 +695,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<>(); final List<Long> existingReversedTransactionIds = new ArrayList<>();
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
CalendarInstance restCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency, ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, holidayDetailDTO); calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds, final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds,
existingReversedTransactionIds, currentUser); existingReversedTransactionIds, currentUser);
@@ -1409,8 +1415,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
WorkingDays workingDays = this.workingDaysRepository.findOne(); WorkingDays workingDays = this.workingDaysRepository.findOne();
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays); HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
CalendarInstance restCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
}
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency, ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
calculatedRepaymentsStartingFromDate, holidayDetailDTO); calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
createLoanScheduleArchive(loan, scheduleGeneratorDTO); createLoanScheduleArchive(loan, scheduleGeneratorDTO);
} }
@@ -42,4 +42,9 @@ public enum InterestCalculationPeriodMethod {
} }
return repaymentMethod; return repaymentMethod;
} }
public boolean isDaily() {
return this.value.equals(InterestCalculationPeriodMethod.DAILY.getValue());
}
} }
@@ -57,4 +57,13 @@ public enum InterestRecalculationCompoundingMethod {
return this.getValue().equals(InterestRecalculationCompoundingMethod.FEE.getValue()) return this.getValue().equals(InterestRecalculationCompoundingMethod.FEE.getValue())
|| this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST_AND_FEE.getValue()); || this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST_AND_FEE.getValue());
} }
public boolean isCompoundingEnabled() {
return !this.getValue().equals(InterestRecalculationCompoundingMethod.NONE.getValue());
}
public boolean isInterestCompoundingEnabled() {
return this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST.getValue())
|| this.getValue().equals(InterestRecalculationCompoundingMethod.INTEREST_AND_FEE.getValue());
}
} }