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.account.service.StandingInstructionWritePlatformServiceImpl.java

License:Apache License

@Override
@CronTarget(jobName = JobName.EXECUTE_STANDING_INSTRUCTIONS)
public void executeStandingInstructions() throws JobExecutionException {
    Collection<StandingInstructionData> instructionDatas = this.standingInstructionReadPlatformService
            .retrieveAll(StandingInstructionStatus.ACTIVE.getValue());
    final StringBuilder sb = new StringBuilder();
    for (StandingInstructionData data : instructionDatas) {
        boolean isDueForTransfer = false;
        AccountTransferRecurrenceType recurrenceType = data.recurrenceType();
        StandingInstructionType instructionType = data.instructionType();
        LocalDate transactionDate = new LocalDate();
        if (recurrenceType.isPeriodicRecurrence()) {
            final ScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
            PeriodFrequencyType frequencyType = data.recurrenceFrequency();
            LocalDate startDate = data.validFrom();
            if (frequencyType.isMonthly()) {
                startDate = startDate.withDayOfMonth(data.recurrenceOnDay());
                if (startDate.isBefore(data.validFrom())) {
                    startDate = startDate.plusMonths(1);
                }/*from ww w. j ava2 s .  c o m*/
            } else if (frequencyType.isYearly()) {
                startDate = startDate.withDayOfMonth(data.recurrenceOnDay())
                        .withMonthOfYear(data.recurrenceOnMonth());
                if (startDate.isBefore(data.validFrom())) {
                    startDate = startDate.plusYears(1);
                }
            }
            isDueForTransfer = scheduledDateGenerator.isDateFallsInSchedule(frequencyType,
                    data.recurrenceInterval(), startDate, transactionDate);

        }
        BigDecimal transactionAmount = data.amount();
        if (data.toAccountType().isLoanAccount() && (recurrenceType.isDuesRecurrence()
                || (isDueForTransfer && instructionType.isDuesAmoutTransfer()))) {
            StandingInstructionDuesData standingInstructionDuesData = this.standingInstructionReadPlatformService
                    .retriveLoanDuesData(data.toAccount().accountId());
            if (data.instructionType().isDuesAmoutTransfer()) {
                transactionAmount = standingInstructionDuesData.totalDueAmount();
            }
            if (recurrenceType.isDuesRecurrence()) {
                isDueForTransfer = new LocalDate().equals(standingInstructionDuesData.dueDate());
            }
        }

        if (isDueForTransfer && transactionAmount != null && transactionAmount.compareTo(BigDecimal.ZERO) > 0) {
            final AccountTransferDetails accountTransferDetails = this.accountTransferDetailRepository
                    .findOne(data.accountDetailId());
            final SavingsAccount fromSavingsAccount = null;
            final boolean isRegularTransaction = true;
            final boolean isExceptionForBalanceCheck = false;
            accountTransferDetails.accountTransferStandingInstruction()
                    .updateLatsRunDate(transactionDate.toDate());
            AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, transactionAmount,
                    data.fromAccountType(), data.toAccountType(), data.fromAccount().accountId(),
                    data.toAccount().accountId(), data.name() + " Standing instruction trasfer ", null, null,
                    null, null, data.toTransferType(), null, null, data.transferType().getValue(),
                    accountTransferDetails, null, null, null, null, fromSavingsAccount, isRegularTransaction,
                    isExceptionForBalanceCheck);
            transferAmount(sb, accountTransferDTO, data.getId());
        }
    }
    if (sb.length() > 0) {
        throw new JobExecutionException(sb.toString());
    }

}

From source file:org.apache.fineract.portfolio.calendar.domain.Calendar.java

License:Apache License

