MIFOSX-1541 : corrected prepayment and interest calculation on date change
This commit is contained in:
+18
-13
@@ -1820,24 +1820,11 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
validateDisbursementDateIsOnNonWorkingDay(workingDays, allowTransactionsOnNonWorkingDay);
|
validateDisbursementDateIsOnNonWorkingDay(workingDays, allowTransactionsOnNonWorkingDay);
|
||||||
validateDisbursementDateIsOnHoliday(allowTransactionsOnHoliday, holidays);
|
validateDisbursementDateIsOnHoliday(allowTransactionsOnHoliday, holidays);
|
||||||
|
|
||||||
BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
|
||||||
boolean isEmiAmountChanged = false;
|
|
||||||
if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
|
|
||||||
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
|
|
||||||
actualDisbursementDate.toDate(), emiAmount, this);
|
|
||||||
this.loanTermVariations.add(loanVariationTerms);
|
|
||||||
isEmiAmountChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
|
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
|
||||||
LocalDate recalculateFrom = null;
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
} else if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule
|
|
||||||
|| isEmiAmountChanged) {
|
|
||||||
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
|
||||||
workingDays);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
@@ -1863,6 +1850,24 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void regenerateScheduleOnDisbursement(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
|
final ApplicationCurrency currency, final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled,
|
||||||
|
final List<Holiday> holidays, final WorkingDays workingDays, final boolean recalculateSchedule,
|
||||||
|
final LocalDate actualDisbursementDate, BigDecimal emiAmount) {
|
||||||
|
boolean isEmiAmountChanged = false;
|
||||||
|
if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) {
|
||||||
|
LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(),
|
||||||
|
actualDisbursementDate.toDate(), emiAmount, this);
|
||||||
|
this.loanTermVariations.add(loanVariationTerms);
|
||||||
|
isEmiAmountChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged) {
|
||||||
|
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canDisburse(final LocalDate actualDisbursementDate) {
|
public boolean canDisburse(final LocalDate actualDisbursementDate) {
|
||||||
Date lastDusburseDate = this.actualDisbursementDate;
|
Date lastDusburseDate = this.actualDisbursementDate;
|
||||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
||||||
|
|||||||
+2
-2
@@ -156,7 +156,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
|||||||
}
|
}
|
||||||
int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays();
|
int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays();
|
||||||
// if (daysToBeAccrued < 1) { return; }
|
// if (daysToBeAccrued < 1) { return; }
|
||||||
int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
|
// int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays();
|
||||||
/*
|
/*
|
||||||
* switch (accrualData.getRepaymentFrequency()) { case MONTHS: int
|
* switch (accrualData.getRepaymentFrequency()) { case MONTHS: int
|
||||||
* numberOfDaysInMonth =
|
* numberOfDaysInMonth =
|
||||||
@@ -175,7 +175,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
|||||||
BigDecimal interestportion = null;
|
BigDecimal interestportion = null;
|
||||||
BigDecimal feeportion = accrualData.getDueDateFeeIncome();
|
BigDecimal feeportion = accrualData.getDueDateFeeIncome();
|
||||||
BigDecimal penaltyportion = accrualData.getDueDatePenaltyIncome();
|
BigDecimal penaltyportion = accrualData.getDueDatePenaltyIncome();
|
||||||
if (daysInSchedule >= totalNumberOfDays) {
|
if (daysToBeAccrued >= totalNumberOfDays) {
|
||||||
interestportion = accrualData.getInterestIncome();
|
interestportion = accrualData.getInterestIncome();
|
||||||
} else {
|
} else {
|
||||||
double iterest = interestPerDay * daysToBeAccrued;
|
double iterest = interestPerDay * daysToBeAccrued;
|
||||||
|
|||||||
+27
-13
@@ -83,6 +83,7 @@ import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentComman
|
|||||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||||
@@ -280,7 +281,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
ChangedTransactionDetail changedTransactionDetail = null;
|
ChangedTransactionDetail changedTransactionDetail = null;
|
||||||
if (canDisburse) {
|
if (canDisburse) {
|
||||||
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
||||||
boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
boolean recalculateSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
||||||
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
||||||
if (isAccountTransfer) {
|
if (isAccountTransfer) {
|
||||||
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
|
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
|
||||||
@@ -301,9 +302,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regenerateScheduleOnDisbursement(command, loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays, recalculateSchedule);
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
|
||||||
|
loan, null);
|
||||||
|
}
|
||||||
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
|
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
|
||||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||||
allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
|
allowTransactionsOnNonWorkingDay, recalculateSchedule, restCalendarInstance);
|
||||||
}
|
}
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
|
||||||
@@ -322,10 +329,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
|
||||||
createLoanScheduleArchive(loan, applicationCurrency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
|
||||||
workingDays);
|
|
||||||
}
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -476,7 +480,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (canDisburse) {
|
if (canDisburse) {
|
||||||
Money amountBeforeAdjust = loan.getPrincpal();
|
Money amountBeforeAdjust = loan.getPrincpal();
|
||||||
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
Money disburseAmount = loan.adjustDisburseAmount(command, actualDisbursementDate);
|
||||||
boolean recalcualteSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
boolean recalculateSchedule = amountBeforeAdjust.isNotEqualTo(loan.getPrincpal());
|
||||||
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
|
||||||
if (isAccountTransfer) {
|
if (isAccountTransfer) {
|
||||||
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
|
disburseLoanToSavings(loan, command, disburseAmount, paymentDetail);
|
||||||
@@ -496,10 +500,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||||
}
|
}
|
||||||
|
regenerateScheduleOnDisbursement(command, loan, applicationCurrency, firstRepaymentOnDate, isHolidayEnabled, holidays,
|
||||||
|
workingDays, recalculateSchedule);
|
||||||
|
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
|
||||||
|
loan, null);
|
||||||
|
}
|
||||||
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
|
changedTransactionDetail = loan.disburse(this.loanScheduleFactory, currentUser, command, applicationCurrency, changes,
|
||||||
firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||||
allowTransactionsOnNonWorkingDay, recalcualteSchedule, restCalendarInstance);
|
allowTransactionsOnNonWorkingDay, recalculateSchedule, restCalendarInstance);
|
||||||
}
|
}
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
|
|
||||||
@@ -518,10 +527,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
|
||||||
createLoanScheduleArchive(loan, applicationCurrency, firstRepaymentOnDate, isHolidayEnabled, holidays, workingDays);
|
|
||||||
}
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
}
|
}
|
||||||
final Set<LoanCharge> loanCharges = loan.charges();
|
final Set<LoanCharge> loanCharges = loan.charges();
|
||||||
@@ -2315,6 +2320,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void regenerateScheduleOnDisbursement(final JsonCommand command, final Loan loan, final ApplicationCurrency applicationCurrency,
|
||||||
|
final LocalDate calculatedRepaymentsStartingFromDate, final boolean isHolidayEnabled, final List<Holiday> holidays,
|
||||||
|
final WorkingDays workingDays, final boolean recalculateSchedule) {
|
||||||
|
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||||
|
BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
||||||
|
loan.regenerateScheduleOnDisbursement(loanScheduleFactory, applicationCurrency, calculatedRepaymentsStartingFromDate,
|
||||||
|
isHolidayEnabled, holidays, workingDays, recalculateSchedule, actualDisbursementDate, emiAmount);
|
||||||
|
}
|
||||||
|
|
||||||
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
|
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
|
||||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
|
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user