Example usage for org.joda.time LocalDate isBefore

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

Introduction

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

Prototype

public boolean isBefore(ReadablePartial partial) 

Source Link

Document

Is this partial earlier than the specified partial.

Usage

From source file:org.apache.fineract.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) {

    // first repayment's from date is same as disbursement 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;
    LocalDate seedDate = meetingStartDate;
    LocalDate latestRepaymentDate = null;
    for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {

        LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();

        // FIXME: AA this won't update repayment dates before current date.

        if (oldDueDate.isAfter(seedDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) {

            newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, seedDate, oldDueDate,
                    loanRepaymentInterval, frequency, workingDays);

            final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(
                    repaymentPeriodFrequencyType, loanRepaymentInterval, tmpFromDate);

            if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) {
                newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate,
                        tmpFromDate, loanRepaymentInterval, frequency, workingDays);
            }/*from   ww  w .j a v a 2 s  .c o  m*/

            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
            loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
            tmpFromDate = newRepaymentDate;// update with new repayment
            // date
        } else {
            tmpFromDate = oldDueDate;
        }
    }
    if (latestRepaymentDate != null) {
        this.expectedMaturityDate = latestRepaymentDate.toDate();
    }
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.Loan.java

License:Apache License

public void applyHolidayToRepaymentScheduleDates(final Holiday holiday) {
    // first repayment's from date is same as disbursement date.
    LocalDate tmpFromDate = getDisbursementDate();
    // Loop through all loanRepayments
    for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
        final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();

        // update from date if it's not same as previous installament's due
        // date.//www  .  ja  v a 2 s.  c  o m
        if (!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)) {
            loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
        }
        if (oldDueDate.isAfter(holiday.getToDateLocalDate())) {
            break;
        }

        if (oldDueDate.equals(holiday.getFromDateLocalDate()) || oldDueDate.equals(holiday.getToDateLocalDate())
                || oldDueDate.isAfter(holiday.getFromDateLocalDate())
                        && oldDueDate.isBefore(holiday.getToDateLocalDate())) {
            // FIXME: AA do we need to apply non-working days.
            // Assuming holiday's repayment reschedule to date cannot be
            // created on a non-working day.
            final LocalDate newRepaymentDate = holiday.getRepaymentsRescheduledToLocalDate();
            loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
        }
        tmpFromDate = loanRepaymentScheduleInstallment.getDueDate();
    }
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.Loan.java

License:Apache License

private LocalDate getLastUserTransactionDate() {
    LocalDate currentTransactionDate = getDisbursementDate();
    for (final LoanTransaction previousTransaction : this.loanTransactions) {
        if (!(previousTransaction.isReversed() || previousTransaction.isAccrual())) {
            if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
                currentTransactionDate = previousTransaction.getTransactionDate();
            }/*  ww  w . ja  v a 2 s. c  o m*/
        }
    }
    return currentTransactionDate;
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.Loan.java

License:Apache License

