Example usage for org.joda.time LocalDate isEqual

List of usage examples for org.joda.time LocalDate isEqual

Introduction

In this page you can find the example usage for org.joda.time LocalDate isEqual.

Prototype

public boolean isEqual(ReadablePartial partial) 

Source Link

Document

Is this partial the same as the specified partial.

Usage

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*/
}