public Map<String, Object> updateStartDateAndDerivedFeilds(final LocalDate newMeetingStartDate) {

    final Map<String, Object> actualChanges = new LinkedHashMap<>(9);

    final LocalDate currentDate = DateUtils.getLocalDateOfTenant();

    if (newMeetingStartDate.isBefore(currentDate)) {
        final String defaultUserMessage = "New meeting effective from date cannot be in past";
        throw new CalendarDateException("new.start.date.cannot.be.in.past", defaultUserMessage,
                newMeetingStartDate, getStartDateLocalDate());
    } else if (isStartDateAfter(newMeetingStartDate) && isStartDateBeforeOrEqual(currentDate)) {
        // new meeting date should be on or after start date or current
        // date//  www.j  av a 2s  .c om
        final String defaultUserMessage = "New meeting effective from date cannot be a date before existing meeting start date";
        throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage,
                newMeetingStartDate, getStartDateLocalDate());
    } else {

        actualChanges.put(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue(), newMeetingStartDate.toString());
        this.startDate = newMeetingStartDate.toDate();

        /*
         * If meeting start date is changed then there is possibilities of
         * recurring day may change, so derive the recurring day and update
         * it if it is changed. For weekly type is weekday and for monthly
         * type it is day of the month
         */

        CalendarFrequencyType calendarFrequencyType = CalendarUtils.getFrequency(this.recurrence);
        Integer interval = CalendarUtils.getInterval(this.recurrence);
        Integer repeatsOnDay = null;

        /*
         * Repeats on day, need to derive based on the start date
         */

        if (calendarFrequencyType.isWeekly()) {
            repeatsOnDay = newMeetingStartDate.getDayOfWeek();
        } else if (calendarFrequencyType.isMonthly()) {
            repeatsOnDay = newMeetingStartDate.getDayOfMonth();
        }

        // TODO cover other recurrence also

        this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay);

    }

    return actualChanges;

}

From source file:org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData.java

License:Apache License

private boolean occursBefore(final LocalDate date, final LocalDate target) {
    return target != null && target.isBefore(date);
}

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

License:Apache License

/**
 * Creates a loanTransaction for "Apply Charge Event" with transaction date
 * set to "suppliedTransactionDate". The newly created transaction is also
 * added to the Loan on which this method is called.
 * // w  ww.  java  2 s.  c o  m
 * If "suppliedTransactionDate" is not passed Id, the transaction date is
 * set to the loans due date if the due date is lesser than todays date. If
 * not, the transaction date is set to todays date
 * 
 * @param loanCharge
 * @param suppliedTransactionDate
 * @return
 */
public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge,
        final LocalDate suppliedTransactionDate, final AppUser currentUser) {
    final Money chargeAmount = loanCharge.getAmount(getCurrency());
    Money feeCharges = chargeAmount;
    Money penaltyCharges = Money.zero(loanCurrency());
    if (loanCharge.isPenaltyCharge()) {
        penaltyCharges = chargeAmount;
        feeCharges = Money.zero(loanCurrency());
    }

    LocalDate transactionDate = null;

    if (suppliedTransactionDate != null) {
        transactionDate = suppliedTransactionDate;
    } else {
        transactionDate = loanCharge.getDueLocalDate();
        final LocalDate currentDate = DateUtils.getLocalDateOfTenant();

        // if loan charge is to be applied on a future date, the loan
        // transaction would show todays date as applied date
        if (transactionDate == null || currentDate.isBefore(transactionDate)) {
            transactionDate = currentDate;
        }
    }

    final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(),
            chargeAmount, transactionDate, feeCharges, penaltyCharges, DateUtils.getLocalDateTimeOfTenant(),
            currentUser);
    Integer installmentNumber = null;
    final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge,
            loanCharge.getAmount(getCurrency()).getAmount(), installmentNumber);
    applyLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
    this.loanTransactions.add(applyLoanChargeTransaction);
    return applyLoanChargeTransaction;
}

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

License:Apache License

private BigDecimal constructFloatingInterestRates(final BigDecimal annualNominalInterestRate,
        final FloatingRateDTO floatingRateDTO, final List<LoanTermVariationsData> loanTermVariations) {
    final LocalDate dateValue = null;
    final boolean isSpecificToInstallment = false;
    BigDecimal interestRate = annualNominalInterestRate;
    if (loanProduct.isLinkedToFloatingInterestRate()) {
        Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
        LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
        for (FloatingRatePeriodData periodData : applicableRates) {
            LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
                    LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE),
                    periodData.getFromDateAsLocalDate(), periodData.getInterestRate(), dateValue,
                    isSpecificToInstallment);
            if (!interestRateStartDate.isBefore(periodData.getFromDateAsLocalDate())) {
                interestRateStartDate = periodData.getFromDateAsLocalDate();
                interestRate = periodData.getInterestRate();
            }/*www  . j a va 2s.c o m*/
            loanTermVariations.add(loanTermVariation);
        }
    }
    return interestRate;
}

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

License:Apache License

