Example usage for org.joda.time LocalDate isAfter

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

Introduction

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

Prototype

public boolean isAfter(ReadablePartial partial) 

Source Link

Document

Is this partial later than the specified partial.

Usage

From source file:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
        final JsonArray disbursementDataArray, final LoanLifecycleStateMachine loanLifecycleStateMachine) {

    validateAccountStatus(LoanEvent.LOAN_APPROVED);

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

    /*//from w  w w .j  a va  2s  . co m
     * statusEnum is holding the possible new status derived from
     * loanLifecycleStateMachine.transition.
     */

    final LoanStatus newStatusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_APPROVED,
            LoanStatus.fromInt(this.loanStatus));

    /*
     * FIXME: There is no need to check below condition, if
     * loanLifecycleStateMachine.transition is doing it's responsibility
     * properly. Better implementation approach is, if code passes invalid
     * combination of states (fromState and toState), state machine should
     * return invalidate state and below if condition should check for not
     * equal to invalidateState, instead of check new value is same as
     * present value.
     */

    if (!newStatusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
        this.loanStatus = newStatusEnum.getValue();
        actualChanges.put("status", LoanEnumerations.status(this.loanStatus));

        // only do below if status has changed in the 'approval' case
        LocalDate approvedOn = command.localDateValueOfParameterNamed("approvedOnDate");
        String approvedOnDateChange = command.stringValueOfParameterNamed("approvedOnDate");
        if (approvedOn == null) {
            approvedOn = command.localDateValueOfParameterNamed("eventDate");
            approvedOnDateChange = command.stringValueOfParameterNamed("eventDate");
        }

        LocalDate expecteddisbursementDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");

        BigDecimal approvedLoanAmount = command
                .bigDecimalValueOfParameterNamed(LoanApiConstants.approvedLoanAmountParameterName);

        if (approvedLoanAmount != null) {

            // Approved amount has to be less than or equal to principal
            // amount demanded

            if (approvedLoanAmount.compareTo(this.proposedPrincipal) == -1) {

                this.approvedPrincipal = approvedLoanAmount;

                /*
                 * All the calculations are done based on the principal
                 * amount, so it is necessary to set principal amount to
                 * approved amount
                 */

                this.loanRepaymentScheduleDetail.setPrincipal(approvedLoanAmount);

                actualChanges.put(LoanApiConstants.approvedLoanAmountParameterName, approvedLoanAmount);
                actualChanges.put(LoanApiConstants.disbursementPrincipalParameterName, approvedLoanAmount);
            } else if (approvedLoanAmount.compareTo(this.proposedPrincipal) == 1) {
                final String errorMessage = "Loan approved amount can't be greater than loan amount demanded.";
                throw new InvalidLoanStateTransitionException("approval",
                        "amount.can't.be.greater.than.loan.amount.demanded", errorMessage,
                        this.proposedPrincipal, approvedLoanAmount);
            }

            /* Update disbursement details */
            if (disbursementDataArray != null) {
                updateDisbursementDetails(command, actualChanges);
            }
        }
        if (loanProduct.isMultiDisburseLoan()) {
            recalculateAllCharges();

            if (this.disbursementDetails.isEmpty()) {
                final String errorMessage = "For this loan product, disbursement details must be provided";
                throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName,
                        errorMessage);
            }

            if (this.disbursementDetails.size() > loanProduct.maxTrancheCount()) {
                final String errorMessage = "Number of tranche shouldn't be greter than "
                        + loanProduct.maxTrancheCount();
                throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName,
                        errorMessage, loanProduct.maxTrancheCount(), disbursementDetails.size());
            }
        }
        this.approvedOnDate = approvedOn.toDate();
        this.approvedBy = currentUser;
        actualChanges.put("locale", command.locale());
        actualChanges.put("dateFormat", command.dateFormat());
        actualChanges.put("approvedOnDate", approvedOnDateChange);

        final LocalDate submittalDate = new LocalDate(this.submittedOnDate);
        if (approvedOn.isBefore(submittalDate)) {
            final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: "
                    + submittalDate.toString();
            throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date",
                    errorMessage, getApprovedOnDate(), submittalDate);
        }

        if (expecteddisbursementDate != null) {
            this.expectedDisbursementDate = expecteddisbursementDate.toDate();
            actualChanges.put("expectedDisbursementDate", expectedDisbursementDate);

            if (expecteddisbursementDate.isBefore(approvedOn)) {
                final String errorMessage = "The expected disbursement date should be either on or after the approval date: "
                        + approvedOn.toString();
                throw new InvalidLoanStateTransitionException("expecteddisbursal",
                        "should.be.on.or.after.approval.date", errorMessage, getApprovedOnDate(),
                        expecteddisbursementDate);
            }
        }

        validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_APPROVED, approvedOn);

        if (approvedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
            final String errorMessage = "The date on which a loan is approved cannot be in the future.";
            throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage,
                    getApprovedOnDate());
        }

        if (this.loanOfficer != null) {
            final LoanOfficerAssignmentHistory loanOfficerAssignmentHistory = LoanOfficerAssignmentHistory
                    .createNew(this, this.loanOfficer, approvedOn);
            this.loanOfficerHistory.add(loanOfficerAssignmentHistory);
        }
    }

    return actualChanges;
}

