List of usage examples for org.joda.time LocalDate isEqual
public boolean isEqual(ReadablePartial partial)
From source file:com.gst.portfolio.loanaccount.domain.Loan.java
License:Apache License
private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction, final List<LoanTransaction> loanTransactions) { boolean isChronologicallyLatestRepaymentOrWaiver = true; final LocalDate currentTransactionDate = loanTransaction.getTransactionDate(); for (final LoanTransaction previousTransaction : loanTransactions) { if (previousTransaction.isNotReversed()) { if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate()) || currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) { isChronologicallyLatestRepaymentOrWaiver = false; break; }//from w ww . j a v a2 s . c om } } return isChronologicallyLatestRepaymentOrWaiver; }
From source file:com.gst.portfolio.loanaccount.domain.Loan.java
License:Apache License
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule, final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays, final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate, final LocalDate newMeetingDate, final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) { // first repayment's from date is same as disbursement date. /*//from www. j av a2 s .c o m * meetingStartDate is used as seedDate Capture the seedDate from user * and use the seedDate as meetingStart date */ LocalDate tmpFromDate = getDisbursementDate(); final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail .getRepaymentPeriodFrequencyType(); final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery(); final String frequency = CalendarUtils .getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType); LocalDate newRepaymentDate = null; Boolean isFirstTime = true; LocalDate latestRepaymentDate = null; List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments(); for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) { LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate(); if (oldDueDate.isEqual(presentMeetingDate) || oldDueDate.isAfter(presentMeetingDate)) { if (isFirstTime) { isFirstTime = false; newRepaymentDate = newMeetingDate; } else { // tmpFromDate.plusDays(1) is done to make sure // getNewRepaymentMeetingDate method returns next meeting // date and not the same as tmpFromDate newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, tmpFromDate, tmpFromDate.plusDays(1), loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays); } if (isHolidayEnabled) { newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays); } if (latestRepaymentDate == null || latestRepaymentDate.isBefore(newRepaymentDate)) { latestRepaymentDate = newRepaymentDate; } loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate); // reset from date to get actual daysInPeriod if (!isFirstTime) { loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate); } tmpFromDate = newRepaymentDate;// update with new repayment // date } else { tmpFromDate = oldDueDate; } } if (latestRepaymentDate != null) { this.expectedMaturityDate = latestRepaymentDate.toDate(); } }
From source file:com.gst.portfolio.loanaccount.domain.Loan.java
License:Apache License
public Money retrieveAccruedAmountAfterDate(final LocalDate tillDate) { Money totalAmountAccrued = Money.zero(getCurrency()); Money actualAmountTobeAccrued = Money.zero(getCurrency()); for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) { totalAmountAccrued = totalAmountAccrued.plus(installment.getInterestAccrued(getCurrency())); if (tillDate.isAfter(installment.getFromDate()) && tillDate.isBefore(installment.getDueDate())) { int daysInPeriod = Days.daysBetween(installment.getFromDate(), installment.getDueDate()).getDays(); int tillDays = Days.daysBetween(installment.getFromDate(), tillDate).getDays(); double interest = calculateInterestForDays(daysInPeriod, installment.getInterestCharged(getCurrency()).getAmount(), tillDays); actualAmountTobeAccrued = actualAmountTobeAccrued.plus(interest); } else if ((tillDate.isAfter(installment.getFromDate()) && tillDate.isEqual(installment.getDueDate())) || (tillDate.isEqual(installment.getFromDate()) && tillDate.isEqual(installment.getDueDate())) || (tillDate.isAfter(installment.getFromDate()) && tillDate.isAfter(installment.getDueDate()))) { actualAmountTobeAccrued = actualAmountTobeAccrued .plus(installment.getInterestAccrued(getCurrency())); }/* w w w . ja v a2 s. c o m*/ } Money accredAmountAfterDate = totalAmountAccrued.minus(actualAmountTobeAccrued); if (accredAmountAfterDate.isLessThanZero()) { accredAmountAfterDate = Money.zero(getCurrency()); } return accredAmountAfterDate; }
From source file:com.gst.portfolio.loanaccount.domain.LoanAccountDomainServiceJpa.java
License:Apache License
@Override public Map<String, Object> foreCloseLoan(final Loan loan, final LocalDate foreClosureDate, final String noteText) { this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_FORECLOSURE, constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); MonetaryCurrency currency = loan.getCurrency(); LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant(); final Map<String, Object> changes = new LinkedHashMap<>(); List<LoanTransaction> newTransactions = new ArrayList<>(); final List<Long> existingTransactionIds = new ArrayList<>(); final List<Long> existingReversedTransactionIds = new ArrayList<>(); existingTransactionIds.addAll(loan.findExistingTransactionIds()); existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds()); final ScheduleGeneratorDTO scheduleGeneratorDTO = null; AppUser appUser = getAppUserIfPresent(); final LoanRepaymentScheduleInstallment foreCloseDetail = loan.fetchLoanForeclosureDetail(foreClosureDate); if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() && (loan.getAccruedTill() == null || !foreClosureDate.isEqual(loan.getAccruedTill()))) { loan.reverseAccrualsAfter(foreClosureDate); Money[] accruedReceivables = loan.getReceivableIncome(foreClosureDate); Money interestPortion = foreCloseDetail.getInterestCharged(currency).minus(accruedReceivables[0]); Money feePortion = foreCloseDetail.getFeeChargesCharged(currency).minus(accruedReceivables[1]); Money penaltyPortion = foreCloseDetail.getPenaltyChargesCharged(currency).minus(accruedReceivables[2]); Money total = interestPortion.plus(feePortion).plus(penaltyPortion); if (total.isGreaterThanZero()) { LoanTransaction accrualTransaction = LoanTransaction.accrueTransaction(loan, loan.getOffice(), foreClosureDate, total.getAmount(), interestPortion.getAmount(), feePortion.getAmount(), penaltyPortion.getAmount(), appUser); LocalDate fromDate = loan.getDisbursementDate(); if (loan.getAccruedTill() != null) { fromDate = loan.getAccruedTill(); }/* w w w . j a va2s . c om*/ createdDate = createdDate.plusSeconds(1); newTransactions.add(accrualTransaction); loan.addLoanTransaction(accrualTransaction); Set<LoanChargePaidBy> accrualCharges = accrualTransaction.getLoanChargesPaid(); for (LoanCharge loanCharge : loan.charges()) { if (loanCharge.isActive() && !loanCharge.isPaid() && (loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, foreClosureDate) || loanCharge.isInstalmentFee())) { final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(accrualTransaction, loanCharge, loanCharge.getAmountOutstanding(currency).getAmount(), null); accrualCharges.add(loanChargePaidBy); } } } } Money interestPayable = foreCloseDetail.getInterestCharged(currency); Money feePayable = foreCloseDetail.getFeeChargesCharged(currency); Money penaltyPayable = foreCloseDetail.getPenaltyChargesCharged(currency); Money payPrincipal = foreCloseDetail.getPrincipal(currency); loan.updateInstallmentsPostDate(foreClosureDate); LoanTransaction payment = null; if (payPrincipal.plus(interestPayable).plus(feePayable).plus(penaltyPayable).isGreaterThanZero()) { final PaymentDetail paymentDetail = null; String externalId = null; final LocalDateTime currentDateTime = DateUtils.getLocalDateTimeOfTenant(); payment = LoanTransaction.repayment(loan.getOffice(), payPrincipal.plus(interestPayable).plus(feePayable).plus(penaltyPayable), paymentDetail, foreClosureDate, externalId, currentDateTime, appUser); createdDate = createdDate.plusSeconds(1); payment.updateCreatedDate(createdDate.toDate()); payment.updateLoan(loan); newTransactions.add(payment); } List<Long> transactionIds = new ArrayList<>(); final ChangedTransactionDetail changedTransactionDetail = loan.handleForeClosureTransactions(payment, defaultLoanLifecycleStateMachine(), scheduleGeneratorDTO, appUser); /*** * TODO Vishwas Batch save is giving me a * HibernateOptimisticLockingFailureException, looping and saving for * the time being, not a major issue for now as this loop is entered * only in edge cases (when a payment is made before the latest payment * recorded against the loan) ***/ for (LoanTransaction newTransaction : newTransactions) { saveLoanTransactionWithDataIntegrityViolationChecks(newTransaction); transactionIds.add(newTransaction.getId()); } changes.put("transactions", transactionIds); changes.put("eventAmount", payPrincipal.getAmount().negate()); if (changedTransactionDetail != null) { for (Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings() .entrySet()) { saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue()); // update loan with references to the newly created transactions loan.getLoanTransactions().add(mapEntry.getValue()); updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } } saveAndFlushLoanWithDataIntegrityViolationChecks(loan); if (StringUtils.isNotBlank(noteText)) { changes.put("note", noteText); final Note note = Note.loanNote(loan, noteText); this.noteRepository.save(note); } postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, false); this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_FORECLOSURE, constructEntityMap(BUSINESS_ENTITY.LOAN_TRANSACTION, payment)); return changes; }
From source file:com.gst.portfolio.loanaccount.domain.LoanCharge.java
License:Apache License
public LoanInstallmentCharge getInstallmentLoanCharge(final LocalDate periodDueDate) { for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) { if (periodDueDate.isEqual(loanChargePerInstallment.getRepaymentInstallment().getDueDate())) { return loanChargePerInstallment; }//from w w w.j ava 2 s.co m } return null; }
From source file:com.gst.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java
License:Apache License
@Override protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex, final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate, final Money transactionAmount) { boolean isInAdvance = false; LocalDate lastInstallmentDueDate = null; int previousInstallmentIndex = 0; if (currentInstallmentIndex > 0) { previousInstallmentIndex = currentInstallmentIndex - 1; }/*from w w w . j a v a 2 s.c o m*/ final LoanRepaymentScheduleInstallment previousInstallment = installments.get(previousInstallmentIndex); lastInstallmentDueDate = previousInstallment.getDueDate(); isInAdvance = !(transactionDate.isAfter(lastInstallmentDueDate) || (transactionDate.isEqual(lastInstallmentDueDate))); return isInAdvance; }
From source file:com.gst.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java
License:Apache License
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, 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(); boolean checkForOutstanding = true; List<RecalculationDetail> unprocessedTransactions = new ArrayList<>(); List<RecalculationDetail> processTransactions = new ArrayList<>(); LoanScheduleModelPeriod installment = null; LocalDate periodStartDateApplicableForInterest = periodStartDateForInterest; for (RecalculationDetail detail : applicableTransactions) { if (detail.isProcessed()) { continue; }//from w w w . java2 s . c o m boolean updateLatePaymentMap = false; final LocalDate transactionDate = detail.getTransactionDate(); if (transactionDate.isBefore(scheduledDueDate)) { if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null && scheduleParams.getLoanRepaymentScheduleTransactionProcessor() .isInterestFirstRepaymentScheduleTransactionProcessor()) { if (detail.getTransaction().isWaiver()) { processTransactions.add(detail); continue; } List<LoanTransaction> currentTransactions = new ArrayList<>(); for (RecalculationDetail processDetail : processTransactions) { currentTransactions.addAll(createCurrentTransactionList(processDetail)); } processTransactions.clear(); currentTransactions.addAll(createCurrentTransactionList(detail)); if (!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || scheduleParams.getInstalmentNumber() == 1) { int periodDays = Days.daysBetween(scheduleParams.getPeriodStartDate(), transactionDate) .getDays(); // calculates period start date for interest // calculation as per the configuration periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod( loanApplicationTerms, scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate, loanApplicationTerms.isInterestChargedFromDateSameAsDisbursalDateEnabled(), loanApplicationTerms.getExpectedDisbursementDate()); int daysInPeriodApplicable = Days .daysBetween(periodStartDateApplicableForInterest, transactionDate).getDays(); Money interestForThisinstallment = Money.zero(currency); if (daysInPeriodApplicable > 0) { // 5 determine interest till the transaction // date PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams.getTotalCumulativePrincipal() .minus(scheduleParams.getReducePrincipal()), scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm, scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(), scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams), scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, transactionDate, interestRates); interestForThisinstallment = principalInterestForThisPeriod.interest(); scheduleParams.setTotalOutstandingInterestPaymentDueToGrace( principalInterestForThisPeriod.interestPaymentDueToGrace()); } Money principalForThisPeriod = Money.zero(currency); // applies all the applicable charges to the // newly // created installment PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment, null); Money feeChargesForInstallment = cumulativeFeeChargesDueWithin( scheduleParams.getPeriodStartDate(), transactionDate, loanCharges, currency, principalInterest, scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativeInterest(), false); Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin( scheduleParams.getPeriodStartDate(), transactionDate, loanCharges, currency, principalInterest, scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativeInterest(), false); // sum up real totalInstallmentDue from // components final Money totalInstallmentDue = principalForThisPeriod .plus(interestForThisinstallment).plus(feeChargesForInstallment) .plus(penaltyChargesForInstallment); // create repayment period from parts installment = LoanScheduleModelRepaymentPeriod.repayment( scheduleParams.getInstalmentNumber(), scheduleParams.getPeriodStartDate(), transactionDate, principalForThisPeriod, scheduleParams.getOutstandingBalance(), interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment, totalInstallmentDue, true); periods.add(installment); addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment); updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate); // update outstanding balance for interest // calculation as per the rest updateOutstandingBalanceAsPerRest(scheduleParams, transactionDate); // handle cumulative fields scheduleParams.addLoanTermInDays(periodDays); scheduleParams.addTotalRepaymentExpected(totalInstallmentDue); scheduleParams.addTotalCumulativeInterest(interestForThisinstallment); scheduleParams.addTotalFeeChargesCharged(feeChargesForInstallment); scheduleParams.addTotalPenaltyChargesCharged(penaltyChargesForInstallment); scheduleParams.setPeriodStartDate(transactionDate); periodStartDateApplicableForInterest = scheduleParams.getPeriodStartDate(); updateLatePaymentMap = true; scheduleParams.incrementInstalmentNumber(); populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms, holidayDetailDTO, scheduleParams, loanCharges, currency); // creates and insert Loan repayment schedule // for // the period } else if (installment == null) { installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1); } // applies the transaction as per transaction // strategy // on scheduled installments to identify the // unprocessed(early payment ) amounts Money unprocessed = scheduleParams.getLoanRepaymentScheduleTransactionProcessor() .handleRepaymentSchedule(currentTransactions, currency, scheduleParams.getInstallments()); if (unprocessed.isGreaterThanZero()) { if (loanApplicationTerms.getPreClosureInterestCalculationStrategy() .calculateTillRestFrequencyEnabled()) { LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); checkForOutstanding = transactionDate.isEqual(applicableDate); } // reduces actual outstanding balance scheduleParams.reduceOutstandingBalance(unprocessed); // if outstanding balance becomes less than zero // then adjusts the princiapal Money addToPrinciapal = Money.zero(currency); if (!scheduleParams.getOutstandingBalance().isGreaterThanZero()) { addToPrinciapal = addToPrinciapal.plus(scheduleParams.getOutstandingBalance()); scheduleParams.setOutstandingBalance(Money.zero(currency)); currentPeriodParams.setLastInstallment(installment); } // updates principal portion map with the early // payment amounts and applicable date as per // rest updateAmountsBasedOnEarlyPayment(loanApplicationTerms, holidayDetailDTO, scheduleParams, installment, detail, unprocessed, addToPrinciapal); // method applies early payment strategy scheduleParams.addReducePrincipal(unprocessed); scheduleParams.setReducePrincipal(applyEarlyPaymentStrategy(loanApplicationTerms, scheduleParams.getReducePrincipal(), scheduleParams.getTotalCumulativePrincipal(), scheduleParams.getPeriodNumber(), mc)); } // identify late payments and add compounding // details to // map for interest calculation handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail); if (updateLatePaymentMap) { updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams.getLatePaymentMap(), scheduledDueDate, scheduleParams.getInstallments(), true, lastRestDate); } } else if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null) { LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); if (applicableDate.isBefore(scheduledDueDate)) { List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail); Money unprocessed = scheduleParams.getLoanRepaymentScheduleTransactionProcessor() .handleRepaymentSchedule(currentTransactions, currency, scheduleParams.getInstallments()); Money arrears = fetchArrears(loanApplicationTerms, currency, detail.getTransaction()); if (unprocessed.isGreaterThanZero()) { updateMapWithAmount(scheduleParams.getPrincipalPortionMap(), unprocessed, applicableDate); currentPeriodParams.plusEarlyPaidAmount(unprocessed); // this check is to identify pre-closure and // apply interest calculation as per // configuration for non due date payments if (!scheduleParams.getOutstandingBalance().isGreaterThan(unprocessed) && !loanApplicationTerms.getPreClosureInterestCalculationStrategy() .calculateTillRestFrequencyEnabled()) { scheduleParams.getCompoundingDateVariations().put( periodStartDateApplicableForInterest, new TreeMap<>(scheduleParams.getCompoundingMap())); LocalDate calculateTill = transactionDate; PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, currentPeriodParams .getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams.getTotalCumulativePrincipal() .minus(scheduleParams.getReducePrincipal()), scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm, scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(), scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams), scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, calculateTill, interestRates); if (!principalInterestForThisPeriod.interest() .plus(principalInterestForThisPeriod.interestPaymentDueToGrace()) .plus(scheduleParams.getOutstandingBalance()) .isGreaterThan(unprocessed)) { currentPeriodParams.minusEarlyPaidAmount(unprocessed); updateMapWithAmount(scheduleParams.getPrincipalPortionMap(), unprocessed.negated(), applicableDate); LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null, transactionDate, null, DateUtils.getLocalDateTimeOfTenant(), null); RecalculationDetail recalculationDetail = new RecalculationDetail( transactionDate, loanTransaction); unprocessedTransactions.add(recalculationDetail); break; } } LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null, scheduledDueDate, null, DateUtils.getLocalDateTimeOfTenant(), null); RecalculationDetail recalculationDetail = new RecalculationDetail(scheduledDueDate, loanTransaction); unprocessedTransactions.add(recalculationDetail); checkForOutstanding = false; scheduleParams.reduceOutstandingBalance(unprocessed); // if outstanding balance becomes less than // zero // then adjusts the princiapal Money addToPrinciapal = Money.zero(currency); if (scheduleParams.getOutstandingBalance().isLessThanZero()) { addToPrinciapal = addToPrinciapal.plus(scheduleParams.getOutstandingBalance()); scheduleParams.setOutstandingBalance(Money.zero(currency)); updateMapWithAmount(scheduleParams.getPrincipalPortionMap(), addToPrinciapal, applicableDate); currentPeriodParams.plusEarlyPaidAmount(addToPrinciapal); } } if (arrears.isGreaterThanZero() && applicableDate.isBefore(lastRestDate)) { handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail); } } } } } applicableTransactions.addAll(unprocessedTransactions); if (checkForOutstanding && scheduleParams.getOutstandingBalance().isZero() && scheduleParams.getDisburseDetailMap().isEmpty()) { currentPeriodParams.setSkipCurrentLoop(true); } } }
From source file:com.gst.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java
License:Apache License
/** * Method calculates interest on not paid outstanding principal and interest * (if compounding is enabled) till current date and adds new repayment * schedule detail/*from www . ja va 2s . c o m*/ * * @param compoundingMap * TODO * @param loanCharges * TODO * @param principalPortioMap * TODO * */ private Money addInterestOnlyRepaymentScheduleForCurrentdate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO, final MonetaryCurrency currency, final Collection<LoanScheduleModelPeriod> periods, final LocalDate currentDate, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final Collection<RecalculationDetail> transactions, final Set<LoanCharge> loanCharges, final LoanScheduleParams params) { boolean isFirstRepayment = false; LocalDate startDate = params.getPeriodStartDate(); Money outstanding = params.getOutstandingBalanceAsPerRest(); Money totalInterest = Money.zero(currency); Money totalCumulativeInterest = Money.zero(currency); double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0); int periodNumberTemp = 1; LocalDate lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); Collection<LoanTermVariationsData> applicableVariations = loanApplicationTerms.getLoanTermVariations() .getInterestRateChanges(); Money uncompoundedFromLastInstallment = params.getUnCompoundedAmount(); LocalDate additionalPeriodsStartDate = params.getPeriodStartDate(); do { params.setActualRepaymentDate(this.scheduledDateGenerator.generateNextRepaymentDate( params.getActualRepaymentDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO)); if (params.getActualRepaymentDate().isAfter(currentDate)) { params.setActualRepaymentDate(currentDate); } Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod( params.applyInterestRecalculation(), params.getActualRepaymentDate(), transactions); populateCompoundingDatesInPeriod(params.getPeriodStartDate(), params.getActualRepaymentDate(), loanApplicationTerms, holidayDetailDTO, params, loanCharges, currency); for (RecalculationDetail detail : applicableTransactions) { if (detail.isProcessed()) { continue; } LocalDate transactionDate = detail.getTransactionDate(); List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail); if (!params.getPeriodStartDate().isEqual(transactionDate)) { PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms, periodNumberTemp, mc, mergeVariationsToMap(params), params.getCompoundingMap(), params.getPeriodStartDate(), transactionDate, applicableVariations); Money interest = principalInterestForThisPeriod.interest(); totalInterest = totalInterest.plus(interest); LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment( params.getInstalmentNumber(), startDate, transactionDate, totalInterest.zero(), totalInterest.zero(), totalInterest, totalInterest.zero(), totalInterest.zero(), totalInterest, true); params.incrementInstalmentNumber(); periods.add(installment); totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest); totalInterest = totalInterest.zero(); addLoanRepaymentScheduleInstallment(params.getInstallments(), installment); updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, params, lastRestDate, transactionDate); populateCompoundingDatesInPeriod(installment.periodDueDate(), params.getActualRepaymentDate(), loanApplicationTerms, holidayDetailDTO, params, loanCharges, currency); uncompoundedFromLastInstallment = params.getUnCompoundedAmount(); params.setPeriodStartDate(transactionDate); startDate = transactionDate; additionalPeriodsStartDate = startDate; } loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions, currency, params.getInstallments()); updateLatePaidAmountsToPrincipalMap(detail.getTransaction(), loanApplicationTerms, currency, holidayDetailDTO, lastRestDate, params); updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, params.getLatePaymentMap(), currentDate, params.getInstallments(), false, lastRestDate); if (params.getLatePaymentMap().isEmpty() && isCompleted(params.getInstallments())) { outstanding = outstanding.zero(); } else { outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(), outstanding, false); } if (params.getLatePaymentMap().isEmpty() && outstanding.isZero()) { break; } } if (!outstanding.isZero()) { PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms, periodNumberTemp, mc, mergeVariationsToMap(params), params.getCompoundingMap(), params.getPeriodStartDate(), params.getActualRepaymentDate(), applicableVariations); Money interest = principalInterestForThisPeriod.interest(); totalInterest = totalInterest.plus(interest); if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) { Money uncompounded = params.getUnCompoundedAmount(); Money compounded = uncompounded.zero(); for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) { if (mapEntry.getKey().isAfter(params.getPeriodStartDate())) { compounded = compounded.plus(mapEntry.getValue()); } } if (compounded.isGreaterThanZero() && startDate.isEqual(additionalPeriodsStartDate)) { params.setCompoundedInLastInstallment(uncompoundedFromLastInstallment);// uncompounded in last installment additionalPeriodsStartDate = additionalPeriodsStartDate.plusDays(1); } Money compoundedForThisPeriod = compounded.minus(uncompounded); Money uncompoundedForThisPeriod = interest.minus(compoundedForThisPeriod); params.setUnCompoundedAmount(uncompoundedForThisPeriod); LocalDate compoundingDate = params.getPeriodStartDate(); if (loanApplicationTerms.allowCompoundingOnEod()) { compoundingDate = compoundingDate.minusDays(1); } compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO); if (compoundingDate.isEqual(params.getActualRepaymentDate())) { params.getCompoundingMap().put(compoundingDate, uncompoundedForThisPeriod); params.setUnCompoundedAmount(uncompoundedForThisPeriod.zero()); } } } params.setPeriodStartDate(params.getActualRepaymentDate()); } while (params.getActualRepaymentDate().isBefore(currentDate) && !outstanding.isZero()); if (totalInterest.isGreaterThanZero()) { LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment( params.getInstalmentNumber(), startDate, params.getActualRepaymentDate(), totalInterest.zero(), totalInterest.zero(), totalInterest, totalInterest.zero(), totalInterest.zero(), totalInterest, true); params.incrementInstalmentNumber(); periods.add(installment); params.getCompoundingDateVariations().put(startDate, new TreeMap<>(params.getCompoundingMap())); totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest); } return totalCumulativeInterest; }
From source file:com.gst.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java
License:Apache License
private void updateCompoundingMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO, final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) { if (loanApplicationTerms.isInterestRecalculationEnabled() && loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) { final MonetaryCurrency currency = params.getCurrency(); Money totalCompoundedAmount = Money.zero(currency); boolean lastInstallmentIsPastDate = false; for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) { if (params.getCompoundingDateVariations() .containsKey(loanRepaymentScheduleInstallment.getFromDate())) { lastInstallmentIsPastDate = params.applyInterestRecalculation() && loanRepaymentScheduleInstallment.getDueDate() .isBefore(DateUtils.getLocalDateOfTenant()); } else { final boolean isPastDate = params.applyInterestRecalculation() && loanRepaymentScheduleInstallment.getDueDate() .isBefore(DateUtils.getLocalDateOfTenant()); boolean periodHasCompoundingDate = false; Money amountCharged = Money.zero(currency); if (loanApplicationTerms.getInterestRecalculationCompoundingMethod() != null) { amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, loanRepaymentScheduleInstallment); }//from w w w .ja v a 2 s. c om final Map<LocalDate, Money> compoundingMap = params.getCompoundingMap(); LocalDate effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate(); if (loanApplicationTerms.allowCompoundingOnEod()) { effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate().minusDays(1); } LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(effectiveStartDate, loanApplicationTerms, holidayDetailDTO); final LocalDate restDate = getNextRestScheduleDate(scheduledDueDate.minusDays(1), loanApplicationTerms, holidayDetailDTO); if (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) { Money amountCompoundedFromLastPeriod = params.getCompoundedInLastInstallment(); if (amountCompoundedFromLastPeriod.isZero()) { amountCompoundedFromLastPeriod = params.getUnCompoundedAmount(); } totalCompoundedAmount = totalCompoundedAmount.minus(amountCompoundedFromLastPeriod); periodHasCompoundingDate = true; } while (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) { if (compoundingEffectiveDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) { Money amountToBeCompounding = amountCharged.minus(totalCompoundedAmount); updateMapWithAmount(compoundingMap, amountToBeCompounding, compoundingEffectiveDate); totalCompoundedAmount = totalCompoundedAmount.plus(amountToBeCompounding); } else if (compoundingMap.containsKey(compoundingEffectiveDate)) { Money compounedAmount = compoundingMap.get(compoundingEffectiveDate); totalCompoundedAmount = totalCompoundedAmount.plus(compounedAmount); } if (!loanApplicationTerms.allowCompoundingOnEod()) { compoundingEffectiveDate = compoundingEffectiveDate.plusDays(1); } compoundingEffectiveDate = getNextCompoundScheduleDate(compoundingEffectiveDate, loanApplicationTerms, holidayDetailDTO); } if (periodHasCompoundingDate) { if (isPastDate) { updateMapWithAmount(params.getPrincipalPortionMap(), totalCompoundedAmount.plus(params.getUnCompoundedAmount()), lastRestDate); } else { Money amountToBeEffected = amountCharged; if (lastInstallmentIsPastDate) { amountToBeEffected = amountToBeEffected.plus(params.getUnCompoundedAmount()); } updateMapWithAmount(params.getPrincipalPortionMap(), amountToBeEffected, restDate); } } if (totalCompoundedAmount.isGreaterThanZero()) { params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(), new TreeMap<>(params.getCompoundingMap())); for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) { if (!mapEntry.getKey().isAfter(loanRepaymentScheduleInstallment.getDueDate())) { updateMapWithAmount(params.getPrincipalPortionMap(), mapEntry.getValue().negated(), mapEntry.getKey()); } } params.minusUnCompoundedAmount(params.getUnCompoundedAmount()); params.getCompoundingMap().clear(); params.addUnCompoundedAmount(amountCharged.minus(totalCompoundedAmount)); } else { params.getCompoundingMap().clear(); params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(), new TreeMap<>(params.getCompoundingMap())); params.addUnCompoundedAmount(amountCharged); } params.setCompoundedInLastInstallment(amountCharged.zero()); lastInstallmentIsPastDate = isPastDate; } } } }
From source file:com.gst.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java
License:Apache License
private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate, final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency) { if (!amountApplicableDate.isEqual(lastRestDate)) { Money compoundedIncome = fetchCompoundedArrears(loanApplicationTerms, currency, transaction); updateMapWithAmount(principalPortionMap, compoundedIncome, amountApplicableDate); updateMapWithAmount(principalPortionMap, compoundedIncome.negated(), lastRestDate); }/*from ww w . java 2 s.com*/ }