private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate,
        final AppUser currentUser) {

    // add repayment transaction to track incoming money from client to mfi
    // for (charges due at time of disbursement)

    /***//from  w w  w.ja  va  2  s.com
     * TODO Vishwas: do we need to be able to pass in payment type details
     * for repayments at disbursements too?
     ***/

    final Money totalFeeChargesDueAtDisbursement = this.summary
            .getTotalFeeChargesDueAtDisbursement(loanCurrency());
    /**
     * all Charges repaid at disbursal is marked as repaid and
     * "APPLY Charge" transactions are created for all other fees ( which
     * are created during disbursal but not repaid)
     **/

    Money disbursentMoney = Money.zero(getCurrency());
    final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney,
            null, disbursedOn, null, createdDate, currentUser);
    final Integer installmentNumber = null;
    for (final LoanCharge charge : charges()) {
        Date actualDisbursementDate = getActualDisbursementDate(charge);
        if (charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()
                || (charge.getCharge().getChargeTimeType() == ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()
                        && disbursedOn.equals(new LocalDate(actualDisbursementDate))
                        && actualDisbursementDate != null && !charge.isWaived() && !charge.isFullyPaid())) {
            if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()
                    && !charge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
                charge.markAsFullyPaid();
                // Add "Loan Charge Paid By" details to this transaction
                final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge,
                        charge.amount(), installmentNumber);
                chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
                disbursentMoney = disbursentMoney.plus(charge.amount());
            }
        } else if (disbursedOn.equals(new LocalDate(this.actualDisbursementDate))) {
            /**
             * create a Charge applied transaction if Up front Accrual, None
             * or Cash based accounting is enabled
             **/
            if (isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
                handleChargeAppliedTransaction(charge, disbursedOn, currentUser);
            }
        }
    }

    if (disbursentMoney.isGreaterThanZero()) {
        final Money zero = Money.zero(getCurrency());
        chargesPayment.updateComponentsAndTotal(zero, zero, disbursentMoney, zero);
        chargesPayment.updateLoan(this);
        this.loanTransactions.add(chargesPayment);
        updateLoanOutstandingBalaces();
    }

    if (getApprovedOnDate() != null && disbursedOn.isBefore(getApprovedOnDate())) {
        final String errorMessage = "The date on which a loan is disbursed cannot be before its approval date: "
                + getApprovedOnDate().toString();
        throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.before.approval.date",
                errorMessage, disbursedOn, getApprovedOnDate());
    }

    if (getExpectedFirstRepaymentOnDate() != null
            && (disbursedOn.isAfter(this.fetchRepaymentScheduleInstallment(1).getDueDate())
                    || disbursedOn.isAfter(getExpectedFirstRepaymentOnDate()))
            && disbursedOn.toDate().equals(this.actualDisbursementDate)) {
        final String errorMessage = "submittedOnDate cannot be after the loans  expectedFirstRepaymentOnDate: "
                + getExpectedFirstRepaymentOnDate().toString();
        throw new InvalidLoanStateTransitionException("disbursal",
                "cannot.be.after.expected.first.repayment.date", errorMessage, disbursedOn,
                getExpectedFirstRepaymentOnDate());
    }

    validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSED, disbursedOn);

    if (disbursedOn.isAfter(new LocalDate())) {
        final String errorMessage = "The date on which a loan with identifier : " + this.accountNumber
                + " is disbursed cannot be in the future.";
        throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.a.future.date", errorMessage,
                disbursedOn);
    }

}

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

License:Apache License

private ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(
        final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine,
        final LoanTransaction adjustedTransaction, final ScheduleGeneratorDTO scheduleGeneratorDTO,
        final AppUser currentUser) {

    ChangedTransactionDetail changedTransactionDetail = null;

    LoanStatus statusEnum = null;/*from  w  w w.j a  v  a  2 s .  c  om*/

    LocalDate recalculateFrom = loanTransaction.getTransactionDate();
    if (adjustedTransaction != null && adjustedTransaction.getTransactionDate().isBefore(recalculateFrom)) {
        recalculateFrom = adjustedTransaction.getTransactionDate();
    }

    if (loanTransaction.isRecoveryRepayment()) {
        statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RECOVERY_PAYMENT,
                LoanStatus.fromInt(this.loanStatus));
    } else {
        statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
                LoanStatus.fromInt(this.loanStatus));
    }

    this.loanStatus = statusEnum.getValue();

    loanTransaction.updateLoan(this);

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

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

    if (loanTransaction.isNotRepayment() && loanTransaction.isNotWaiver()
            && loanTransaction.isNotRecoveryRepayment()) {
        final String errorMessage = "A transaction of type repayment or recovery repayment or waiver was expected but not received.";
        throw new InvalidLoanTransactionTypeException("transaction",
                "is.not.a.repayment.or.waiver.or.recovery.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 (loanTransaction.isInterestWaiver()) {
        Money totalInterestOutstandingOnLoan = getTotalInterestOutstandingOnLoan();
        if (adjustedTransaction != null) {
            totalInterestOutstandingOnLoan = totalInterestOutstandingOnLoan
                    .plus(adjustedTransaction.getAmount(loanCurrency()));
        }
        if (loanTransaction.getAmount(loanCurrency()).isGreaterThan(totalInterestOutstandingOnLoan)) {
            final String errorMessage = "The amount of interest to waive cannot be greater than total interest outstanding on loan.";
            throw new InvalidLoanStateTransitionException("waive.interest",
                    "amount.exceeds.total.outstanding.interest", errorMessage,
                    loanTransaction.getAmount(loanCurrency()), totalInterestOutstandingOnLoan.getAmount());
        }
    }

    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);

    final LoanRepaymentScheduleInstallment currentInstallment = fetchLoanRepaymentScheduleInstallment(
            loanTransaction.getTransactionDate());
    boolean reprocess = true;

    if (isTransactionChronologicallyLatest && adjustedTransaction == null
            && loanTransaction.getTransactionDate().isEqual(LocalDate.now()) && currentInstallment != null
            && currentInstallment.getTotalOutstanding(getCurrency())
                    .isEqualTo(loanTransaction.getAmount(getCurrency()))) {
        reprocess = false;
    }

    if (isTransactionChronologicallyLatest && adjustedTransaction == null
            && (!reprocess || !this.repaymentScheduleDetail().isInterestRecalculationEnabled())) {
        loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(),
                this.repaymentScheduleInstallments, charges());
        reprocess = false;
        if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
            if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
                reprocess = true;
            } else {
                final LoanRepaymentScheduleInstallment nextInstallment = fetchRepaymentScheduleInstallment(
                        currentInstallment.getInstallmentNumber() + 1);
                if (nextInstallment != null
                        && nextInstallment.getTotalPaidInAdvance(getCurrency()).isGreaterThanZero()) {
                    reprocess = true;
                }
            }
        }
    }
    if (reprocess) {
        if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
            regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
        }
        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);
        }
        /***
         * Commented since throwing exception if external id present for one
         * of the transactions. for this need to save the reversed
         * transactions first and then new transactions.
         */
        this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
    }

    updateLoanSummaryDerivedFields();

    /**
     * FIXME: Vishwas, skipping post loan transaction checks for Loan
     * recoveries
     **/
    if (loanTransaction.isNotRecoveryRepayment()) {
        doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
    }

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

    if (changedTransactionDetail != null) {
        this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values());
    }
    return changedTransactionDetail;
}

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

License:Apache License

public ChangedTransactionDetail closeAsWrittenOff(final JsonCommand command,
        final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes,
        final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
        final AppUser currentUser, final ScheduleGeneratorDTO scheduleGeneratorDTO) {

    final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
            .determineProcessor(this.transactionProcessingStrategy);
    ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO,
            loanRepaymentScheduleTransactionProcessor, currentUser);

    validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING);

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

    LoanTransaction loanTransaction = null;
    if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
        this.loanStatus = statusEnum.getValue();
        changes.put("status", LoanEnumerations.status(this.loanStatus));

        existingTransactionIds.addAll(findExistingTransactionIds());
        existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());

        final LocalDate writtenOffOnLocalDate = command.localDateValueOfParameterNamed("transactionDate");
        final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");

        this.closedOnDate = writtenOffOnLocalDate.toDate();
        this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
        this.closedBy = currentUser;
        changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));
        changes.put("writtenOffOnDate", command.stringValueOfParameterNamed("transactionDate"));

        if (writtenOffOnLocalDate.isBefore(getDisbursementDate())) {
            final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: "
                    + getDisbursementDate().toString();
            throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.before.submittal.date",
                    errorMessage, writtenOffOnLocalDate, getDisbursementDate());
        }/*from w w  w  .ja v  a  2s  .co m*/

        validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.WRITE_OFF_OUTSTANDING,
                writtenOffOnLocalDate);

        if (writtenOffOnLocalDate.isAfter(DateUtils.getLocalDateOfTenant())) {
            final String errorMessage = "The date on which a loan is written off cannot be in the future.";
            throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage,
                    writtenOffOnLocalDate);
        }

        LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
        loanTransaction = LoanTransaction.writeoff(this, getOffice(), writtenOffOnLocalDate, txnExternalId,
                createdDate, currentUser);
        LocalDate lastTransactionDate = getLastUserTransactionDate();
        if (lastTransactionDate.isAfter(writtenOffOnLocalDate)) {
            final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
            throw new InvalidLoanStateTransitionException("writeoff",
                    "must.occur.on.or.after.other.transaction.dates", errorMessage, writtenOffOnLocalDate);
        }

        this.loanTransactions.add(loanTransaction);

        loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
                this.repaymentScheduleInstallments);

        updateLoanSummaryDerivedFields();
    }
    if (changedTransactionDetail == null) {
        changedTransactionDetail = new ChangedTransactionDetail();
    }
    changedTransactionDetail.getNewTransactionMappings().put(0L, loanTransaction);
    return changedTransactionDetail;
}

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