public void regenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO,
        final AppUser currentUser) {

    LocalDate lastTransactionDate = getLastUserTransactionDate();
    final LoanScheduleDTO loanSchedule = getRecalculatedSchedule(generatorDTO);
    if (loanSchedule == null) {
        return;/*from   w  ww.j  av  a 2 s. c  om*/
    }
    updateLoanSchedule(loanSchedule.getInstallments(), currentUser);
    this.interestRecalculatedOn = DateUtils.getDateOfTenant();
    LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate();
    Set<LoanCharge> charges = this.charges();
    for (LoanCharge loanCharge : charges) {
        if (!loanCharge.isDueAtDisbursement()) {
            updateOverdueScheduleInstallment(loanCharge);
            if (loanCharge.getDueLocalDate() == null
                    || (!lastRepaymentDate.isBefore(loanCharge.getDueLocalDate()))) {
                if (!loanCharge.isWaived() && (loanCharge.getDueLocalDate() == null
                        || !lastTransactionDate.isAfter(loanCharge.getDueLocalDate()))) {
                    recalculateLoanCharge(loanCharge, generatorDTO.getPenaltyWaitPeriod());
                    loanCharge.updateWaivedAmount(getCurrency());
                }
            } else {
                loanCharge.setActive(false);
            }
        }
    }

    processPostDisbursementTransactions();
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.Loan.java

License:Apache License

private ChangedTransactionDetail handleRefundTransaction(final LoanTransaction loanTransaction,
        final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction) {

    ChangedTransactionDetail changedTransactionDetail = null;

    final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REFUND,
            LoanStatus.fromInt(this.loanStatus));
    this.loanStatus = statusEnum.getValue();

    loanTransaction.updateLoan(this);

    // final boolean isTransactionChronologicallyLatest =
    // isChronologicallyLatestRefund(loanTransaction,
    // this.loanTransactions);

    if (status().isOverpaid() || status().isClosed()) {

        final String errorMessage = "This refund option is only for active loans ";
        throw new InvalidLoanStateTransitionException("transaction", "is.exceeding.overpaid.amount",
                errorMessage, this.totalOverpaid, loanTransaction.getAmount(getCurrency()).getAmount());

    } else if (this.getTotalPaidInRepayments().isZero()) {
        final String errorMessage = "Cannot refund when no payment has been made";
        throw new InvalidLoanStateTransitionException("transaction", "no.payment.yet.made.for.loan",
                errorMessage);/*from   w  ww.  j  ava 2  s .  c om*/
    }

    if (loanTransaction.isNotZero(loanCurrency())) {
        this.loanTransactions.add(loanTransaction);
    }

    if (loanTransaction.isNotRefundForActiveLoan()) {
        final String errorMessage = "A transaction of type refund was expected but not received.";
        throw new InvalidLoanTransactionTypeException("transaction", "is.not.a.refund.transaction",
                errorMessage);
    }

    final LocalDate loanTransactionDate = loanTransaction.getTransactionDate();
    if (loanTransactionDate.isBefore(getDisbursementDate())) {
        final String errorMessage = "The transaction date cannot be before the loan disbursement date: "
                + getApprovedOnDate().toString();
        throw new InvalidLoanStateTransitionException("transaction", "cannot.be.before.disbursement.date",
                errorMessage, loanTransactionDate, getDisbursementDate());
    }

    if (loanTransactionDate.isAfter(DateUtils.getLocalDateOfTenant())) {
        final String errorMessage = "The transaction date cannot be in the future.";
        throw new InvalidLoanStateTransitionException("transaction", "cannot.be.a.future.date", errorMessage,
                loanTransactionDate);
    }

    if (this.loanProduct.isMultiDisburseLoan() && adjustedTransaction == null) {
        BigDecimal totalDisbursed = getDisbursedAmount();
        if (totalDisbursed.compareTo(this.summary.getTotalPrincipalRepaid()) < 0) {
            final String errorMessage = "The transaction cannot be done before the loan disbursement: "
                    + getApprovedOnDate().toString();
            throw new InvalidLoanStateTransitionException("transaction", "cannot.be.done.before.disbursement",
                    errorMessage);
        }
    }

    final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
            .determineProcessor(this.transactionProcessingStrategy);

    // If is a refund
    if (adjustedTransaction == null) {
        loanRepaymentScheduleTransactionProcessor.handleRefund(loanTransaction, getCurrency(),
                this.repaymentScheduleInstallments, charges());
    } else {
        final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
        changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
                getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(),
                this.repaymentScheduleInstallments, charges());
        for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail
                .getNewTransactionMappings().entrySet()) {
            mapEntry.getValue().updateLoan(this);
        }

    }

    updateLoanSummaryDerivedFields();

    doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);

    return changedTransactionDetail;
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.Loan.java

License:Apache License