From source file:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

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

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

    /***//from w w  w.ja  va2 s .  co  m
     * 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,
            paymentDetail, disbursedOn, null, createdDate, currentUser);
    final Integer installmentNumber = null;
    for (final LoanCharge charge : charges()) {
        Date actualDisbursementDate = getActualDisbursementDate(charge);
        if ((charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()
                && disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null
                && !charge.isWaived() && !charge.isFullyPaid())
                || (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);
        addLoanTransaction(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:com.gst.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;/*  w ww.  j ava2  s .com*/

    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,
            getLoanTransactions());

    if (loanTransaction.isNotZero(loanCurrency())) {
        addLoanTransaction(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 (!isForeclosure() && isTransactionChronologicallyLatest && adjustedTransaction == null
            && loanTransaction.getTransactionDate().isEqual(DateUtils.getLocalDateOfTenant())
            && currentInstallment != null && currentInstallment.getTotalOutstanding(getCurrency())
                    .isEqualTo(loanTransaction.getAmount(getCurrency()))) {
        reprocess = false;
    }

    if (isTransactionChronologicallyLatest && adjustedTransaction == null
            && (!reprocess || !this.repaymentScheduleDetail().isInterestRecalculationEnabled())
            && !isForeclosure()) {
        loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(),
                getRepaymentScheduleInstallments(), 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(),
                getRepaymentScheduleInstallments(), 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:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

public LocalDate possibleNextRepaymentDate() {
    LocalDate earliestUnpaidInstallmentDate = new LocalDate();
    List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
    for (final LoanRepaymentScheduleInstallment installment : installments) {
        if (installment.isNotFullyPaidOff()) {
            earliestUnpaidInstallmentDate = installment.getDueDate();
            break;
        }//from  w w w. j av  a 2 s  .co  m
    }

    LocalDate lastTransactionDate = null;
    for (final LoanTransaction transaction : this.loanTransactions) {
        if (transaction.isRepayment() && transaction.isNonZero()) {
            lastTransactionDate = transaction.getTransactionDate();
        }
    }

    LocalDate possibleNextRepaymentDate = earliestUnpaidInstallmentDate;
    if (lastTransactionDate != null && lastTransactionDate.isAfter(earliestUnpaidInstallmentDate)) {
        possibleNextRepaymentDate = lastTransactionDate;
    }

    return possibleNextRepaymentDate;
}

From source file:com.gst.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 www .  ja  v  a2 s . c  o  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);
        }

        addLoanTransaction(loanTransaction);
        loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
                getRepaymentScheduleInstallments());

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

From source file:com.gst.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  www  . 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,
                    getLoanTransactions());
            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);
            }

            addLoanTransaction(loanTransaction);
            loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
                    getRepaymentScheduleInstallments());

            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:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

/**
 * Behaviour added to comply with capability of previous mifos product to
 * support easier transition to fineract platform.
 *//*from ww  w.j  av a  2s.  c om*/
public void closeAsMarkedForReschedule(final JsonCommand command,
        final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {

    final LocalDate rescheduledOn = command.localDateValueOfParameterNamed("transactionDate");

    final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE,
            LoanStatus.fromInt(this.loanStatus));
    if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
        this.loanStatus = statusEnum.getValue();
        changes.put("status", LoanEnumerations.status(this.loanStatus));
    }

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

    final LocalDate rescheduledOnLocalDate = new LocalDate(this.rescheduledOnDate);
    if (rescheduledOnLocalDate.isBefore(getDisbursementDate())) {
        final String errorMessage = "The date on which a loan is rescheduled cannot be before the loan disbursement date: "
                + getDisbursementDate().toString();
        throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.before.submittal.date",
                errorMessage, rescheduledOnLocalDate, getDisbursementDate());
    }

    if (rescheduledOnLocalDate.isAfter(new LocalDate())) {
        final String errorMessage = "The date on which a loan is rescheduled cannot be in the future.";
        throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.a.future.date",
                errorMessage, rescheduledOnLocalDate);
    }
}

