interest recalculation performance issue fixes
This commit is contained in:
+29
-18
@@ -3389,18 +3389,20 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2517.24", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanFutureRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
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, "2517.24", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues, 0);
|
||||
|
||||
@@ -3495,9 +3497,10 @@ public class ClientLoanIntegrationTest {
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2505.73", "23.18", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "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);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3513,9 +3516,10 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2505.71", "23.2", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.28", "11.63", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.57", "46.34", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.49", "31.42", "200", "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);
|
||||
|
||||
@@ -3529,9 +3533,10 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2505.73", "23.18", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "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);
|
||||
|
||||
Float earlyPayment = new Float("5100");
|
||||
@@ -3544,9 +3549,10 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "0", "11.16", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2417.24", "11.16", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "5057.13", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "0", "19.55", "200", "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);
|
||||
|
||||
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);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
|
||||
|
||||
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, "2517.13", "11.78", "0.0", "0.0");
|
||||
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "35.24", "0.16", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
String JobName = "Apply penalty to overdue loans";
|
||||
@@ -3813,9 +3822,10 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2517.24", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
@@ -3889,9 +3899,10 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance();
|
||||
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, "2517.24", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "11.79", "0.05", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
|
||||
+3
-2
@@ -22,12 +22,13 @@ public class ScheduleGeneratorDTO {
|
||||
LocalDate lastTransactionDate;
|
||||
|
||||
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.applicationCurrency = applicationCurrency;
|
||||
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
||||
this.calendarInstanceForInterestRecalculation = null;
|
||||
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
||||
this.recalculateFrom = null;
|
||||
this.overdurPenaltyWaitPeriod = null;
|
||||
this.lastTransactionDate = null;
|
||||
|
||||
+60
-29
@@ -102,6 +102,7 @@ import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
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.LoanProductRelatedDetail;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||
@@ -2363,12 +2364,23 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
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(),
|
||||
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
|
||||
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
|
||||
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(),
|
||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||
@@ -4300,17 +4312,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final Set<LoanInstallmentCharge> loanChargePerInstallments = new HashSet<>();
|
||||
if (loanCharge.isInstalmentFee()) {
|
||||
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||
if (!installment.isRecalculatedInterestComponent()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isFlat()) {
|
||||
amount = loanCharge.amount().divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments()));
|
||||
} else {
|
||||
amount = calculateInstallmentChargeAmount(loanCharge.getChargeCalculation(), loanCharge.getPercentage(),
|
||||
installment).getAmount();
|
||||
}
|
||||
final LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
|
||||
loanChargePerInstallments.add(loanInstallmentCharge);
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isFlat()) {
|
||||
amount = loanCharge.amount().divide(BigDecimal.valueOf(repaymentScheduleDetail().getNumberOfRepayments()));
|
||||
} else {
|
||||
amount = calculateInstallmentChargeAmount(loanCharge.getChargeCalculation(), loanCharge.getPercentage(), installment)
|
||||
.getAmount();
|
||||
}
|
||||
final LoanInstallmentCharge loanInstallmentCharge = new LoanInstallmentCharge(amount, loanCharge, installment);
|
||||
loanChargePerInstallments.add(loanInstallmentCharge);
|
||||
}
|
||||
}
|
||||
return loanChargePerInstallments;
|
||||
@@ -4636,17 +4646,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (loanSchedule == null) { return; }
|
||||
updateLoanSchedule(loanSchedule, currentUser);
|
||||
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();
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -4682,8 +4692,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(),
|
||||
generatorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
|
||||
loanRepaymentScheduleTransactionProcessor, this.repaymentScheduleInstallments, generatorDTO.getRecalculateFrom(),
|
||||
generatorDTO.getLastTransactionDate(), generatorDTO.getPenaltyWaitPeriod());
|
||||
loanRepaymentScheduleTransactionProcessor, generatorDTO.getLastTransactionDate());
|
||||
return loanSchedule;
|
||||
}
|
||||
|
||||
@@ -4723,7 +4732,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory) {
|
||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||
CalendarInstance restCalendarInstance, HolidayDetailDTO holidayDetailDTO) {
|
||||
LoanRepaymentScheduleInstallment installment = null;
|
||||
|
||||
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
||||
@@ -4759,14 +4769,23 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
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,
|
||||
loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null,
|
||||
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
|
||||
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(),
|
||||
LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges());
|
||||
DateUtils.getLocalDateOfTenant(), loanApplicationTerms, mc, charges(), holidayDetailDTO);
|
||||
} else {
|
||||
installment = this.getTotalOutstandingOnLoan();
|
||||
}
|
||||
@@ -4903,12 +4922,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param restCalendarInstance
|
||||
* TODO
|
||||
* @param loan
|
||||
* the Loan object
|
||||
* @return application terms of the Loan object
|
||||
**/
|
||||
@SuppressWarnings({ "unused" })
|
||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency) {
|
||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||
final CalendarInstance restCalendarInstance) {
|
||||
LoanProduct loanProduct = loanProduct();
|
||||
// LoanProductRelatedDetail loanProductRelatedDetail =
|
||||
// getLoanRepaymentScheduleDetail();
|
||||
@@ -4961,11 +4983,20 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
|
||||
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,
|
||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
||||
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
||||
this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf());
|
||||
this.loanProduct.getPrincipalThresholdForLastInstalment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-2
@@ -546,9 +546,13 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||
allowTransactionsOnNonWorkingDay);
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
}
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
|
||||
return scheduleGeneratorDTO;
|
||||
}
|
||||
|
||||
+6
-6
@@ -33,20 +33,20 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
for (final LoanRepaymentScheduleInstallment period : repaymentPeriods) {
|
||||
|
||||
final Money feeChargesDueForRepaymentPeriod = cumulativeFeeChargesDueWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, !period.isRecalculatedInterestComponent(),
|
||||
currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, true,
|
||||
lastTransactionDate);
|
||||
final Money feeChargesWaivedForRepaymentPeriod = cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, !period.isRecalculatedInterestComponent());
|
||||
currency, true);
|
||||
final Money feeChargesWrittenOffForRepaymentPeriod = cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, !period.isRecalculatedInterestComponent());
|
||||
loanCharges, currency, true);
|
||||
|
||||
final Money penaltyChargesDueForRepaymentPeriod = cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest,
|
||||
!period.isRecalculatedInterestComponent(), lastTransactionDate);
|
||||
true, lastTransactionDate);
|
||||
final Money penaltyChargesWaivedForRepaymentPeriod = cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, !period.isRecalculatedInterestComponent());
|
||||
loanCharges, currency, true);
|
||||
final Money penaltyChargesWrittenOffForRepaymentPeriod = cumulativePenaltyChargesWrittenOffWithin(startDate,
|
||||
period.getDueDate(), loanCharges, currency, !period.isRecalculatedInterestComponent());
|
||||
period.getDueDate(), loanCharges, currency, true);
|
||||
|
||||
period.updateChargePortion(feeChargesDueForRepaymentPeriod, feeChargesWaivedForRepaymentPeriod,
|
||||
feeChargesWrittenOffForRepaymentPeriod, penaltyChargesDueForRepaymentPeriod, penaltyChargesWaivedForRepaymentPeriod,
|
||||
|
||||
+118
-190
@@ -11,7 +11,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.RecalculationDetail;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link LoanRepaymentScheduleTransactionProcessor}
|
||||
@@ -140,16 +138,17 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
|
||||
for (final LoanTransaction loanTransaction : transactionstoBeProcessed) {
|
||||
|
||||
if(!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) {
|
||||
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
|
||||
@Override
|
||||
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
|
||||
return ord1.getDueDate().compareTo(ord2.getDueDate());
|
||||
}
|
||||
};
|
||||
Collections.sort(installments,byDate);
|
||||
}
|
||||
|
||||
if (!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) {
|
||||
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
|
||||
|
||||
@Override
|
||||
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
|
||||
return ord1.getDueDate().compareTo(ord2.getDueDate());
|
||||
}
|
||||
};
|
||||
Collections.sort(installments, byDate);
|
||||
}
|
||||
|
||||
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
// pass through for new transactions
|
||||
@@ -183,12 +182,11 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
} else if (loanTransaction.isWriteOff()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
handleWriteOff(loanTransaction, currency, installments);
|
||||
}
|
||||
else if(loanTransaction.isRefundForActiveLoan()) {
|
||||
} else if (loanTransaction.isRefundForActiveLoan()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
|
||||
handleRefund(loanTransaction, currency, installments,charges);
|
||||
}
|
||||
|
||||
handleRefund(loanTransaction, currency, installments, charges);
|
||||
}
|
||||
}
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
@@ -470,47 +468,18 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecalculationDetail> handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement,
|
||||
final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments,
|
||||
final LoanRepaymentScheduleInstallment installment, final Map<LocalDate, LocalDate> recalculationDates,
|
||||
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;
|
||||
}
|
||||
}
|
||||
public Money handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
Money unProcessed = Money.zero(currency);
|
||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
Money amountToProcess = null;
|
||||
LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
if (loanTransaction != preCloseTransaction) {
|
||||
transactionDate = recalculationDates.get(transactionDate);
|
||||
}
|
||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||
if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) {
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
|
||||
}
|
||||
return earlypaymentDetail;
|
||||
return unProcessed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -519,114 +488,85 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTransaction(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments) {
|
||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
Money amountToProcess = null;
|
||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
processTransaction(newLoanTransaction, currency, installments, amountToProcess);
|
||||
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
|
||||
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
|
||||
public int compare(LoanRepaymentScheduleInstallment ord1,
|
||||
LoanRepaymentScheduleInstallment ord2) {
|
||||
return ord1.getDueDate().compareTo(ord2.getDueDate());
|
||||
}
|
||||
};
|
||||
Collections.sort(installments, Collections.reverseOrder(byDate));
|
||||
Money transactionAmountUnprocessed = loanTransaction
|
||||
.getAmount(currency);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
Money outstanding = currentInstallment
|
||||
.getTotalOutstanding(currency);
|
||||
Money due = currentInstallment.getDue(currency);
|
||||
private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
|
||||
final Integer installmentNumber) {
|
||||
|
||||
if (outstanding.isLessThan(due)) {
|
||||
transactionAmountUnprocessed = handleRefundTransactionPaymentOfInstallment(
|
||||
currentInstallment, loanTransaction,
|
||||
transactionAmountUnprocessed);
|
||||
Money amountRemaining = feeCharges;
|
||||
while (amountRemaining.isGreaterThanZero()) {
|
||||
final LoanCharge paidCharge = findLatestPaidChargeFromUnOrderedSet(charges, feeCharges.getCurrency());
|
||||
|
||||
}
|
||||
if (paidCharge != null) {
|
||||
Money feeAmount = feeCharges.zero();
|
||||
|
||||
if (transactionAmountUnprocessed.isZero())
|
||||
break;
|
||||
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);
|
||||
|
||||
final Set<LoanCharge> loanFees = extractFeeCharges(charges);
|
||||
final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges);
|
||||
Integer installmentNumber = null;
|
||||
amountRemaining = amountRemaining.minus(amountDeductedTowardsCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
public ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(final LocalDate disbursementDate,
|
||||
@@ -636,48 +576,36 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, recalculateChargesFrom,
|
||||
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
-13
@@ -6,16 +6,15 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
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.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.RecalculationDetail;
|
||||
|
||||
public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
@@ -29,9 +28,8 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||
|
||||
List<RecalculationDetail> handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentInstallment,
|
||||
Map<LocalDate, LocalDate> recalculationDates, LoanTransaction preCloseTransaction);
|
||||
Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments);
|
||||
|
||||
/**
|
||||
* Used in interest recalculation to introduce new interest only
|
||||
@@ -39,16 +37,11 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
*/
|
||||
boolean isInterestFirstRepaymentScheduleTransactionProcessor();
|
||||
|
||||
void applyTransaction(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments);
|
||||
|
||||
ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(LocalDate disbursementDate,
|
||||
List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, LocalDate recalculateChargesFrom);
|
||||
|
||||
void handleRefund(LoanTransaction loanTransaction,
|
||||
MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments,
|
||||
final Set<LoanCharge> charges);
|
||||
|
||||
void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
||||
final Set<LoanCharge> charges);
|
||||
|
||||
}
|
||||
+1
-1
@@ -110,7 +110,7 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
|
||||
final Money principalPortion = Money.zero(currency);
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, Money.zero(currency), Money.zero(currency));
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion,penaltyChargesPortion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+841
-1117
File diff suppressed because it is too large
Load Diff
+43
-6
@@ -6,7 +6,10 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
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.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
|
||||
@@ -42,14 +45,48 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
|
||||
@SuppressWarnings("unused") final Money totalCumulativeInterest,
|
||||
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int periodNumber, final MathContext mc) {
|
||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, 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,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestPaymentDueToGrace,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance);
|
||||
|
||||
final Money interestForThisInstallment = result.interest();
|
||||
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));
|
||||
}
|
||||
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc);
|
||||
|
||||
+7
-3
@@ -6,7 +6,10 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
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;
|
||||
|
||||
public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGenerator {
|
||||
@@ -15,9 +18,10 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
|
||||
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final PaymentPeriodsInOneYearCalculator calculator,
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
|
||||
final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final int daysInPeriodApplicableForInterest, final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms,
|
||||
final int periodNumber, final MathContext mc) {
|
||||
|
||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, 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,
|
||||
daysInPeriodApplicableForInterest, outstandingBalance, periodNumber, mc);
|
||||
|
||||
|
||||
+10
-8
@@ -150,12 +150,11 @@ public final class LoanApplicationTerms {
|
||||
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final Integer graceOnArrearsAgeing,
|
||||
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 InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||
final CalendarInstance restCalendarInstance = null;
|
||||
final RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
|
||||
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
|
||||
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney,
|
||||
@@ -173,7 +172,9 @@ public final class LoanApplicationTerms {
|
||||
final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
|
||||
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
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 repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -197,9 +198,6 @@ public final class LoanApplicationTerms {
|
||||
final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType();
|
||||
final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled();
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||
final CalendarInstance restCalendarInstance = null;
|
||||
final RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
|
||||
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod,
|
||||
@@ -208,7 +206,7 @@ public final class LoanApplicationTerms {
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance,
|
||||
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
|
||||
}
|
||||
|
||||
@@ -1170,4 +1168,8 @@ public final class LoanApplicationTerms {
|
||||
public ApplicationCurrency getApplicationCurrency() {
|
||||
return this.currency;
|
||||
}
|
||||
|
||||
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
|
||||
return this.interestCalculationPeriodMethod;
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -12,6 +12,7 @@ import java.util.Set;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
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.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
@@ -28,13 +29,12 @@ public interface LoanScheduleGenerator {
|
||||
LoanScheduleModel rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
|
||||
final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions,
|
||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom, LocalDate lastTransactionDate,
|
||||
int penaltyWaitPeriod);
|
||||
LocalDate lastTransactionDate);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, LocalDate onDate, LocalDate interestChargedFromLocalDate, LoanApplicationTerms loanApplicationTerms,
|
||||
MathContext mc, Set<LoanCharge> charges);
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, MathContext mc,
|
||||
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO);
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
|
||||
}
|
||||
+5
@@ -99,4 +99,9 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPrincipalAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+3
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
|
||||
public interface LoanScheduleModelPeriod {
|
||||
@@ -33,4 +34,6 @@ public interface LoanScheduleModelPeriod {
|
||||
void addLoanCharges(BigDecimal feeCharge, BigDecimal penaltyCharge);
|
||||
|
||||
boolean isRecalculatedInterestComponent();
|
||||
|
||||
void addPrincipalAmount(Money principalDue);
|
||||
}
|
||||
|
||||
+7
-1
@@ -20,7 +20,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
private final int periodNumber;
|
||||
private final LocalDate fromDate;
|
||||
private final LocalDate dueDate;
|
||||
private final Money principalDue;
|
||||
private Money principalDue;
|
||||
private final Money outstandingLoanBalance;
|
||||
private final Money interestDue;
|
||||
private Money feeChargesDue;
|
||||
@@ -124,6 +124,12 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
this.penaltyChargesDue = this.penaltyChargesDue.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
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
|
||||
+15
-38
@@ -6,55 +6,32 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public class RecalculationDetail {
|
||||
|
||||
private boolean isLatePayment;
|
||||
private boolean isInterestompound;
|
||||
private LocalDate startDate;
|
||||
private LocalDate toDate;
|
||||
private Money amount;
|
||||
private LocalDate transactionDate;
|
||||
private boolean isProcessed;
|
||||
private LoanTransaction transaction;
|
||||
|
||||
public RecalculationDetail(final boolean isLatePayment, final LocalDate startDate, final LocalDate toDate, final Money amount,
|
||||
final boolean isInterestompound) {
|
||||
this.isLatePayment = isLatePayment;
|
||||
this.startDate = startDate;
|
||||
this.toDate = toDate;
|
||||
this.amount = amount;
|
||||
this.isInterestompound = isInterestompound;
|
||||
public RecalculationDetail(final LocalDate transactionDate, final LoanTransaction transaction) {
|
||||
this.transactionDate = transactionDate;
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
public boolean isLatePayment() {
|
||||
return this.isLatePayment;
|
||||
public LocalDate getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public LocalDate getStartDate() {
|
||||
return this.startDate;
|
||||
public LoanTransaction getTransaction() {
|
||||
return this.transaction;
|
||||
}
|
||||
|
||||
public LocalDate getToDate() {
|
||||
return this.toDate;
|
||||
public boolean isProcessed() {
|
||||
return this.isProcessed;
|
||||
}
|
||||
|
||||
public Money getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
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;
|
||||
public void setProcessed(boolean isProcessed) {
|
||||
this.isProcessed = isProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
+59
-14
@@ -30,7 +30,11 @@ import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWr
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
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.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.MeetingFrequencyMismatchException;
|
||||
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.LoanProductRelatedDetail;
|
||||
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.service.LoanEnumerations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -249,9 +254,24 @@ public class LoanScheduleAssembler {
|
||||
final DaysInYearType daysInYearType = loanProduct.fetchDaysInYearType();
|
||||
|
||||
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 Integer installmentAmountInMultiplesOf= loanProduct.getInstallmentAmountInMultiplesOf();
|
||||
final Integer installmentAmountInMultiplesOf = loanProduct.getInstallmentAmountInMultiplesOf();
|
||||
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||
@@ -259,8 +279,33 @@ public class LoanScheduleAssembler {
|
||||
principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
|
||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, principalThresholdForLastInstalment,
|
||||
installmentAmountInMultiplesOf);
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
||||
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) {
|
||||
@@ -387,8 +432,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
|
||||
final List<LoanRepaymentScheduleInstallment> previousSchedule,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, LocalDate recalculateFrom,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate recalculateDueDateChargesFrom) {
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
@@ -400,24 +444,25 @@ public class LoanScheduleAssembler {
|
||||
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
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,
|
||||
loanRepaymentScheduleTransactionProcessor, previousSchedule, recalculateFrom, recalculateDueDateChargesFrom,
|
||||
penaltyWaitPeriod);
|
||||
loanRepaymentScheduleTransactionProcessor, recalculateDueDateChargesFrom);
|
||||
}
|
||||
|
||||
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 RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
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,
|
||||
loanApplicationTerms.getInterestChargedFromLocalDate(), loanApplicationTerms, mc, loanCharges);
|
||||
loanApplicationTerms, mc, loanCharges, holidayDetailDTO);
|
||||
}
|
||||
|
||||
private void validateDisbursementDateIsOnNonWorkingDay(final LocalDate disbursementDate, final WorkingDays workingDays) {
|
||||
|
||||
+3
-3
@@ -164,7 +164,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.charges());
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.charges(),
|
||||
loan.getOfficeId());
|
||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
Money interestDue = Money.zero(currency);
|
||||
@@ -185,8 +186,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
}
|
||||
|
||||
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
|
||||
modifiedTransactions, loan.charges(), loan.fetchRepaymentScheduleInstallments(), loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate.now(), LocalDate.now());
|
||||
modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, LocalDate.now());
|
||||
LoanScheduleData scheduleDate = model.toData();
|
||||
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
|
||||
for (LoanSchedulePeriodData periodData : periodDatas) {
|
||||
|
||||
+4
-3
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
|
||||
import java.math.MathContext;
|
||||
|
||||
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.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
|
||||
@@ -18,19 +19,19 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
|
||||
@Override
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||
final HolidayDetailDTO holidayDetailDTO) {
|
||||
final HolidayDetailDTO holidayDetailDTO,final CalendarInstance restCalendarInstance) {
|
||||
|
||||
LoanRescheduleModel loanRescheduleModel = null;
|
||||
|
||||
switch (interestMethod) {
|
||||
case DECLINING_BALANCE:
|
||||
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||
applicationCurrency, holidayDetailDTO);
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
break;
|
||||
|
||||
case FLAT:
|
||||
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||
applicationCurrency, holidayDetailDTO);
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
break;
|
||||
|
||||
case INVALID:
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
|
||||
import java.math.MathContext;
|
||||
|
||||
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.loanproduct.domain.InterestMethod;
|
||||
|
||||
@@ -15,5 +16,5 @@ public interface LoanReschedulerFactory {
|
||||
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||
final HolidayDetailDTO holidayDetailDTO);
|
||||
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
|
||||
}
|
||||
|
||||
+14
-2
@@ -18,6 +18,9 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
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.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
|
||||
@@ -41,19 +44,22 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
|
||||
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) {
|
||||
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
|
||||
final CalendarInstanceRepository calendarInstanceRepository) {
|
||||
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,8 +84,14 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
||||
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
|
||||
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||
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,
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO);
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
|
||||
oldPeriods);
|
||||
return loanRescheduleModelWithOldPeriods;
|
||||
|
||||
+6
-1
@@ -321,8 +321,13 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||
|
||||
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,
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO);
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
|
||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
|
||||
+38
-7
@@ -24,6 +24,7 @@ import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
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.domain.JdbcSupport;
|
||||
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.SearchParameters;
|
||||
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.domain.ApplicationCurrency;
|
||||
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.staff.data.StaffData;
|
||||
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.accountdetails.domain.AccountType;
|
||||
import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
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.charge.data.ChargeData;
|
||||
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.service.GroupReadPlatformService;
|
||||
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.LoanApplicationTimelineData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanApprovalData;
|
||||
@@ -125,6 +134,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
|
||||
private final LoanScheduleGeneratorFactory loanScheduleFactory;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
|
||||
@@ -135,7 +148,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final FundReadPlatformService fundReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService,
|
||||
final CodeValueReadPlatformService codeValueReadPlatformService, final RoutingDataSource dataSource,
|
||||
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.loanRepository = loanRepository;
|
||||
this.loanTransactionRepository = loanTransactionRepository;
|
||||
@@ -152,6 +167,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||||
this.loanScheduleFactory = loanScheduleFactory;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -391,7 +410,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
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 Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
|
||||
@@ -838,8 +870,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
|
||||
graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
|
||||
syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount,
|
||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
|
||||
fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,7 +939,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||
this.lastDueDate = this.disbursement.disbursementDate();
|
||||
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
||||
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
||||
this.disbursementData = disbursementData;
|
||||
this.excludePastUndisbursed = isInterestRecalculationEnabled;
|
||||
}
|
||||
@@ -981,8 +1013,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
|
||||
periods.add(periodData);
|
||||
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||
} else if (data.isDueForDisbursement(fromDate, dueDate)
|
||||
&& this.outstandingLoanPrincipalBalance.compareTo(BigDecimal.ZERO) == 1) {
|
||||
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
||||
if (!excludePastUndisbursed
|
||||
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
||||
principal = principal.add(data.amount());
|
||||
|
||||
+14
-2
@@ -695,8 +695,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
|
||||
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,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
|
||||
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds,
|
||||
existingReversedTransactionIds, currentUser);
|
||||
@@ -1409,8 +1415,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||
|
||||
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,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -42,4 +42,9 @@ public enum InterestCalculationPeriodMethod {
|
||||
}
|
||||
return repaymentMethod;
|
||||
}
|
||||
|
||||
public boolean isDaily() {
|
||||
return this.value.equals(InterestCalculationPeriodMethod.DAILY.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -57,4 +57,13 @@ public enum InterestRecalculationCompoundingMethod {
|
||||
return this.getValue().equals(InterestRecalculationCompoundingMethod.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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user