License:Apache License

public ChangedTransactionDetail close(final JsonCommand command,
        final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes,
        final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
        final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {

    validateAccountStatus(LoanEvent.LOAN_CLOSED);

    existingTransactionIds.addAll(findExistingTransactionIds());
    existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());

    final LocalDate closureDate = command.localDateValueOfParameterNamed("transactionDate");
    final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");

    this.closedOnDate = closureDate.toDate();
    changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));

    validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.REPAID_IN_FULL, closureDate);
    if (closureDate.isBefore(getDisbursementDate())) {
        final String errorMessage = "The date on which a loan is closed cannot be before the loan disbursement date: "
                + getDisbursementDate().toString();
        throw new InvalidLoanStateTransitionException("close", "cannot.be.before.submittal.date", errorMessage,
                closureDate, getDisbursementDate());
    }//from w  w  w . ja  v a  2 s.c om

    if (closureDate.isAfter(DateUtils.getLocalDateOfTenant())) {
        final String errorMessage = "The date on which a loan is closed cannot be in the future.";
        throw new InvalidLoanStateTransitionException("close", "cannot.be.a.future.date", errorMessage,
                closureDate);
    }
    final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
            .determineProcessor(this.transactionProcessingStrategy);
    ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO,
            loanRepaymentScheduleTransactionProcessor, currentUser);

    LoanTransaction loanTransaction = null;
    if (isOpen()) {
        final Money totalOutstanding = this.summary.getTotalOutstanding(loanCurrency());
        if (totalOutstanding.isGreaterThanZero()
                && getInArrearsTolerance().isGreaterThanOrEqualTo(totalOutstanding)) {

            final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL,
                    LoanStatus.fromInt(this.loanStatus));
            if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
                this.loanStatus = statusEnum.getValue();
                changes.put("status", LoanEnumerations.status(this.loanStatus));
            }
            this.closedOnDate = closureDate.toDate();
            loanTransaction = LoanTransaction.writeoff(this, getOffice(), closureDate, txnExternalId,
                    DateUtils.getLocalDateTimeOfTenant(), currentUser);
            final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction,
                    this.loanTransactions);
            if (!isLastTransaction) {
                final String errorMessage = "The closing date of the loan must be on or after latest transaction date.";
                throw new InvalidLoanStateTransitionException("close.loan",
                        "must.occur.on.or.after.latest.transaction.date", errorMessage, closureDate);
            }

            this.loanTransactions.add(loanTransaction);

            loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
                    this.repaymentScheduleInstallments);

            updateLoanSummaryDerivedFields();
        } else if (totalOutstanding.isGreaterThanZero()) {
            final String errorMessage = "A loan with money outstanding cannot be closed";
            throw new InvalidLoanStateTransitionException("close", "loan.has.money.outstanding", errorMessage,
                    totalOutstanding.toString());
        }
    }

    if (isOverPaid()) {
        final Money totalLoanOverpayment = calculateTotalOverpayment();
        if (totalLoanOverpayment.isGreaterThanZero()
                && getInArrearsTolerance().isGreaterThanOrEqualTo(totalLoanOverpayment)) {
            // TODO - KW - technically should set somewhere that this loan
            // has
            // 'overpaid' amount
            final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL,
                    LoanStatus.fromInt(this.loanStatus));
            if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
                this.loanStatus = statusEnum.getValue();
                changes.put("status", LoanEnumerations.status(this.loanStatus));
            }
            this.closedOnDate = closureDate.toDate();
        } else if (totalLoanOverpayment.isGreaterThanZero()) {
            final String errorMessage = "The loan is marked as 'Overpaid' and cannot be moved to 'Closed (obligations met).";
            throw new InvalidLoanStateTransitionException("close", "loan.is.overpaid", errorMessage,
                    totalLoanOverpayment.toString());
        }
    }

    if (changedTransactionDetail == null) {
        changedTransactionDetail = new ChangedTransactionDetail();
    }
    changedTransactionDetail.getNewTransactionMappings().put(0L, loanTransaction);
    return changedTransactionDetail;
}

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,
        final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate,
        final LocalDate newMeetingDate) {

    // first repayment's from date is same as disbursement date.
    /*/* ww  w. j a  va  2s. 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;
    for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {

        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);
            }

            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();
    }
}