Merge pull request #1580 from pramodn02/variableinstalmentchanges

MIFOSX-2358:fix for last installment overdue charge
This commit is contained in:
Adi Narayana Raju
2015-12-29 14:06:58 +05:30
6 changed files with 66 additions and 21 deletions
@@ -836,6 +836,9 @@ public class Loan extends AbstractPersistable<Long> {
*/
private BigDecimal calculateAmountPercentageAppliedTo(final LoanCharge loanCharge) {
BigDecimal amount = BigDecimal.ZERO;
if(loanCharge.isOverdueInstallmentCharge()){
return loanCharge.getAmountPercentageAppliedTo();
}
switch (loanCharge.getChargeCalculation()) {
case PERCENT_OF_AMOUNT:
amount = getPrincpal().getAmount();
@@ -172,7 +172,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// calculated interest start date for the period
LocalDate periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
scheduleParams.getPeriodStartDate(), idealDisbursementDate);
scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate);
// Loan Schedule Exceptions that need to be applied for Loan Account
LoanTermVariationParams termVariationParams = applyLoanTermVariations(loanApplicationTerms, scheduleParams,
@@ -229,14 +229,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// for a loan repayment which falls between the
// two periods for interest first repayment strategies
handleRecalculationForNonDueDateTransactions(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, scheduleParams, periods,
totalInterestChargedForFullLoanTerm, idealDisbursementDate, lastRestDate, scheduledDueDate,
totalInterestChargedForFullLoanTerm, idealDisbursementDate, firstRepaymentdate, lastRestDate, scheduledDueDate,
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams);
if (currentPeriodParams.isSkipCurrentLoop()) {
continue;
}
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
scheduleParams.getPeriodStartDate(), idealDisbursementDate);
scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate);
// backup for pre-close transaction
updateCompoundingDetails(scheduleParams, periodStartDateApplicableForInterest);
@@ -581,9 +581,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
private void handleRecalculationForNonDueDateTransactions(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, LoanScheduleParams scheduleParams,
final Collection<LoanScheduleModelPeriod> periods, final Money totalInterestChargedForFullLoanTerm,
final LocalDate idealDisbursementDate, final LocalDate lastRestDate, final LocalDate scheduledDueDate,
final LocalDate periodStartDateForInterest, final Collection<RecalculationDetail> applicableTransactions,
final ScheduleCurrentPeriodParams currentPeriodParams) {
final LocalDate idealDisbursementDate, LocalDate firstRepaymentdate, final LocalDate lastRestDate,
final LocalDate scheduledDueDate, final LocalDate periodStartDateForInterest,
final Collection<RecalculationDetail> applicableTransactions, final ScheduleCurrentPeriodParams currentPeriodParams) {
if (scheduleParams.applyInterestRecalculation()) {
final MonetaryCurrency currency = scheduleParams.getCurrency();
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
@@ -608,7 +608,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// calculates period start date for interest
// calculation as per the configuration
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
scheduleParams.getPeriodStartDate(), idealDisbursementDate);
scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate);
int daysInPeriodApplicable = Days.daysBetween(periodStartDateApplicableForInterest, transactionDate).getDays();
Money interestForThisinstallment = Money.zero(currency);
@@ -1507,15 +1507,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
/**
* calculates Interest stating date as per the settings
*
* @param firstRepaymentdate
* TODO
*/
private LocalDate calculateInterestStartDateForPeriod(final LoanApplicationTerms loanApplicationTerms, LocalDate periodStartDate,
final LocalDate idealDisbursementDate) {
final LocalDate idealDisbursementDate, final LocalDate firstRepaymentdate) {
LocalDate periodStartDateApplicableForInterest = periodStartDate;
if (periodStartDate.isBefore(idealDisbursementDate)) {
if (periodStartDate.isBefore(idealDisbursementDate) || firstRepaymentdate.isAfter(periodStartDate)) {
if (loanApplicationTerms.getInterestChargedFromLocalDate() != null) {
if (periodStartDate.isEqual(loanApplicationTerms.getExpectedDisbursementDate())
|| loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate().isBefore(
loanApplicationTerms.getInterestChargedFromLocalDate())) {
|| loanApplicationTerms.getInterestChargedFromLocalDate().isAfter(periodStartDate)) {
periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate();
}
} else {
@@ -146,13 +146,13 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
dataValidationErrors.add(error);
} else if (repaymentsStartingFromDate == null && interestChargedFromDate != null) {
if (expectedDisbursementDate != null && expectedDisbursementDate.isAfter(interestChargedFromDate)) {
/* if (expectedDisbursementDate != null && expectedDisbursementDate.isAfter(interestChargedFromDate)) {
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.loan.interestChargedFromDate.cannot.be.before.disbursement.date",
"The parameter interestChargedFromDate cannot be before the date given for expectedDisbursementDate.",
"interestChargedFromDate", interestChargedFromDate, expectedDisbursementDate);
dataValidationErrors.add(error);
}
}*/
}
}
@@ -1482,6 +1482,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(rm.schema()).append(" where DATE_SUB(CURDATE(),INTERVAL ? DAY) > ls.duedate ")
.append(" and ls.completed_derived <> 1 and mc.charge_applies_to_enum =1 ")
.append(" and ls.recalculated_interest_component <> 1 ")
.append(" and mc.charge_time_enum = 9 and ml.loan_status_id = 300 ");
if (backdatePenalties) { return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { penaltyWaitPeriod }); }
@@ -2474,6 +2474,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<>();
boolean runInterestRecalculation = false;
LocalDate recalculateFrom = DateUtils.getLocalDateOfTenant();
LocalDate lastChargeDate = null;
for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduleDatas) {
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(overdueInstallment.toString());
@@ -2486,6 +2487,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (recalculateFrom.isAfter(overdueDTO.getRecalculateFrom())) {
recalculateFrom = overdueDTO.getRecalculateFrom();
}
if (lastChargeDate == null || overdueDTO.getLastChargeAppliedDate().isAfter(lastChargeDate)) {
lastChargeDate = overdueDTO.getLastChargeAppliedDate();
}
}
if (loan != null) {
boolean reprocessRequired = true;
@@ -2503,6 +2507,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
if (reprocessRequired) {
addInstallmentIfPenaltyAppliedAfterLastDueDate(loan, lastChargeDate);
ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactions();
if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -2528,6 +2533,28 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
private void addInstallmentIfPenaltyAppliedAfterLastDueDate(Loan loan, LocalDate lastChargeDate) {
if (lastChargeDate != null) {
List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
LoanRepaymentScheduleInstallment lastInstallment = loan.fetchRepaymentScheduleInstallment(installments.size());
if (lastChargeDate.isAfter(lastInstallment.getDueDate())) {
if (lastInstallment.isRecalculatedInterestComponent()) {
installments.remove(lastInstallment);
lastInstallment = loan.fetchRepaymentScheduleInstallment(installments.size());
}
boolean recalculatedInterestComponent = true;
BigDecimal principal = BigDecimal.ZERO;
BigDecimal interest = BigDecimal.ZERO;
BigDecimal feeCharges = BigDecimal.ZERO;
BigDecimal penaltyCharges = BigDecimal.ONE;
LoanRepaymentScheduleInstallment newEntry = new LoanRepaymentScheduleInstallment(loan, installments.size() + 1,
lastInstallment.getDueDate(), lastChargeDate, principal, interest, feeCharges, penaltyCharges,
recalculatedInterestComponent);
installments.add(newEntry);
}
}
}
public LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Long loanId, final Long loanChargeId, final Integer periodNumber,
final JsonCommand command, Loan loan, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
boolean runInterestRecalculation = false;
@@ -2565,6 +2592,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
LoanRepaymentScheduleInstallment installment = null;
LocalDate lastChargeAppliedDate = dueDate;
if (!scheduleDates.isEmpty()) {
if (loan == null) {
loan = this.loanAssembler.assembleFrom(loanId);
@@ -2573,8 +2601,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
}
installment = loan.fetchRepaymentScheduleInstallment(periodNumber);
lastChargeAppliedDate = installment.getDueDate();
}
LocalDate recalculateFrom = DateUtils.getLocalDateOfTenant();
if (loan != null) {
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_APPLY_OVERDUE_CHARGE,
constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
@@ -2591,10 +2621,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (entry.getValue().isBefore(recalculateFrom)) {
recalculateFrom = entry.getValue();
}
if (entry.getValue().isAfter(lastChargeAppliedDate)) {
lastChargeAppliedDate = entry.getValue();
}
}
}
return new LoanOverdueDTO(loan, runInterestRecalculation, recalculateFrom);
return new LoanOverdueDTO(loan, runInterestRecalculation, recalculateFrom, lastChargeAppliedDate);
}
@Override
@@ -3079,11 +3112,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
BigDecimal interestRateDiff = loan.getInterestRateDifferential();
List<FloatingRatePeriodData> baseLendingRatePeriods = null;
try{
baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
.getRatePeriods();
}catch(final FloatingRateNotFoundException ex){
// Do not do anything
try {
baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate().getRatePeriods();
} catch (final FloatingRateNotFoundException ex) {
// Do not do anything
}
floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
baseLendingRatePeriods);
@@ -13,11 +13,14 @@ public class LoanOverdueDTO {
private final Loan loan;
private final boolean runInterestRecalculation;
private final LocalDate recalculateFrom;
private final LocalDate lastChargeAppliedDate;
public LoanOverdueDTO(final Loan loan, final boolean runInterestRecalculation, final LocalDate recalculateFrom) {
public LoanOverdueDTO(final Loan loan, final boolean runInterestRecalculation, final LocalDate recalculateFrom,
final LocalDate lastChargeAppliedDate) {
this.loan = loan;
this.runInterestRecalculation = runInterestRecalculation;
this.recalculateFrom = recalculateFrom;
this.lastChargeAppliedDate = lastChargeAppliedDate;
}
public boolean isRunInterestRecalculation() {
@@ -28,8 +31,12 @@ public class LoanOverdueDTO {
return this.loan;
}
public LocalDate getRecalculateFrom() {
return this.recalculateFrom;
}
public LocalDate getLastChargeAppliedDate() {
return this.lastChargeAppliedDate;
}
}