From source file:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

private void validateUnassignDate(final LoanOfficerAssignmentHistory latestHistoryRecord,
        final LocalDate unassignDate) {

    final LocalDate today = DateUtils.getLocalDateOfTenant();

    if (latestHistoryRecord.getStartDate().isAfter(unassignDate)) {

        final String errorMessage = "The Loan officer Unassign date(" + unassignDate
                + ") cannot be before its assignment date (" + latestHistoryRecord.getStartDate() + ").";

        throw new LoanOfficerUnassignmentDateException("cannot.be.before.assignment.date", errorMessage,
                getId(), getLoanOfficer().getId(), latestHistoryRecord.getStartDate(), unassignDate);

    } else if (unassignDate.isAfter(today)) {

        final String errorMessage = "The Loan Officer Unassign date (" + unassignDate
                + ") cannot be in the future.";

        throw new LoanOfficerUnassignmentDateException("cannot.be.a.future.date", errorMessage, unassignDate);
    }/* ww  w.j  a va  2  s. c  om*/
}

From source file:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
        final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
        final Boolean reschedulebasedOnMeetingDates, final LocalDate presentMeetingDate,
        final LocalDate newMeetingDate, final boolean isSkipRepaymentonfirstdayofmonth,
        final Integer numberofDays) {

    // first repayment's from date is same as disbursement date.
    /*/*from w  ww  .j av  a 2 s.  c  o m*/
     * meetingStartDate is used as seedDate Capture the seedDate from user
     * and use the seedDate as meetingStart date
     */

    LocalDate tmpFromDate = getDisbursementDate();
    final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail
            .getRepaymentPeriodFrequencyType();
    final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery();
    final String frequency = CalendarUtils
            .getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);

    LocalDate newRepaymentDate = null;
    Boolean isFirstTime = true;
    LocalDate latestRepaymentDate = null;
    List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
    for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {

        LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();

        if (oldDueDate.isEqual(presentMeetingDate) || oldDueDate.isAfter(presentMeetingDate)) {

            if (isFirstTime) {

                isFirstTime = false;
                newRepaymentDate = newMeetingDate;

            } else {
                // tmpFromDate.plusDays(1) is done to make sure
                // getNewRepaymentMeetingDate method returns next meeting
                // date and not the same as tmpFromDate
                newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, tmpFromDate,
                        tmpFromDate.plusDays(1), loanRepaymentInterval, frequency, workingDays,
                        isSkipRepaymentonfirstdayofmonth, numberofDays);
            }

            if (isHolidayEnabled) {
                newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate,
                        holidays);
            }
            if (latestRepaymentDate == null || latestRepaymentDate.isBefore(newRepaymentDate)) {
                latestRepaymentDate = newRepaymentDate;
            }
            loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
            // reset from date to get actual daysInPeriod

            if (!isFirstTime) {
                loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
            }

            tmpFromDate = newRepaymentDate;// update with new repayment
            // date
        } else {
            tmpFromDate = oldDueDate;
        }
    }
    if (latestRepaymentDate != null) {
        this.expectedMaturityDate = latestRepaymentDate.toDate();
    }
}

From source file:com.gst.portfolio.loanaccount.domain.Loan.java

License:Apache License

public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
        final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
        final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {

    // 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;
    List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
    for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {

        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, isSkipRepaymentonfirstdayofmonth,
                    numberofDays);//from   w w  w . j a v a  2  s  .c om

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

            if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) {
                newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate,
                        tmpFromDate, loanRepaymentInterval, frequency, workingDays,
                        isSkipRepaymentonfirstdayofmonth, numberofDays);
            }

            if (isHolidayEnabled) {
                newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate,
                        holidays);
            }
            if (latestRepaymentDate == null || latestRepaymentDate.isBefore(newRepaymentDate)) {
                latestRepaymentDate = newRepaymentDate;
            }

            loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
            // reset from date to get actual daysInPeriod
            loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
            tmpFromDate = newRepaymentDate;// update with new repayment
            // date
        } else {
            tmpFromDate = oldDueDate;
        }
    }
    if (latestRepaymentDate != null) {
        this.expectedMaturityDate = latestRepaymentDate.toDate();
    }
}