public Map<String, Object> undoLastDisbursal(ScheduleGeneratorDTO scheduleGeneratorDTO,
        List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds, AppUser currentUser,
        Loan loan) {//from w  w  w .j a v  a2s  . co m

    validateAccountStatus(LoanEvent.LOAN_DISBURSAL_UNDO_LAST);
    existingTransactionIds.addAll(findExistingTransactionIds());
    existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
    final Map<String, Object> actualChanges = new LinkedHashMap<>();
    validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO_LAST,
            getDisbursementDate());
    LocalDate actualDisbursementDate = null;
    LocalDate lastTransactionDate = getDisbursementDate();
    List<LoanTransaction> loanTransactions = retreiveListOfTransactionsExcludeAccruals();
    Collections.reverse(loanTransactions);
    for (final LoanTransaction previousTransaction : loanTransactions) {
        if (lastTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
            if (previousTransaction.isRepayment() || previousTransaction.isWaiver()
                    || previousTransaction.isChargePayment()) {
                throw new UndoLastTrancheDisbursementException(previousTransaction.getId());
            }
        }
        if (previousTransaction.isDisbursement()) {
            lastTransactionDate = previousTransaction.getTransactionDate();
            break;
        }
    }
    actualDisbursementDate = lastTransactionDate;
    updateLoanToLastDisbursalState(actualDisbursementDate);
    for (Iterator<LoanTermVariations> iterator = this.loanTermVariations.iterator(); iterator.hasNext();) {
        LoanTermVariations loanTermVariations = iterator.next();
        if (loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate)) {
            iterator.remove();
        }
    }
    reverseExistingTransactionsTillLastDisbursal(actualDisbursementDate);
    loan.recalculateScheduleFromLastTransaction(scheduleGeneratorDTO, existingTransactionIds,
            existingReversedTransactionIds, currentUser);
    actualChanges.put("undolastdisbursal", "true");
    actualChanges.put("disbursedAmount", this.getDisbursedAmount());
    updateLoanSummaryDerivedFields();

    return actualChanges;
}

From source file:org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainServiceJpa.java

License:Apache License

@Override
public void recalculateAccruals(Loan loan) {
    LocalDate accruedTill = loan.getAccruedTill();
    if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()
            || !loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || accruedTill == null
            || loan.isNpa() || !loan.status().isActive()) {
        return;/*from   www .j  a  v a  2s  . c om*/
    }
    Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>();
    List<LoanRepaymentScheduleInstallment> installments = loan.fetchRepaymentScheduleInstallments();
    Long loanId = loan.getId();
    Long officeId = loan.getOfficeId();
    LocalDate accrualStartDate = null;
    PeriodFrequencyType repaymentFrequency = loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType();
    Integer repayEvery = loan.repaymentScheduleDetail().getRepayEvery();
    LocalDate interestCalculatedFrom = loan.getInterestChargedFromDate();
    Long loanProductId = loan.productId();
    MonetaryCurrency currency = loan.getCurrency();
    ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository
            .findOneWithNotFoundDetection(currency);
    CurrencyData currencyData = applicationCurrency.toData();
    Set<LoanCharge> loanCharges = loan.charges();

    for (LoanRepaymentScheduleInstallment installment : installments) {
        if (!accruedTill.isBefore(installment.getDueDate()) || (accruedTill.isAfter(installment.getFromDate())
                && !accruedTill.isAfter(installment.getDueDate()))) {
            BigDecimal dueDateFeeIncome = BigDecimal.ZERO;
            BigDecimal dueDatePenaltyIncome = BigDecimal.ZERO;
            LocalDate chargesTillDate = installment.getDueDate();
            if (!accruedTill.isAfter(installment.getDueDate())) {
                chargesTillDate = accruedTill;
            }

            for (final LoanCharge loanCharge : loanCharges) {
                if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(installment.getFromDate(),
                        chargesTillDate)) {
                    if (loanCharge.isFeeCharge()) {
                        dueDateFeeIncome = dueDateFeeIncome.add(loanCharge.amount());
                    } else if (loanCharge.isPenaltyCharge()) {
                        dueDatePenaltyIncome = dueDatePenaltyIncome.add(loanCharge.amount());
                    }
                }
            }
            LoanScheduleAccrualData accrualData = new LoanScheduleAccrualData(loanId, officeId,
                    installment.getInstallmentNumber(), accrualStartDate, repaymentFrequency, repayEvery,
                    installment.getDueDate(), installment.getFromDate(), installment.getId(), loanProductId,
                    installment.getInterestCharged(currency).getAmount(),
                    installment.getFeeChargesCharged(currency).getAmount(),
                    installment.getPenaltyChargesCharged(currency).getAmount(),
                    installment.getInterestAccrued(currency).getAmount(),
                    installment.getFeeAccrued(currency).getAmount(),
                    installment.getPenaltyAccrued(currency).getAmount(), currencyData, interestCalculatedFrom,
                    installment.getInterestWaived(currency).getAmount());
            loanScheduleAccrualDatas.add(accrualData);

        }
    }

    if (!loanScheduleAccrualDatas.isEmpty()) {
        String error = this.loanAccrualPlatformService.addPeriodicAccruals(accruedTill,
                loanScheduleAccrualDatas);
        if (error.length() > 0) {
            String globalisationMessageCode = "error.msg.accrual.exception";
            throw new GeneralPlatformDomainRuleException(globalisationMessageCode, error, error);
        }
    }
}

