MIFOSX-1421 : fixed interest recalculation with RBI strategy
This commit is contained in:
+47
-13
@@ -1759,8 +1759,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
&& fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now())) {
|
&& fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now())) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
|
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
@@ -2295,6 +2296,11 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
LoanStatus statusEnum = null;
|
LoanStatus statusEnum = null;
|
||||||
|
|
||||||
|
LocalDate recalculateFrom = loanTransaction.getTransactionDate();
|
||||||
|
if (adjustedTransaction != null && adjustedTransaction.getTransactionDate().isBefore(recalculateFrom)) {
|
||||||
|
recalculateFrom = adjustedTransaction.getTransactionDate();
|
||||||
|
}
|
||||||
|
|
||||||
if (loanTransaction.isRecoveryRepayment()) {
|
if (loanTransaction.isRecoveryRepayment()) {
|
||||||
statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RECOVERY_PAYMENT, LoanStatus.fromInt(this.loanStatus));
|
statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RECOVERY_PAYMENT, LoanStatus.fromInt(this.loanStatus));
|
||||||
} else {
|
} else {
|
||||||
@@ -2382,7 +2388,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
if (reprocess) {
|
if (reprocess) {
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||||
@@ -2395,7 +2401,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
* of the transactions. for this need to save the reversed
|
* of the transactions. for this need to save the reversed
|
||||||
* transactions first and then new transactions.
|
* transactions first and then new transactions.
|
||||||
*/
|
*/
|
||||||
// this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
@@ -2408,6 +2414,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changedTransactionDetail != null) {
|
||||||
|
this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||||
|
}
|
||||||
return changedTransactionDetail;
|
return changedTransactionDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2434,6 +2443,18 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return repaymentsOrWaivers;
|
return repaymentsOrWaivers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursementExcludeAccruals() {
|
||||||
|
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||||
|
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||||
|
if (!transaction.isDisbursement() && transaction.isNotReversed() && !transaction.isAccrual()) {
|
||||||
|
repaymentsOrWaivers.add(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
|
||||||
|
Collections.sort(repaymentsOrWaivers, transactionComparator);
|
||||||
|
return repaymentsOrWaivers;
|
||||||
|
}
|
||||||
|
|
||||||
private void doPostLoanTransactionChecks(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
private void doPostLoanTransactionChecks(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
|
||||||
if (isOverPaid()) {
|
if (isOverPaid()) {
|
||||||
@@ -2651,8 +2672,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
.determineProcessor(this.transactionProcessingStrategy);
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
|
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
|
||||||
@@ -2797,8 +2819,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
regenerateRepaymentSchedule(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays,
|
||||||
workingDays);
|
workingDays);
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||||
@@ -3897,8 +3920,9 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
workingDays);
|
workingDays);
|
||||||
|
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
@@ -3976,17 +4000,24 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return maturityDate;
|
return maturityDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangedTransactionDetail recalculateSchedule(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
public ChangedTransactionDetail recalculateScheduleFromLastTransaction(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation, final List<Long> existingTransactionIds,
|
final CalendarInstance calendarInstanceForInterestRecalculation, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds) {
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
|
List<LoanTransaction> loanTransactions = this.retreiveListOfTransactionsPostDisbursementExcludeAccruals();
|
||||||
|
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||||
|
if (recalculateFrom == null || loanTransaction.getTransactionDate().isAfter(recalculateFrom)) {
|
||||||
|
recalculateFrom = loanTransaction.getTransactionDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, applicationCurrency,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation);
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays,
|
||||||
|
calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
}
|
}
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategy);
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
@@ -4002,10 +4033,11 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
* the transactions. for this need to save the reversed transactions
|
* the transactions. for this need to save the reversed transactions
|
||||||
* first and then new transactions.
|
* first and then new transactions.
|
||||||
*/
|
*/
|
||||||
// this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
|
|
||||||
|
this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||||
return changedTransactionDetail;
|
return changedTransactionDetail;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4013,7 +4045,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
private void regenerateRepaymentScheduleWithInterestRecalculation(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
private void regenerateRepaymentScheduleWithInterestRecalculation(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||||
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
final ApplicationCurrency applicationCurrency, final LocalDate calculatedRepaymentsStartingFromDate,
|
||||||
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
final CalendarInstance calendarInstanceForInterestRecalculation) {
|
final CalendarInstance calendarInstanceForInterestRecalculation, LocalDate recalculateFrom) {
|
||||||
|
|
||||||
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled() || isNpa) { return; }
|
if (!this.repaymentScheduleDetail().isInterestRecalculationEnabled() || isNpa) { return; }
|
||||||
|
|
||||||
@@ -4056,8 +4088,10 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
.determineProcessor(this.transactionProcessingStrategy);
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
|
|
||||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, applicationCurrency,
|
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, applicationCurrency,
|
||||||
loanApplicationTerms, charges(), isHolidayEnabled, holidays, workingDays, retreiveListOfTransactionsPostDisbursement(),
|
loanApplicationTerms, charges(), isHolidayEnabled, holidays, workingDays,
|
||||||
loanRepaymentScheduleTransactionProcessor);
|
retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
|
||||||
|
this.repaymentScheduleInstallments, recalculateFrom);
|
||||||
|
if (loanSchedule == null) { return; }
|
||||||
|
|
||||||
updateLoanSchedule(loanSchedule);
|
updateLoanSchedule(loanSchedule);
|
||||||
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
|
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
|
||||||
|
|||||||
+6
-17
@@ -104,11 +104,11 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
final List<LoanRepaymentScheduleInstallment> processInstallments = new ArrayList<>(1);
|
final List<LoanRepaymentScheduleInstallment> processInstallments = new ArrayList<>(1);
|
||||||
processInstallments.add(chargePaidDetail.getInstallment());
|
processInstallments.add(chargePaidDetail.getInstallment());
|
||||||
Money processAmt = chargePaidDetail.getAmount();
|
Money processAmt = chargePaidDetail.getAmount();
|
||||||
if(processAmt.isGreaterThan(unprocessed)){
|
if (processAmt.isGreaterThan(unprocessed)) {
|
||||||
processAmt = unprocessed;
|
processAmt = unprocessed;
|
||||||
}
|
}
|
||||||
unprocessed = handleTransactionAndCharges(loanTransaction, currency, processInstallments,
|
unprocessed = handleTransactionAndCharges(loanTransaction, currency, processInstallments, transferCharges, processAmt,
|
||||||
transferCharges, processAmt, chargePaidDetail.isFeeCharge());
|
chargePaidDetail.isFeeCharge());
|
||||||
if (!unprocessed.isGreaterThanZero()) {
|
if (!unprocessed.isGreaterThanZero()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -437,19 +437,6 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
// empty implementation by default.
|
// empty implementation by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<LocalDate, Money> handleRecalculation(final LocalDate disbursementDate,
|
|
||||||
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentinstallment,
|
|
||||||
final Map<LocalDate, LocalDate> recalculationDates) {
|
|
||||||
|
|
||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
|
||||||
currentInstallment.resetDerivedComponents();
|
|
||||||
currentInstallment.updateDerivedFields(currency, disbursementDate);
|
|
||||||
}
|
|
||||||
return handleRepaymentSchedule(transactionsPostDisbursement, currency, installments, currentinstallment, recalculationDates);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<LocalDate, Money> handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement,
|
public Map<LocalDate, Money> handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement,
|
||||||
final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments,
|
final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> installments,
|
||||||
@@ -458,7 +445,9 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
Money currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
|
Money currentInstallmentOutstanding = installment.getTotalOutstanding(currency);
|
||||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||||
Money amountToProcess = null;
|
Money amountToProcess = null;
|
||||||
Money unProcessed = processTransaction(loanTransaction, currency, installments, amountToProcess);
|
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||||
|
newLoanTransaction.resetDerivedComponents();
|
||||||
|
Money unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
|
||||||
if (loanTransaction.getTransactionDate().isAfter(installment.getFromDate())
|
if (loanTransaction.getTransactionDate().isAfter(installment.getFromDate())
|
||||||
&& recalculationDates.get(loanTransaction.getTransactionDate()).isBefore(installment.getDueDate())) {
|
&& recalculationDates.get(loanTransaction.getTransactionDate()).isBefore(installment.getDueDate())) {
|
||||||
Money earlyPayment = currentInstallmentOutstanding.minus(installment.getTotalOutstanding(currency));
|
Money earlyPayment = currentInstallmentOutstanding.minus(installment.getTotalOutstanding(currency));
|
||||||
|
|||||||
+2
-4
@@ -28,10 +28,8 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
|||||||
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||||
|
|
||||||
Map<LocalDate, Money> handleRecalculation(LocalDate disbursementDate, List<LoanTransaction> transactionsPostDisbursement,
|
|
||||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentinstallment, Map<LocalDate, LocalDate> recalculationDates);
|
|
||||||
|
|
||||||
Map<LocalDate, Money> handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
Map<LocalDate, Money> handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||||
List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentInstallment, Map<LocalDate, LocalDate> recalculationDates);
|
List<LoanRepaymentScheduleInstallment> installments, LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
Map<LocalDate, LocalDate> recalculationDates);
|
||||||
|
|
||||||
}
|
}
|
||||||
+132
-45
@@ -212,8 +212,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (diffAmt != null && !diffAmt.isEmpty()) {
|
if (diffAmt != null && !diffAmt.isEmpty()) {
|
||||||
Money interestDueToLatePayment = totalCumulativeInterest.zero();
|
BigDecimal interestDueToLatePayment = BigDecimal.ZERO;
|
||||||
Money interestReducedDueToEarlyPayment = totalCumulativeInterest.zero();
|
BigDecimal interestReducedDueToEarlyPayment = BigDecimal.ZERO;
|
||||||
for (RecalculationDetail detail : diffAmt) {
|
for (RecalculationDetail detail : diffAmt) {
|
||||||
if (!detail.isLatePayment() && detail.getStartDate().isAfter(periodStartDate)
|
if (!detail.isLatePayment() && detail.getStartDate().isAfter(periodStartDate)
|
||||||
&& !detail.getStartDate().isAfter(scheduledDueDate)) {
|
&& !detail.getStartDate().isAfter(scheduledDueDate)) {
|
||||||
@@ -231,7 +231,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interestReducedDueToEarlyPayment = interestReducedDueToEarlyPayment.plus(loanApplicationTerms.interestRateFor(
|
interestReducedDueToEarlyPayment = interestReducedDueToEarlyPayment.add(loanApplicationTerms.interestRateFor(
|
||||||
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), detail.getStartDate(), scheduledDueDate));
|
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), detail.getStartDate(), scheduledDueDate));
|
||||||
|
|
||||||
} else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
|
} else if (detail.isLatePayment() && detail.isOverlapping(periodStartDate, scheduledDueDate)
|
||||||
@@ -247,7 +247,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
if (toDate.isAfter(LocalDate.now())) {
|
if (toDate.isAfter(LocalDate.now())) {
|
||||||
toDate = LocalDate.now();
|
toDate = LocalDate.now();
|
||||||
}
|
}
|
||||||
interestDueToLatePayment = interestDueToLatePayment.plus(loanApplicationTerms.interestRateFor(
|
interestDueToLatePayment = interestDueToLatePayment.add(loanApplicationTerms.interestRateFor(
|
||||||
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), fromDate, toDate));
|
this.paymentPeriodsInOneYearCalculator, mc, detail.getAmount(), fromDate, toDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,17 +332,19 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
LocalDate fromDate = detail.getStartDate();
|
LocalDate fromDate = detail.getStartDate();
|
||||||
LocalDate toDate = detail.getToDate();
|
LocalDate toDate = detail.getToDate();
|
||||||
if (!toDate.isAfter(LocalDate.now())) {
|
if (!toDate.isAfter(LocalDate.now())) {
|
||||||
Money interestDueToLatePayment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
BigDecimal interestForLatePayment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
||||||
detail.getAmount(), fromDate, toDate);
|
detail.getAmount(), fromDate, toDate);
|
||||||
|
Money interestDueToLatePayment = Money.of(detail.getAmount().getCurrency(), interestForLatePayment);
|
||||||
|
if (interestDueToLatePayment.isGreaterThanZero()) {
|
||||||
|
totalInterestCharged = totalInterestCharged.add(interestDueToLatePayment.getAmount());
|
||||||
|
totalRepaymentExpected = totalRepaymentExpected.add(interestDueToLatePayment.getAmount());
|
||||||
|
|
||||||
totalInterestCharged = totalInterestCharged.add(interestDueToLatePayment.getAmount());
|
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate,
|
||||||
totalRepaymentExpected = totalRepaymentExpected.add(interestDueToLatePayment.getAmount());
|
toDate, interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment,
|
||||||
|
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment);
|
||||||
final LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(periodNumber, fromDate, toDate,
|
periods.add(installment);
|
||||||
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment,
|
periodNumber++;
|
||||||
interestDueToLatePayment.zero(), interestDueToLatePayment.zero(), interestDueToLatePayment);
|
}
|
||||||
periods.add(installment);
|
|
||||||
periodNumber++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,47 +522,95 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
public LoanScheduleModel rescheduleNextInstallments(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
public LoanScheduleModel rescheduleNextInstallments(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
||||||
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
||||||
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
|
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom) {
|
||||||
|
|
||||||
int installmentNumber = 0;
|
LoanScheduleModel loanScheduleModel = null;
|
||||||
final List<RecalculationDetail> recalculationDetails = new ArrayList<>();
|
List<LoanRepaymentScheduleInstallment> installments = previousSchedule;
|
||||||
LoanScheduleModel loanScheduleModel = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled,
|
List<LoanRepaymentScheduleInstallment> removeInstallments = new ArrayList<>();
|
||||||
holidays, workingDays);
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (!loanApplicationTerms.isPrincipalGraceApplicableForThisPeriod(installment.getInstallmentNumber())
|
||||||
|
&& installment.getPrincipal(loanApplicationTerms.getCurrency()).isZero()) {
|
||||||
|
removeInstallments.add(installment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
installments.removeAll(removeInstallments);
|
||||||
|
if (previousSchedule == null) {
|
||||||
|
loanScheduleModel = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays,
|
||||||
|
workingDays);
|
||||||
|
installments = retrieveRepaymentSchedule(loanScheduleModel);
|
||||||
|
}
|
||||||
|
if (recalculateFrom == null) {
|
||||||
|
recalculateFrom = loanApplicationTerms.getExpectedDisbursementDate();
|
||||||
|
}
|
||||||
|
while (!recalculateFrom.isAfter(LocalDate.now())) {
|
||||||
|
int installmentNumber = findLastProcessedInstallmentNumber(installments, recalculateFrom);
|
||||||
|
List<LoanTransaction> processTransactions = processTransactions(transactions, recalculateFrom);
|
||||||
|
loanScheduleModel = recalculateInstallment(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled,
|
||||||
|
holidays, workingDays, loanRepaymentScheduleTransactionProcessor, previousSchedule, loanScheduleModel, installments,
|
||||||
|
processTransactions, installmentNumber);
|
||||||
|
|
||||||
while (installmentNumber < loanScheduleModel.getPeriods().size() - 1) {
|
recalculateFrom = getNextRecalculateFromDate(transactions, recalculateFrom);
|
||||||
RecalculatedSchedule recalculatedSchedule = recalculateInterest(mc, applicationCurrency, loanApplicationTerms, loanCharges,
|
|
||||||
isHolidayEnabled, holidays, workingDays, transactions, loanRepaymentScheduleTransactionProcessor, installmentNumber,
|
|
||||||
loanScheduleModel, recalculationDetails);
|
|
||||||
installmentNumber = recalculatedSchedule.getInstallmentNumber();
|
|
||||||
loanScheduleModel = recalculatedSchedule.getLoanScheduleModel();
|
|
||||||
}
|
}
|
||||||
return loanScheduleModel;
|
return loanScheduleModel;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LocalDate getNextRecalculateFromDate(List<LoanTransaction> processTransactions, LocalDate preCalculationDate) {
|
||||||
|
LocalDate recalculateFrom = null;
|
||||||
|
for (LoanTransaction loanTransaction : processTransactions) {
|
||||||
|
if (preCalculationDate.isBefore(loanTransaction.getTransactionDate())
|
||||||
|
&& (recalculateFrom == null || recalculateFrom.isAfter(loanTransaction.getTransactionDate()))) {
|
||||||
|
recalculateFrom = loanTransaction.getTransactionDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (recalculateFrom == null) {
|
||||||
|
recalculateFrom = LocalDate.now().plusDays(1);
|
||||||
|
}
|
||||||
|
return recalculateFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanScheduleModel recalculateInstallment(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
||||||
|
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
||||||
|
final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> previousSchedule, LoanScheduleModel loanScheduleModel,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, List<LoanTransaction> processTransactions, final int skipRecalculation) {
|
||||||
|
int processInstallmentsFrom = 0;
|
||||||
|
Integer numberOfInstallments = previousSchedule.size() - 1;
|
||||||
|
final List<RecalculationDetail> recalculationDetails = new ArrayList<>();
|
||||||
|
while (processInstallmentsFrom < numberOfInstallments) {
|
||||||
|
RecalculatedSchedule recalculatedSchedule = recalculateInterest(mc, applicationCurrency, loanApplicationTerms, loanCharges,
|
||||||
|
isHolidayEnabled, holidays, workingDays, processTransactions, loanRepaymentScheduleTransactionProcessor,
|
||||||
|
processInstallmentsFrom, installments, recalculationDetails, skipRecalculation);
|
||||||
|
processInstallmentsFrom = recalculatedSchedule.getInstallmentNumber();
|
||||||
|
if (recalculatedSchedule.getLoanScheduleModel() != null) {
|
||||||
|
loanScheduleModel = recalculatedSchedule.getLoanScheduleModel();
|
||||||
|
installments = retrieveRepaymentSchedule(loanScheduleModel);
|
||||||
|
numberOfInstallments = installments.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loanScheduleModel;
|
||||||
|
}
|
||||||
|
|
||||||
private RecalculatedSchedule recalculateInterest(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
private RecalculatedSchedule recalculateInterest(final MathContext mc, final ApplicationCurrency applicationCurrency,
|
||||||
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
final LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final boolean isHolidayEnabled,
|
||||||
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
|
final List<Holiday> holidays, final WorkingDays workingDays, final List<LoanTransaction> transactions,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final int installmentNumber,
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final int installmentNumber,
|
||||||
LoanScheduleModel model, final List<RecalculationDetail> recalculationDetails) {
|
final List<LoanRepaymentScheduleInstallment> installments, final List<RecalculationDetail> recalculationDetails,
|
||||||
|
final int skipRecalculation) {
|
||||||
boolean processRecalculate = false;
|
boolean processRecalculate = false;
|
||||||
int processedInstallmentNumber = installmentNumber;
|
int processedInstallmentNumber = installmentNumber;
|
||||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
|
||||||
final List<RecalculationDetail> diffAmt = new ArrayList<>();
|
final List<RecalculationDetail> diffAmt = new ArrayList<>();
|
||||||
Money unpaidPricipal = loanApplicationTerms.getPrincipal();
|
Money unpaidPricipal = loanApplicationTerms.getPrincipal();
|
||||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
|
|
||||||
if (scheduledLoanInstallment.isRepaymentPeriod()) {
|
|
||||||
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(null,
|
|
||||||
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
|
||||||
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
|
||||||
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
|
||||||
scheduledLoanInstallment.penaltyChargesDue());
|
|
||||||
installments.add(installment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
|
MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
|
||||||
final List<LoanRepaymentScheduleInstallment> processinstallmets = new ArrayList<>();
|
final List<LoanRepaymentScheduleInstallment> processinstallmets = new ArrayList<>();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
installment.resetDerivedComponents();
|
||||||
|
installment.updateDerivedFields(currency, loanApplicationTerms.getExpectedDisbursementDate());
|
||||||
|
}
|
||||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
processinstallmets.add(installment);
|
processinstallmets.add(installment);
|
||||||
unpaidPricipal = unpaidPricipal.minus(installment.getPrincipal(currency));
|
unpaidPricipal = unpaidPricipal.minus(installment.getPrincipal(currency));
|
||||||
@@ -577,7 +627,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
isHolidayEnabled, holidays, workingDays);
|
isHolidayEnabled, holidays, workingDays);
|
||||||
for (LoanTransaction loanTransaction : transactions) {
|
for (LoanTransaction loanTransaction : transactions) {
|
||||||
LocalDate loantransactionDate = loanTransaction.getTransactionDate();
|
LocalDate loantransactionDate = loanTransaction.getTransactionDate();
|
||||||
if (!loantransactionDate.isAfter(transactionsDate) && !loanTransaction.isAccrual()) {
|
if (!loantransactionDate.isAfter(transactionsDate)) {
|
||||||
transactionsForInstallment.add(loanTransaction);
|
transactionsForInstallment.add(loanTransaction);
|
||||||
recalculationDates.put(
|
recalculationDates.put(
|
||||||
loantransactionDate,
|
loantransactionDate,
|
||||||
@@ -585,9 +635,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
workingDays));
|
workingDays));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map<LocalDate, Money> earlyPaymentMap = loanRepaymentScheduleTransactionProcessor.handleRecalculation(
|
Map<LocalDate, Money> earlyPaymentMap = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(
|
||||||
loanApplicationTerms.getExpectedDisbursementDate(), transactionsForInstallment, currency, processinstallmets,
|
transactionsForInstallment, currency, processinstallmets, installment, recalculationDates);
|
||||||
installment, recalculationDates);
|
|
||||||
|
|
||||||
for (Map.Entry<LocalDate, Money> entry : earlyPaymentMap.entrySet()) {
|
for (Map.Entry<LocalDate, Money> entry : earlyPaymentMap.entrySet()) {
|
||||||
LocalDate startDate = entry.getKey();
|
LocalDate startDate = entry.getKey();
|
||||||
@@ -645,20 +694,37 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!diffAmt.isEmpty()) {
|
if ((!diffAmt.isEmpty() && skipRecalculation <= installment.getInstallmentNumber())
|
||||||
|
|| installment.getInstallmentNumber() == installments.size() - 1) {
|
||||||
processRecalculate = true;
|
processRecalculate = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
LoanScheduleModel model = null;
|
||||||
|
recalculationDetails.addAll(diffAmt);
|
||||||
if (processRecalculate) {
|
if (processRecalculate) {
|
||||||
recalculationDetails.addAll(diffAmt);
|
|
||||||
model = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays,
|
model = generate(mc, applicationCurrency, loanApplicationTerms, loanCharges, isHolidayEnabled, holidays, workingDays,
|
||||||
recalculationDetails);
|
recalculationDetails);
|
||||||
}
|
}
|
||||||
return new RecalculatedSchedule(model, processedInstallmentNumber);
|
return new RecalculatedSchedule(model, processedInstallmentNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentSchedule(LoanScheduleModel model) {
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||||
|
for (final LoanScheduleModelPeriod scheduledLoanInstallment : model.getPeriods()) {
|
||||||
|
if (scheduledLoanInstallment.isRepaymentPeriod()) {
|
||||||
|
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(null,
|
||||||
|
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||||
|
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||||
|
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||||
|
scheduledLoanInstallment.penaltyChargesDue());
|
||||||
|
installments.add(installment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return installments;
|
||||||
|
}
|
||||||
|
|
||||||
private void applyRest(List<LoanTransaction> loanTransactions, LocalDate from, LocalDate to,
|
private void applyRest(List<LoanTransaction> loanTransactions, LocalDate from, LocalDate to,
|
||||||
LoanRepaymentScheduleInstallment installment,
|
LoanRepaymentScheduleInstallment installment,
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, MonetaryCurrency currency,
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, MonetaryCurrency currency,
|
||||||
@@ -668,7 +734,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
Map<LocalDate, LocalDate> recalculationDates = new HashMap<>();
|
Map<LocalDate, LocalDate> recalculationDates = new HashMap<>();
|
||||||
for (LoanTransaction transaction : loanTransactions) {
|
for (LoanTransaction transaction : loanTransactions) {
|
||||||
LocalDate loantransactionDate = transaction.getTransactionDate();
|
LocalDate loantransactionDate = transaction.getTransactionDate();
|
||||||
if (loantransactionDate.isAfter(from) && !transaction.getTransactionDate().isAfter(to) && !transaction.isAccrual()) {
|
if (loantransactionDate.isAfter(from) && !transaction.getTransactionDate().isAfter(to)) {
|
||||||
transactions.add(transaction);
|
transactions.add(transaction);
|
||||||
recalculationDates.put(
|
recalculationDates.put(
|
||||||
loantransactionDate,
|
loantransactionDate,
|
||||||
@@ -714,10 +780,31 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Money interest = applicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc, prepaymentAmount,
|
BigDecimal interest = applicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc, prepaymentAmount,
|
||||||
calculateInterestFrom, LocalDate.now());
|
calculateInterestFrom, LocalDate.now());
|
||||||
prepaymentAmount = prepaymentAmount.plus(interest).plus(amount);
|
prepaymentAmount = prepaymentAmount.plus(interest).plus(amount);
|
||||||
return prepaymentAmount;
|
return prepaymentAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Integer findLastProcessedInstallmentNumber(final List<LoanRepaymentScheduleInstallment> installments, LocalDate date) {
|
||||||
|
int installmentNumber = 0;
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||||
|
if (!installment.getDueDate().isAfter(date) && installmentNumber < installment.getInstallmentNumber()) {
|
||||||
|
installmentNumber = installment.getInstallmentNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return installmentNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LoanTransaction> processTransactions(final List<LoanTransaction> transactions, final LocalDate tillDate) {
|
||||||
|
List<LoanTransaction> toProcess = new ArrayList<>();
|
||||||
|
for (LoanTransaction loanTransaction : transactions) {
|
||||||
|
if (!loanTransaction.getTransactionDate().isAfter(tillDate)) {
|
||||||
|
toProcess.add(loanTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toProcess;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+11
-6
@@ -663,8 +663,8 @@ public final class LoanApplicationTerms {
|
|||||||
return periodicInterestRate;
|
return periodicInterestRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc, final Money outstandingBalance,
|
public BigDecimal interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc,
|
||||||
final LocalDate fromDate, final LocalDate toDate) {
|
final Money outstandingBalance, final LocalDate fromDate, final LocalDate toDate) {
|
||||||
|
|
||||||
long loanTermPeriodsInOneYear = calculator.calculate(PeriodFrequencyType.DAYS).longValue();
|
long loanTermPeriodsInOneYear = calculator.calculate(PeriodFrequencyType.DAYS).longValue();
|
||||||
int repaymentEvery = Days.daysBetween(fromDate, toDate).getDays();
|
int repaymentEvery = Days.daysBetween(fromDate, toDate).getDays();
|
||||||
@@ -678,7 +678,7 @@ public final class LoanApplicationTerms {
|
|||||||
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
|
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
|
||||||
divisor, mc);
|
divisor, mc);
|
||||||
BigDecimal interestRate = oneDayOfYearInterestRate.multiply(BigDecimal.valueOf(repaymentEvery), mc);
|
BigDecimal interestRate = oneDayOfYearInterestRate.multiply(BigDecimal.valueOf(repaymentEvery), mc);
|
||||||
return outstandingBalance.multiplyRetainScale(interestRate, mc.getRoundingMode());
|
return outstandingBalance.getAmount().multiply(interestRate, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long calculatePeriodsInOneYear(final PaymentPeriodsInOneYearCalculator calculator) {
|
private long calculatePeriodsInOneYear(final PaymentPeriodsInOneYearCalculator calculator) {
|
||||||
@@ -709,7 +709,7 @@ public final class LoanApplicationTerms {
|
|||||||
return totalNumberOfRepaymentPeriods - getPrincipalGrace();
|
return totalNumberOfRepaymentPeriods - getPrincipalGrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPrincipalGraceApplicableForThisPeriod(final int periodNumber) {
|
public boolean isPrincipalGraceApplicableForThisPeriod(final int periodNumber) {
|
||||||
return periodNumber > 0 && periodNumber <= getPrincipalGrace();
|
return periodNumber > 0 && periodNumber <= getPrincipalGrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +981,7 @@ public final class LoanApplicationTerms {
|
|||||||
if (this.interestCalculationPeriodMethod.getValue().equals(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getValue())) {
|
if (this.interestCalculationPeriodMethod.getValue().equals(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD.getValue())) {
|
||||||
switch (this.repaymentPeriodFrequencyType) {
|
switch (this.repaymentPeriodFrequencyType) {
|
||||||
case WEEKS:
|
case WEEKS:
|
||||||
int days = getPeriodsBetween(fromDate, toDate);
|
int days = Days.daysBetween(fromDate, toDate).getDays();
|
||||||
isSameAsRepaymentPeriod = (days % 7) == 0;
|
isSameAsRepaymentPeriod = (days % 7) == 0;
|
||||||
break;
|
break;
|
||||||
case MONTHS:
|
case MONTHS:
|
||||||
@@ -1016,9 +1016,14 @@ public final class LoanApplicationTerms {
|
|||||||
PeriodType periodType = PeriodType.yearMonthDay();
|
PeriodType periodType = PeriodType.yearMonthDay();
|
||||||
Period difference = new Period(fromDate, toDate, periodType);
|
Period difference = new Period(fromDate, toDate, periodType);
|
||||||
switch (this.repaymentPeriodFrequencyType) {
|
switch (this.repaymentPeriodFrequencyType) {
|
||||||
case WEEKS:
|
case DAYS:
|
||||||
numberOfPeriods = difference.getDays();
|
numberOfPeriods = difference.getDays();
|
||||||
break;
|
break;
|
||||||
|
case WEEKS:
|
||||||
|
periodType = PeriodType.weeks();
|
||||||
|
difference = new Period(fromDate, toDate, periodType);
|
||||||
|
numberOfPeriods = difference.getWeeks();
|
||||||
|
break;
|
||||||
case MONTHS:
|
case MONTHS:
|
||||||
numberOfPeriods = difference.getMonths();
|
numberOfPeriods = difference.getMonths();
|
||||||
break;
|
break;
|
||||||
|
|||||||
+3
-1
@@ -9,6 +9,7 @@ import java.math.MathContext;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
||||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
@@ -27,7 +28,8 @@ public interface LoanScheduleGenerator {
|
|||||||
LoanScheduleModel rescheduleNextInstallments(MathContext mc, ApplicationCurrency applicationCurrency,
|
LoanScheduleModel rescheduleNextInstallments(MathContext mc, ApplicationCurrency applicationCurrency,
|
||||||
LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges, boolean isHolidayEnabled, List<Holiday> holidays,
|
LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges, boolean isHolidayEnabled, List<Holiday> holidays,
|
||||||
WorkingDays workingDays, List<LoanTransaction> transactions,
|
WorkingDays workingDays, List<LoanTransaction> transactions,
|
||||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
|
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||||
|
List<LoanRepaymentScheduleInstallment> previousSchedule, LocalDate recalculateFrom);
|
||||||
|
|
||||||
Money fetchPrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency,
|
Money fetchPrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments, MonetaryCurrency currency,
|
||||||
LoanApplicationTerms applicationTerms, MathContext mc);
|
LoanApplicationTerms applicationTerms, MathContext mc);
|
||||||
|
|||||||
+1
-1
@@ -2205,7 +2205,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
|
||||||
workingDays = this.workingDaysRepository.findOne();
|
workingDays = this.workingDaysRepository.findOne();
|
||||||
}
|
}
|
||||||
ChangedTransactionDetail changedTransactionDetail = loan.recalculateSchedule(loanScheduleFactory, applicationCurrency,
|
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(loanScheduleFactory, applicationCurrency,
|
||||||
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
|
calculatedRepaymentsStartingFromDate, isHolidayEnabled, holidays, workingDays, restCalendarInstance,
|
||||||
existingTransactionIds, existingReversedTransactionIds);
|
existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user