From source file:org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java

License:Apache License

private LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
        final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO,
        final LoanScheduleParams loanScheduleParams) {

    final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
    // generate list of proposed schedule due dates
    LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms,
            holidayDetailDTO);/*from w  w w  .  j a  v  a2s  .  c o m*/
    LoanTermVariationsData lastDueDateVariation = loanApplicationTerms.getLoanTermVariations()
            .fetchLoanTermDueDateVariationsData(loanEndDate);
    if (lastDueDateVariation != null) {
        loanEndDate = lastDueDateVariation.getDateValue();
    }
    loanApplicationTerms.updateLoanEndDate(loanEndDate);

    // determine the total charges due at time of disbursement
    final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);

    // setup variables for tracking important facts required for loan
    // schedule generation.

    final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
    final int numberOfRepayments = loanApplicationTerms.fetchNumberOfRepaymentsAfterExceptions();

    LoanScheduleParams scheduleParams = null;
    if (loanScheduleParams == null) {
        scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency,
                Money.of(currency, chargesDueAtTimeOfDisbursement),
                loanApplicationTerms.getExpectedDisbursementDate(),
                getPrincipalToBeScheduled(loanApplicationTerms));
    } else if (!loanScheduleParams.isPartialUpdate()) {
        scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency,
                Money.of(currency, chargesDueAtTimeOfDisbursement),
                loanApplicationTerms.getExpectedDisbursementDate(),
                getPrincipalToBeScheduled(loanApplicationTerms), loanScheduleParams);
    } else {
        scheduleParams = loanScheduleParams;
    }

    final Collection<RecalculationDetail> transactions = scheduleParams.getRecalculationDetails();
    final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = scheduleParams
            .getLoanRepaymentScheduleTransactionProcessor();

    final Collection<LoanScheduleModelPeriod> periods = createNewLoanScheduleListWithDisbursementDetails(
            numberOfRepayments, loanApplicationTerms, chargesDueAtTimeOfDisbursement);

    // Determine the total interest owed over the full loan for FLAT
    // interest method .
    final Money totalInterestChargedForFullLoanTerm = loanApplicationTerms
            .calculateTotalInterestCharged(this.paymentPeriodsInOneYearCalculator, mc);

    boolean isFirstRepayment = true;
    LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
            loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment,
            holidayDetailDTO);
    final LocalDate idealDisbursementDate = this.scheduledDateGenerator
            .idealDisbursementDateBasedOnFirstRepaymentDate(
                    loanApplicationTerms.getLoanTermPeriodFrequencyType(),
                    loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);

    if (!scheduleParams.isPartialUpdate()) {
        // Set Fixed Principal Amount
        updateAmortization(mc, loanApplicationTerms, scheduleParams.getPeriodNumber(),
                scheduleParams.getOutstandingBalance());

        if (loanApplicationTerms.isMultiDisburseLoan()) {
            // fetches the first tranche amount and also updates other
            // tranche
            // details to map
            BigDecimal disburseAmt = getDisbursementAmount(loanApplicationTerms,
                    scheduleParams.getPeriodStartDate(), periods, chargesDueAtTimeOfDisbursement,
                    scheduleParams.getDisburseDetailMap(), scheduleParams.applyInterestRecalculation());
            scheduleParams.setPrincipalToBeScheduled(Money.of(currency, disburseAmt));
            loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().zero().plus(disburseAmt));
            scheduleParams.setOutstandingBalance(Money.of(currency, disburseAmt));
            scheduleParams.setOutstandingBalanceAsPerRest(Money.of(currency, disburseAmt));
        }
    }

    // charges which depends on total loan interest will be added to this
    // set and handled separately after all installments generated
    final Set<LoanCharge> nonCompoundingCharges = seperateTotalCompoundingPercentageCharges(loanCharges);

    LocalDate currentDate = DateUtils.getLocalDateOfTenant();
    LocalDate lastRestDate = currentDate;
    if (loanApplicationTerms.getRestCalendarInstance() != null) {
        lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms,
                holidayDetailDTO);
    }

    boolean isNextRepaymentAvailable = true;
    Boolean extendTermForDailyRepayments = false;

    if (holidayDetailDTO.getWorkingDays().getExtendTermForDailyRepayments() == true
            && loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.DAYS
            && loanApplicationTerms.getRepaymentEvery() == 1) {
        holidayDetailDTO.getWorkingDays()
                .setRepaymentReschedulingType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getValue());
        extendTermForDailyRepayments = true;
    }

    final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations()
            .getInterestRateChanges();

    // this block is to start the schedule generation from specified date
    if (scheduleParams.isPartialUpdate()) {
        if (loanApplicationTerms.isMultiDisburseLoan()) {
            loanApplicationTerms.setPrincipal(scheduleParams.getPrincipalToBeScheduled());
        }

        applyLoanVariationsForPartialScheduleGenerate(loanApplicationTerms, scheduleParams, interestRates);

        isFirstRepayment = false;
    }
    while (!scheduleParams.getOutstandingBalance().isZero()
            || !scheduleParams.getDisburseDetailMap().isEmpty()) {
        LocalDate previousRepaymentDate = scheduleParams.getActualRepaymentDate();
        scheduleParams.setActualRepaymentDate(
                this.scheduledDateGenerator.generateNextRepaymentDate(scheduleParams.getActualRepaymentDate(),
                        loanApplicationTerms, isFirstRepayment, holidayDetailDTO));
        isFirstRepayment = false;
        LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(
                scheduleParams.getActualRepaymentDate(), loanApplicationTerms, holidayDetailDTO);

        // calculated interest start date for the period
        LocalDate periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(
                loanApplicationTerms, scheduleParams.getPeriodStartDate(), idealDisbursementDate,
                firstRepaymentdate);

        // Loan Schedule Exceptions that need to be applied for Loan Account
        LoanTermVariationParams termVariationParams = applyLoanTermVariations(loanApplicationTerms,
                scheduleParams, previousRepaymentDate, scheduledDueDate);

        scheduledDueDate = termVariationParams.getScheduledDueDate();
        // Updates total days in term
        scheduleParams.addLoanTermInDays(
                Days.daysBetween(scheduleParams.getPeriodStartDate(), scheduledDueDate).getDays());
        if (termVariationParams.isSkipPeriod()) {
            continue;
        }

        if (scheduleParams.getPeriodStartDate().isAfter(scheduledDueDate)) {
            throw new ScheduleDateException("Due date can't be before period start date", scheduledDueDate);
        }

        if (!scheduleParams.getLatePaymentMap().isEmpty()) {
            populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, currentDate,
                    loanApplicationTerms, holidayDetailDTO, scheduleParams.getCompoundingMap(), loanCharges,
                    currency);
            scheduleParams.getCompoundingDateVariations().put(scheduleParams.getPeriodStartDate(),
                    new TreeMap<>(scheduleParams.getCompoundingMap()));
        }

        if (extendTermForDailyRepayments) {
            scheduleParams.setActualRepaymentDate(scheduledDueDate);
        }

        // this block is to generate the schedule till the specified
        // date(used for calculating preclosure)
        if (scheduleParams.getScheduleTillDate() != null
                && !scheduledDueDate.isBefore(scheduleParams.getScheduleTillDate())) {
            scheduledDueDate = scheduleParams.getScheduleTillDate();
            isNextRepaymentAvailable = false;
        }

        // populates the collection with transactions till the due date of
        // the period for interest recalculation enabled loans
        Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(
                scheduleParams.applyInterestRecalculation(), scheduledDueDate, transactions);

        final double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
                .calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest,
                        scheduledDueDate, loanApplicationTerms.getInterestChargedFromLocalDate(),
                        loanApplicationTerms.getLoanTermPeriodFrequencyType(),
                        loanApplicationTerms.getRepaymentEvery());
        ScheduleCurrentPeriodParams currentPeriodParams = new ScheduleCurrentPeriodParams(currency,
                interestCalculationGraceOnRepaymentPeriodFraction);

        if (loanApplicationTerms.isMultiDisburseLoan()) {
            updateBalanceBasedOnDisbursement(loanApplicationTerms, chargesDueAtTimeOfDisbursement,
                    scheduleParams, periods, scheduledDueDate);
        }

        // process repayments to the schedule as per the repayment
        // transaction processor configuration
        // will add a new schedule with interest till the transaction date
        // for a loan repayment which falls between the
        // two periods for interest first repayment strategies
        handleRecalculationForNonDueDateTransactions(mc, loanApplicationTerms, loanCharges, holidayDetailDTO,
                scheduleParams, periods, totalInterestChargedForFullLoanTerm, idealDisbursementDate,
                firstRepaymentdate, lastRestDate, scheduledDueDate, periodStartDateApplicableForInterest,
                applicableTransactions, currentPeriodParams);

        if (currentPeriodParams.isSkipCurrentLoop()) {
            continue;
        }
        periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
                scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate);

        // backup for pre-close transaction
        updateCompoundingDetails(scheduleParams, periodStartDateApplicableForInterest);

        // 5 determine principal,interest of repayment period
        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, scheduledDueDate,
                interestRates);

        // will check for EMI amount greater than interest calculated
        if (loanApplicationTerms.getFixedEmiAmount() != null && loanApplicationTerms.getFixedEmiAmount()
                .compareTo(principalInterestForThisPeriod.interest().getAmount()) == -1) {
            String errorMsg = "EMI amount must be greater than : "
                    + principalInterestForThisPeriod.interest().getAmount();
            throw new MultiDisbursementEmiAmountException(errorMsg,
                    principalInterestForThisPeriod.interest().getAmount(),
                    loanApplicationTerms.getFixedEmiAmount());
        }

        // update cumulative fields for principal & interest
        currentPeriodParams.setInterestForThisPeriod(principalInterestForThisPeriod.interest());
        Money lastTotalOutstandingInterestPaymentDueToGrace = scheduleParams
                .getTotalOutstandingInterestPaymentDueToGrace();
        scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(
                principalInterestForThisPeriod.interestPaymentDueToGrace());
        currentPeriodParams.setPrincipalForThisPeriod(principalInterestForThisPeriod.principal());

        // applies early payments on principal portion
        updatePrincipalPortionBasedOnPreviousEarlyPayments(currency, scheduleParams, currentPeriodParams);

        // updates amounts with current earlyPaidAmount
        updateAmountsBasedOnCurrentEarlyPayments(mc, loanApplicationTerms, scheduleParams, currentPeriodParams);

        if (scheduleParams.getOutstandingBalance().isLessThanZero() || !isNextRepaymentAvailable) {
            currentPeriodParams.plusPrincipalForThisPeriod(scheduleParams.getOutstandingBalance());
            scheduleParams.setOutstandingBalance(Money.zero(currency));
        }

        if (!isNextRepaymentAvailable) {
            scheduleParams.getDisburseDetailMap().clear();
        }

        // applies charges for the period
        applyChargesForCurrentPeriod(loanCharges, currency, scheduleParams, scheduledDueDate,
                currentPeriodParams);

        // sum up real totalInstallmentDue from components
        final Money totalInstallmentDue = currentPeriodParams.fetchTotalAmountForPeriod();

        // if previous installment is last then add interest to same
        // installment
        if (currentPeriodParams.getLastInstallment() != null
                && currentPeriodParams.getPrincipalForThisPeriod().isZero()) {
            currentPeriodParams.getLastInstallment()
                    .addInterestAmount(currentPeriodParams.getInterestForThisPeriod());
            continue;
        }

        // create repayment period from parts
        LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(
                scheduleParams.getInstalmentNumber(), scheduleParams.getPeriodStartDate(), scheduledDueDate,
                currentPeriodParams.getPrincipalForThisPeriod(), scheduleParams.getOutstandingBalance(),
                currentPeriodParams.getInterestForThisPeriod(),
                currentPeriodParams.getFeeChargesForInstallment(),
                currentPeriodParams.getPenaltyChargesForInstallment(), totalInstallmentDue, false);

        // apply loan transactions on installments to identify early/late
        // payments for interest recalculation
        installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency,
                scheduleParams, loanRepaymentScheduleTransactionProcessor, totalInterestChargedForFullLoanTerm,
                lastRestDate, scheduledDueDate, periodStartDateApplicableForInterest, applicableTransactions,
                currentPeriodParams, lastTotalOutstandingInterestPaymentDueToGrace, installment, loanCharges);
        periods.add(installment);

        // Updates principal paid map with efective date for reducing
        // the amount from outstanding balance(interest calculation)
        updateAmountsWithEffectiveDate(loanApplicationTerms, holidayDetailDTO, scheduleParams, scheduledDueDate,
                currentPeriodParams, installment);

        // handle cumulative fields

        scheduleParams.addTotalCumulativePrincipal(currentPeriodParams.getPrincipalForThisPeriod());
        scheduleParams.addTotalRepaymentExpected(totalInstallmentDue);
        scheduleParams.addTotalCumulativeInterest(currentPeriodParams.getInterestForThisPeriod());
        scheduleParams.setPeriodStartDate(scheduledDueDate);
        scheduleParams.incrementInstalmentNumber();
        scheduleParams.incrementPeriodNumber();
        scheduleParams.getCompoundingDateVariations().clear();
        if (termVariationParams.isRecalculateAmounts()) {
            loanApplicationTerms.setCurrentPeriodFixedEmiAmount(null);
            loanApplicationTerms.setCurrentPeriodFixedPrincipalAmount(null);
            adjustInstallmentOrPrincipalAmount(loanApplicationTerms,
                    scheduleParams.getTotalCumulativePrincipal(), scheduleParams.getPeriodNumber(), mc);
        }
    }

    // this condition is to add the interest from grace period if not
    // already applied.
    if (scheduleParams.getTotalOutstandingInterestPaymentDueToGrace().isGreaterThanZero()) {
        LoanScheduleModelPeriod installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
        installment.addInterestAmount(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
        scheduleParams.addTotalRepaymentExpected(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
        scheduleParams
                .addTotalCumulativeInterest(scheduleParams.getTotalOutstandingInterestPaymentDueToGrace());
        scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(Money.zero(currency));
    }

    // determine fees and penalties for charges which depends on total
    // loan interest
    updatePeriodsWithCharges(currency, scheduleParams, periods, nonCompoundingCharges);

    // this block is to add extra re-payment schedules with interest portion
    // if the loan not paid with in loan term

    if (scheduleParams.getScheduleTillDate() != null) {
        currentDate = scheduleParams.getScheduleTillDate();
    }
    if (scheduleParams.applyInterestRecalculation() && scheduleParams.getLatePaymentMap().size() > 0
            && currentDate.isAfter(scheduleParams.getPeriodStartDate())) {
        Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentdate(mc, loanApplicationTerms,
                holidayDetailDTO, currency, periods, currentDate, loanRepaymentScheduleTransactionProcessor,
                transactions, loanCharges, scheduleParams);
        scheduleParams.addTotalCumulativeInterest(totalInterest);
    }

    loanApplicationTerms.resetFixedEmiAmount();
    final BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
    final BigDecimal totalOutstanding = BigDecimal.ZERO;

    return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
            scheduleParams.getPrincipalToBeScheduled(),
            scheduleParams.getTotalCumulativePrincipal().getAmount(), totalPrincipalPaid,
            scheduleParams.getTotalCumulativeInterest().getAmount(),
            scheduleParams.getTotalFeeChargesCharged().getAmount(),
            scheduleParams.getTotalPenaltyChargesCharged().getAmount(),
            scheduleParams.getTotalRepaymentExpected().getAmount(), totalOutstanding);
}

From source file:org.apache.fineract.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<>();
        LoanScheduleModelPeriod installment = null;
        LocalDate periodStartDateApplicableForInterest = periodStartDateForInterest;
        for (RecalculationDetail detail : applicableTransactions) {
            if (detail.isProcessed()) {
                continue;
            }//from  w  w  w. j  a va 2 s. c om
            boolean updateLatePaymentMap = false;
            final LocalDate transactionDate = detail.getTransactionDate();
            if (transactionDate.isBefore(scheduledDueDate)) {
                if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null
                        && scheduleParams.getLoanRepaymentScheduleTransactionProcessor()
                                .isInterestFirstRepaymentScheduleTransactionProcessor()) {
                    List<LoanTransaction> currentTransactions = 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);

                        int daysInPeriodApplicable = Days
                                .daysBetween(periodStartDateApplicableForInterest, transactionDate).getDays();
                        Money interestForThisinstallment = Money.zero(currency);
                        if (daysInPeriodApplicable > 0) {
                            // 5 determine interest till the transaction
                            // date
                            if (!scheduleParams.getCompoundingDateVariations()
                                    .containsKey(periodStartDateApplicableForInterest)) {
                                scheduleParams.getCompoundingDateVariations().put(
                                        periodStartDateApplicableForInterest,
                                        new TreeMap<>(scheduleParams.getCompoundingMap()));
                            }
                            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);

                        // 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();
                        // creates and insert Loan repayment schedule
                        // for
                        // the period
                        addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
                    } 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, periodStartDateApplicableForInterest, detail);
                    if (updateLatePaymentMap) {
                        updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency,
                                scheduleParams.getLatePaymentMap(), scheduledDueDate,
                                scheduleParams.getInstallments(), true, lastRestDate,
                                scheduleParams.getCompoundingMap());
                    }
                } 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 = fetchCompoundedArrears(loanApplicationTerms, currency,
                                detail.getTransaction());
                        if (unprocessed.isGreaterThanZero()) {
                            arrears = getTotalAmount(scheduleParams.getLatePaymentMap(), currency);
                            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()) {

                                LocalDate calculateTill = transactionDate;
                                if (!scheduleParams.getCompoundingDateVariations()
                                        .containsKey(periodStartDateApplicableForInterest)) {
                                    scheduleParams.getCompoundingDateVariations().put(
                                            periodStartDateApplicableForInterest,
                                            new TreeMap<>(scheduleParams.getCompoundingMap()));
                                }
                                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, periodStartDateApplicableForInterest, detail);
                        }
                    }

                }
            }

        }
        applicableTransactions.addAll(unprocessedTransactions);
        if (checkForOutstanding && scheduleParams.getOutstandingBalance().isZero()
                && scheduleParams.getDisburseDetailMap().isEmpty()) {
            currentPeriodParams.setSkipCurrentLoop(true);
        }
    }
}

From source file:org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AbstractLoanScheduleGenerator.java

License:Apache License

private void updateCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
        final Map<LocalDate, Money> latePaymentCompoundingMap, final MonetaryCurrency currency,
        final LocalDate lastRestDate, Money compoundedPortion, final LocalDate applicableDate) {
    Money appliedOnPrincipalVariationMap = Money.zero(currency);
    Map<LocalDate, Money> temp = new HashMap<>();
    for (LocalDate date : latePaymentCompoundingMap.keySet()) {
        if (date.isBefore(lastRestDate)) {
            Money money = latePaymentCompoundingMap.get(date);
            appliedOnPrincipalVariationMap = appliedOnPrincipalVariationMap.plus(money);
            if (appliedOnPrincipalVariationMap.isLessThan(compoundedPortion)) {
                if (date.isBefore(applicableDate)) {
                    updateMapWithAmount(principalVariationMap, money.negated(), date);
                    updateMapWithAmount(principalVariationMap, money, applicableDate);
                }/*from  w ww  .ja va 2 s  .c o m*/
            } else if (temp.isEmpty()) {
                Money diff = money.minus(appliedOnPrincipalVariationMap.minus(compoundedPortion));
                updateMapWithAmount(principalVariationMap, diff.negated(), date);
                updateMapWithAmount(principalVariationMap, diff, applicableDate);
                updateMapWithAmount(temp, money.minus(diff), date);
                updateMapWithAmount(temp, money.minus(diff).negated(), lastRestDate);
            } else {
                updateMapWithAmount(temp, money, date);
                updateMapWithAmount(temp, money.negated(), lastRestDate);
            }
        }
    }
    latePaymentCompoundingMap.clear();
    latePaymentCompoundingMap.putAll(temp);
}