org.mifos.clientportfolio.loan.ui.LoanAccountController.java Source code

Java tutorial

Introduction

Here is the source code for org.mifos.clientportfolio.loan.ui.LoanAccountController.java

Source

/*
 * Copyright (c) 2005-2011 Grameen Foundation USA
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * See also http://www.apache.org/licenses/LICENSE-2.0.html for an
 * explanation of the license and how it is applied.
 */

package org.mifos.clientportfolio.loan.ui;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.mifos.application.admin.servicefacade.AdminServiceFacade;
import org.mifos.application.servicefacade.LoanAccountServiceFacade;
import org.mifos.clientportfolio.loan.service.CreateLoanSchedule;
import org.mifos.clientportfolio.loan.service.RecurringSchedule;
import org.mifos.clientportfolio.loan.ui.helper.LoanControllerHelper;
import org.mifos.clientportfolio.newloan.applicationservice.CreateGlimLoanAccount;
import org.mifos.clientportfolio.newloan.applicationservice.CreateLoanAccount;
import org.mifos.clientportfolio.newloan.applicationservice.GroupMemberAccountDto;
import org.mifos.clientportfolio.newloan.applicationservice.LoanAccountCashFlow;
import org.mifos.clientportfolio.newloan.applicationservice.LoanApplicationStateDto;
import org.mifos.core.MifosRuntimeException;
import org.mifos.dto.domain.CashFlowDto;
import org.mifos.dto.domain.CreateAccountFeeDto;
import org.mifos.dto.domain.CreateAccountPenaltyDto;
import org.mifos.dto.domain.CustomerSearchDto;
import org.mifos.dto.domain.CustomerSearchResultDto;
import org.mifos.dto.domain.FeeDto;
import org.mifos.dto.domain.LoanAccountDetailsDto;
import org.mifos.dto.domain.LoanCreationInstallmentDto;
import org.mifos.dto.domain.LoanPaymentDto;
import org.mifos.dto.domain.MandatoryHiddenFieldsDto;
import org.mifos.dto.domain.MonthlyCashFlowDto;
import org.mifos.dto.domain.PenaltyDto;
import org.mifos.dto.screen.CashFlowDataDto;
import org.mifos.dto.screen.CustomerSearchResultsDto;
import org.mifos.dto.screen.LoanCreationLoanDetailsDto;
import org.mifos.dto.screen.LoanCreationProductDetailsDto;
import org.mifos.dto.screen.LoanCreationResultDto;
import org.mifos.dto.screen.LoanInstallmentsDto;
import org.mifos.dto.screen.LoanScheduleDto;
import org.mifos.dto.screen.SearchDetailsDto;
import org.mifos.dto.screen.UploadedFileDto;
import org.mifos.platform.questionnaire.service.InformationOrderServiceFacade;
import org.mifos.platform.questionnaire.service.QuestionGroupDetail;
import org.mifos.platform.validations.ErrorEntry;
import org.mifos.service.BusinessRuleException;
import org.mifos.ui.core.controller.util.helpers.LoanCreationHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

@SuppressWarnings("PMD")
@Controller
public class LoanAccountController {

    private final LoanAccountServiceFacade loanAccountServiceFacade;
    private final AdminServiceFacade adminServiceFacade;
    private LoanCreationLoanDetailsDto dto;
    private LoanControllerHelper loanControllerHelper;

    @Autowired
    private InformationOrderServiceFacade informationOrderServiceFacade;

    @Autowired
    public LoanAccountController(LoanAccountServiceFacade loanAccountServiceFacade,
            AdminServiceFacade adminServiceFacade, LoanControllerHelper loanControllerHelper) {
        this.loanAccountServiceFacade = loanAccountServiceFacade;
        this.adminServiceFacade = adminServiceFacade;
        this.loanControllerHelper = loanControllerHelper;
    }

    public void markAsRedoLoanAccount(CustomerSearchFormBean formBean) {
        formBean.setRedoLoanAccount(true);
    }

    public void markAsRedoLoanAccount(LoanAccountFormBean formBean) {
        formBean.setRedoLoanAccount(true);
    }

    public CustomerSearchResultsDto searchCustomers(CustomerSearchFormBean formBean, boolean isNewGLIMCreation) {

        // Search result cap. This is needed until ajax search is implemented.
        Integer searchCap = 1000;

        CustomerSearchDto customerSearchDto = new CustomerSearchDto(formBean.getSearchString(), Integer.valueOf(1),
                searchCap);
        List<CustomerSearchResultDto> pagedDetails = this.loanAccountServiceFacade
                .retrieveCustomersThatQualifyForLoans(customerSearchDto, isNewGLIMCreation);

        //int firstResult = formBean.getPage() * formBean.getPageSize() - (formBean.getPageSize()-1);

        // FIXME selected pageNumber and pageSize info should be passed in on bean.
        SearchDetailsDto searchDetails = new SearchDetailsDto(pagedDetails.size(), 1, 1, searchCap);
        return new CustomerSearchResultsDto(searchDetails, pagedDetails);
    }

    public LoanCreationProductDetailsDto retrieveLoanProducts(int customerId,
            org.springframework.binding.message.MessageContext messageContext) {
        LoanCreationProductDetailsDto loanProductDetails = this.loanAccountServiceFacade
                .retrieveGetProductDetailsForLoanAccountCreation(customerId);

        if (loanProductDetails.getErrors().hasErrors()) {

            List<ErrorEntry> errorList = loanProductDetails.getErrors().getErrorEntries();

            for (int i = 0; i < errorList.size(); i++) {
                MessageBuilder builder = new MessageBuilder().error().source(errorList.get(i).getFieldName())
                        .codes(Arrays.asList(errorList.get(i).getErrorCode()).toArray(new String[1]))
                        .defaultText(errorList.get(i).getDefaultMessage());

                messageContext.addMessage(builder.build());
            }
        }
        return loanProductDetails;
    }

    @SuppressWarnings("PMD")
    public LoanCreationLoanDetailsDto retrieveLoanCreationDetails(int customerId, int productId, String eventId,
            String fileToDelete, LoanAccountFormBean formBean) {

        if ("newFileSelected".equals(eventId)) {
            if (formBean.getSelectedFile() != null) {
                CommonsMultipartFile file = formBean.getSelectedFile();
                formBean.getFiles().add(file);
                formBean.getFilesMetadata().add(new UploadedFileDto(file.getOriginalFilename(),
                        file.getContentType(), (int) file.getSize(), formBean.getSelectedFileDescription()));
            }
            return dto;
        } else if ("fileDeleted".equals(eventId)) {
            if (fileToDelete != null) {
                int index = 0;
                for (CommonsMultipartFile formFile : formBean.getFiles()) {
                    if (formFile.getOriginalFilename().equals(fileToDelete)) {
                        index = formBean.getFiles().indexOf(formFile);
                        break;
                    }
                }
                if (index >= 0) {
                    formBean.getFiles().remove(index);
                    formBean.getFilesMetadata().remove(index);
                }
            }
            return dto;
        }
        MandatoryHiddenFieldsDto mandatoryHidden = this.adminServiceFacade.retrieveHiddenMandatoryFieldsToRead();
        dto = this.loanAccountServiceFacade.retrieveLoanDetailsForLoanAccountCreation(customerId,
                Integer.valueOf(productId).shortValue(), formBean.isRedoLoanAccount());

        formBean.setLocale(Locale.getDefault());

        formBean.setDigitsBeforeDecimalForInterest(dto.getAppConfig().getDigitsBeforeDecimalForInterest());
        formBean.setDigitsAfterDecimalForInterest(dto.getAppConfig().getDigitsAfterDecimalForInterest());
        formBean.setDigitsBeforeDecimalForMonetaryAmounts(
                dto.getAppConfig().getDigitsBeforeDecimalForMonetaryAmounts());
        formBean.setDigitsAfterDecimalForMonetaryAmounts(
                dto.getAppConfig().getDigitsAfterDecimalForMonetaryAmounts());

        formBean.setProductId(productId);
        formBean.setCustomerId(dto.getCustomerDetailDto().getCustomerId());
        formBean.setRepaymentScheduleIndependentOfCustomerMeeting(dto.isRepaymentIndependentOfMeetingEnabled());
        formBean.setGraceDuration(dto.getGracePeriodInInstallments());
        formBean.setMaxGraceDuration(dto.getGracePeriodInInstallments());

        if (dto.isRepaymentIndependentOfMeetingEnabled()) {

            // use loan product to default meeting details
            Integer recursEvery = dto.getLoanOfferingMeetingDetail().getMeetingDetailsDto().getEvery();
            Integer dayOfMonth = dto.getLoanOfferingMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                    .getDayNumber();
            Integer weekOfMonth = dto.getLoanOfferingMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                    .getWeekOfMonth();
            Integer dayOfWeek = dto.getLoanOfferingMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                    .getDayOfWeek();
            Integer recurrenceType = dto.getLoanOfferingMeetingDetail().getMeetingDetailsDto()
                    .getRecurrenceTypeId();

            Integer customerRecurrenceType = dto.getCustomerMeetingDetail().getMeetingDetailsDto()
                    .getRecurrenceTypeId();
            if (recurrenceType.equals(customerRecurrenceType)) {
                // if customer and product meeting frequencies are the same e.g. weekly or monthly, then default to customer details except for recurrence details
                dayOfMonth = dto.getCustomerMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                        .getDayNumber();
                weekOfMonth = dto.getCustomerMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                        .getWeekOfMonth();
                dayOfWeek = dto.getCustomerMeetingDetail().getMeetingDetailsDto().getRecurrenceDetails()
                        .getDayOfWeek();
            }

            // sometimes it seems customer meeting information can be setup wrong (i.e. has a day of month even though its weekly)
            if (recurrenceType == 1) {
                if (dateInformationIsAvailable(dayOfWeek)) {
                    formBean.setWeeklyDetails(dayOfWeek, recursEvery);
                }
            } else if (recurrenceType == 2) {
                if (dateInformationIsAvailable(weekOfMonth) && dateInformationIsAvailable(dayOfWeek)) {
                    formBean.setWeekOfMonthDetails(weekOfMonth, dayOfWeek, recursEvery);
                } else if (dateInformationIsAvailable(dayOfMonth)) {
                    formBean.setDayOfMonthDetails(dayOfMonth, recursEvery);
                }
            } else if (recurrenceType == 3) {
                formBean.setRepaymentRecursEvery(recursEvery);
            }
        }

        formBean.setVariableInstallmentsAllowed(dto.isVariableInstallmentsAllowed());
        if (dto.isVariableInstallmentsAllowed()) {
            formBean.setMinGapInDays(dto.getMinGapInDays());
            formBean.setMaxGapInDays(dto.getMaxGapInDays());
            formBean.setMinInstallmentAmount(dto.getMinInstallmentAmount());
        }
        formBean.setGlimApplicable(dto.isGlimApplicable());
        if (dto.isGroup()) {
            formBean.setGroupLoanWithMembersEnabled(dto.isGroupLoanWithMembersEnabled());
        }
        if (dto.isGlimApplicable() || (dto.isGroup() && dto.isGroupLoanWithMembersEnabled())) {
            List<LoanAccountDetailsDto> clientData = dto.getClientDetails();
            String[] clientGlobalIdArray = new String[clientData.size()];
            int index = 0;
            for (LoanAccountDetailsDto loanAccountDetailsDto : clientData) {
                clientGlobalIdArray[index] = loanAccountDetailsDto.getClientId();
                index++;
            }
            formBean.setClientGlobalId(clientGlobalIdArray);

            formBean.setClientSelectForGroup(new Boolean[clientData.size()]);
            formBean.setClientAmount(new Number[clientData.size()]);
            Integer[] loanPurpose = new Integer[clientData.size()];
            formBean.setClientLoanPurposeId(loanPurpose);

            Number[][] selectedFeeIndividualAmounts = new Number[3][clientData.size()];
            formBean.setSelectedFeeIndividualAmounts(selectedFeeIndividualAmounts);

            Number[][] defaultFeeIndividualAmounts = new Number[dto.getDefaultFees().size()][clientData.size()];
            formBean.setDefaultFeeIndividualAmounts(defaultFeeIndividualAmounts);
        } else {
            formBean.setAmount(Double.valueOf(dto.getDefaultLoanAmount().toPlainString()));
        }

        formBean.setMinAllowedAmount(dto.getMinLoanAmount());
        formBean.setMaxAllowedAmount(dto.getMaxLoanAmount());

        formBean.setInterestRate(dto.getDefaultInterestRate());
        formBean.setMinAllowedInterestRate(dto.getMinInterestRate());
        formBean.setMaxAllowedInterestRate(dto.getMaxInterestRate());

        formBean.setNumberOfInstallments(dto.getDefaultNumberOfInstallments());
        formBean.setMinNumberOfInstallments(dto.getMinNumberOfInstallments());
        formBean.setMaxNumberOfInstallments(dto.getMaxNumberOfInstallments());

        formBean.setSourceOfFundsMandatory(mandatoryHidden.isMandatoryLoanSourceOfFund());
        formBean.setPurposeOfLoanMandatory(mandatoryHidden.isMandatoryLoanAccountPurpose());
        formBean.setCollateralTypeAndNotesHidden(mandatoryHidden.isHideSystemCollateralTypeNotes());
        formBean.setExternalIdHidden(mandatoryHidden.isHideSystemExternalId());
        if (!mandatoryHidden.isHideSystemExternalId()) {
            formBean.setExternalIdMandatory(mandatoryHidden.isMandatorySystemExternalId());
        }

        LocalDate possibleDisbursementDate = dto.getNextPossibleDisbursementDate();
        if (possibleDisbursementDate != null) {
            formBean.setDisbursementDateDD(possibleDisbursementDate.getDayOfMonth());
            formBean.setDisbursementDateMM(possibleDisbursementDate.getMonthOfYear());
            formBean.setDisbursementDateYY(possibleDisbursementDate.getYearOfEra());
        }

        formBean.setCollateralNotes("");

        Number[] defaultFeeId = new Number[dto.getDefaultFees().size()];
        Number[] defaultFeeAmountOrRate = new Number[dto.getDefaultFees().size()];
        int index = 0;
        for (FeeDto defaultFee : dto.getDefaultFees()) {
            if (defaultFee.isRateBasedFee()) {
                defaultFeeAmountOrRate[index] = defaultFee.getRate();
            } else {
                defaultFeeAmountOrRate[index] = defaultFee.getAmountAsNumber();
            }
            defaultFeeId[index] = Long.valueOf(defaultFee.getId());
            index++;
        }
        formBean.setDefaultFeeAmountOrRate(defaultFeeAmountOrRate);
        formBean.setDefaultFeeId(defaultFeeId);
        formBean.setDefaultFeeSelected(new Boolean[dto.getDefaultFees().size()]);
        formBean.setDefaultFees(dto.getDefaultFees());

        Number[] defaultPenaltyId = new Number[dto.getDefaultPenalties().size()];
        Number[] defaultPenaltyAmountOrRate = new Number[dto.getDefaultPenalties().size()];
        int idx = 0;
        for (PenaltyDto defaultPenalty : dto.getDefaultPenalties()) {
            if (defaultPenalty.isRateBasedPenalty()) {
                defaultPenaltyAmountOrRate[idx] = defaultPenalty.getRate();
            } else {
                defaultPenaltyAmountOrRate[idx] = defaultPenalty.getAmountAsNumber();
            }
            defaultPenaltyId[idx] = Long.valueOf(defaultPenalty.getPenaltyId());
            idx++;
        }
        formBean.setDefaultPenaltyAmountOrRate(defaultPenaltyAmountOrRate);
        formBean.setDefaultPenaltyId(defaultPenaltyId);
        formBean.setDefaultPenaltySelected(new Boolean[dto.getDefaultPenalties().size()]);
        formBean.setDefaultPenalties(dto.getDefaultPenalties());

        Number[] selectedFeeId = new Number[3];
        formBean.setSelectedFeeId(selectedFeeId);

        Number[] selectedFeeAmount = new Number[3];
        formBean.setSelectedFeeAmount(selectedFeeAmount);
        formBean.setAdditionalFees(dto.getAdditionalFees());

        if (formBean.getFiles() == null) {
            formBean.setFiles(new ArrayList<CommonsMultipartFile>());
            formBean.setFilesMetadata(new ArrayList<UploadedFileDto>());
        }

        formBean.setLoanInformationOrder(informationOrderServiceFacade.getInformationOrder("CreateLoan"));

        return dto;
    }

    private boolean dateInformationIsAvailable(Integer dayOfWeek) {
        return dayOfWeek != null && dayOfWeek > 0;
    }

    public void loadQuestionGroups(Integer productId,
            LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean) {

        List<QuestionGroupDetail> questionGroups = loanAccountServiceFacade
                .retrieveApplicableQuestionGroups(productId);
        loanAccountQuestionGroupFormBean.setQuestionGroups(questionGroups);
    }

    public boolean isCompareForCashFlowEnabled(Integer productId) {
        return this.loanAccountServiceFacade.isCompareWithCashFlowEnabledOnProduct(productId);
    }

    public LoanScheduleDto retrieveLoanSchedule(int customerId, int productId, LoanAccountFormBean formBean,
            BackdatedPaymentable loanScheduleFormBean, boolean resetRedoLoanAccountDetails) {

        LocalDate disbursementDate = LoanCreationHelper.translateDisbursementDateToLocalDate(formBean);

        RecurringSchedule recurringSchedule = LoanCreationHelper.determineRecurringSchedule(formBean);
        List<CreateAccountFeeDto> accountFees = LoanCreationHelper.translateToAccountFeeDtos(formBean);
        List<CreateAccountFeeDto> additionalAccountFees = LoanCreationHelper
                .translateToAdditionalAccountFeeDtos(formBean);
        accountFees.addAll(additionalAccountFees);

        CreateLoanSchedule createLoanAccount = new CreateLoanSchedule(customerId, productId,
                BigDecimal.valueOf(formBean.getAmount().doubleValue()), formBean.getInterestRate().doubleValue(),
                disbursementDate, formBean.getNumberOfInstallments().intValue(),
                formBean.getGraceDuration().intValue(), formBean.isRepaymentScheduleIndependentOfCustomerMeeting(),
                recurringSchedule, accountFees);

        LoanScheduleDto loanSchedule = null;
        if (formBean.isVariableInstallmentsAllowed() && !loanScheduleFormBean.getInstallments().isEmpty()) {
            loanSchedule = loanAccountServiceFacade.createLoanSchedule(createLoanAccount,
                    loanScheduleFormBean.getInstallments(), loanScheduleFormBean.getInstallmentAmounts());
        } else {
            loanSchedule = loanAccountServiceFacade.createLoanSchedule(createLoanAccount);
        }

        loanControllerHelper.populateFormBeanFromDto(customerId, productId, formBean, loanScheduleFormBean,
                disbursementDate, loanSchedule, resetRedoLoanAccountDetails);

        return loanSchedule;
    }

    public CashFlowDto retrieveCashFlowSettings(LoanScheduleDto loanScheduleDto, int productId) {
        DateTime firstInstallment = loanScheduleDto.firstInstallment();
        DateTime lastInstallment = loanScheduleDto.lastInstallment();
        return loanAccountServiceFacade.retrieveCashFlowSettings(firstInstallment, lastInstallment, productId,
                BigDecimal.valueOf(loanScheduleDto.getLoanAmount()));
    }

    public List<CashFlowDataDto> recalculateCashflowSummaryDetails(CashFlowSummaryFormBean formBean,
            CashFlowDto cashFlowDto, List<MonthlyCashFlowDto> monthlyCashFlow, LoanScheduleDto loanScheduleDto,
            int productId) {

        List<CashFlowDataDto> cashFlowDataDtos = this.loanAccountServiceFacade
                .retrieveCashFlowSummary(monthlyCashFlow, loanScheduleDto);
        formBean.setCashFlowDataDtos(cashFlowDataDtos);
        formBean.setProductId(productId);

        BigDecimal cashFlowTotalBalance = BigDecimal.ZERO;
        for (MonthlyCashFlowDto monthlyCashFlowDto : monthlyCashFlow) {
            cashFlowTotalBalance = cashFlowTotalBalance.add(monthlyCashFlowDto.calculateRevenueMinusExpenses());
        }

        formBean.setMonthlyCashFlows(monthlyCashFlow);
        formBean.setCashFlowTotalBalance(cashFlowTotalBalance);
        formBean.setRepaymentCapacity(cashFlowDto.getRepaymentCapacity());

        return cashFlowDataDtos;
    }

    public List<CashFlowDataDto> retrieveCashflowSummaryDetails(CashFlowSummaryFormBean formBean,
            CashFlowDto cashFlowDto, List<MonthlyCashFlowDto> monthlyCashFlow, LoanScheduleDto loanScheduleDto,
            int productId, LoanAccountFormBean loanAccountFormBean) {

        List<CashFlowDataDto> cashFlowDataDtos = this.loanAccountServiceFacade
                .retrieveCashFlowSummary(monthlyCashFlow, loanScheduleDto);
        formBean.setCashFlowDataDtos(cashFlowDataDtos);
        formBean.setProductId(productId);

        BigDecimal loanAmount = BigDecimal.valueOf(loanScheduleDto.getLoanAmount());
        BigDecimal totalInstallmentAmount = BigDecimal.ZERO;
        DateTime firstInstallmentDueDate = new DateTime();
        DateTime lastInstallmentDueDate = new DateTime();
        List<DateTime> installments = new ArrayList<DateTime>();
        List<Number> installmentAmounts = new ArrayList<Number>();
        if (!loanScheduleDto.getInstallments().isEmpty()) {
            firstInstallmentDueDate = loanScheduleDto.firstInstallment();
            lastInstallmentDueDate = loanScheduleDto.lastInstallment();

            for (LoanCreationInstallmentDto installment : loanScheduleDto.getInstallments()) {
                totalInstallmentAmount = totalInstallmentAmount.add(BigDecimal.valueOf(installment.getTotal()));
                installments.add(new DateTime(installment.getDueDate()));
                installmentAmounts.add(installment.getTotal());
            }
        }

        formBean.setInstallments(installments);
        formBean.setInstallmentAmounts(installmentAmounts);
        formBean.setLoanPrincipal(loanAmount);

        LoanInstallmentsDto loanInstallmentsDto = new LoanInstallmentsDto(loanAmount, totalInstallmentAmount,
                firstInstallmentDueDate.toDate(), lastInstallmentDueDate.toDate());

        BigDecimal cashFlowTotalBalance = BigDecimal.ZERO;
        for (MonthlyCashFlowDto monthlyCashFlowDto : monthlyCashFlow) {
            cashFlowTotalBalance = cashFlowTotalBalance.add(monthlyCashFlowDto.calculateRevenueMinusExpenses());
        }

        formBean.setMonthlyCashFlows(monthlyCashFlow);
        formBean.setLoanInstallmentsDto(loanInstallmentsDto);
        formBean.setCashFlowTotalBalance(cashFlowTotalBalance);
        formBean.setRepaymentCapacity(cashFlowDto.getRepaymentCapacity());

        LocalDate disbursementDate = LoanCreationHelper.translateDisbursementDateToLocalDate(loanAccountFormBean);
        loanControllerHelper.populateFormBeanFromDto(loanAccountFormBean.getCustomerId(), productId,
                loanAccountFormBean, formBean, disbursementDate, loanScheduleDto, true);

        return cashFlowDataDtos;
    }

    public LoanCreationResultDto saveLoanApplicationForLater(LoanAccountFormBean formBean,
            LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
            LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean,
            LoanScheduleFormBean loanScheduleFormBean) {

        LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();

        return submitLoanApplication(applicationState.getPartialApplicationId(), formBean,
                loanAccountQuestionGroupFormBean, loanAccountCashFlow, cashFlowSummaryFormBean,
                loanScheduleFormBean);
    }

    public LoanCreationResultDto submitLoanApplication(LoanAccountFormBean formBean,
            LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
            LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean,
            LoanScheduleFormBean loanScheduleFormBean, MessageContext messageContext) {

        LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();

        try {
            return submitLoanApplication(applicationState.getConfiguredApplicationId(), formBean,
                    loanAccountQuestionGroupFormBean, loanAccountCashFlow, cashFlowSummaryFormBean,
                    loanScheduleFormBean);
        } catch (BusinessRuleException e) {
            MessageBuilder builder = new MessageBuilder().error()
                    .codes(Arrays.asList(e.getMessageKey()).toArray(new String[1])).defaultText(e.getMessage())
                    .args(e.getMessageValues());

            messageContext.addMessage(builder.build());
            throw e;
        }
    }

    public LoanCreationResultDto openLoanWithBackdatedPayments(LoanAccountFormBean formBean,
            LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
            LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean,
            LoanScheduleFormBean loanScheduleFormBean, MessageContext messageContext) {

        LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();

        try {
            return submitLoanWithBackdatedPaymentsApplication(applicationState.getPartialApplicationId(), formBean,
                    loanAccountQuestionGroupFormBean, loanAccountCashFlow, cashFlowSummaryFormBean,
                    loanScheduleFormBean);
        } catch (BusinessRuleException e) {
            MessageBuilder builder = new MessageBuilder().error()
                    .codes(Arrays.asList(e.getMessageKey()).toArray(new String[1])).defaultText(e.getMessage())
                    .args(e.getMessageValues());

            messageContext.addMessage(builder.build());
            throw e;
        }
    }

    private LoanCreationResultDto submitLoanWithBackdatedPaymentsApplication(Integer accountState,
            LoanAccountFormBean formBean, LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
            LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean,
            LoanScheduleFormBean loanScheduleFormBean) {

        LocalDate disbursementDate = LoanCreationHelper.translateDisbursementDateToLocalDate(formBean);
        RecurringSchedule recurringSchedule = LoanCreationHelper.determineRecurringSchedule(formBean);
        List<CreateAccountFeeDto> accountFees = LoanCreationHelper.translateToAccountFeeDtos(formBean);
        List<CreateAccountPenaltyDto> accountPenalties = LoanCreationHelper.translateToAccountPenaltyDtos(formBean);
        List<CreateAccountFeeDto> additionalAccountFees = LoanCreationHelper
                .translateToAdditionalAccountFeeDtos(formBean);
        accountFees.addAll(additionalAccountFees);

        BigDecimal loanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
        BigDecimal minAllowedLoanAmount = BigDecimal.valueOf(formBean.getMinAllowedAmount().doubleValue());
        BigDecimal maxAllowedLoanAmount = BigDecimal.valueOf(formBean.getMaxAllowedAmount().doubleValue());

        CreateLoanAccount loanAccountDetails = new CreateLoanAccount(formBean.getCustomerId(),
                formBean.getProductId(), accountState, loanAmount, minAllowedLoanAmount, maxAllowedLoanAmount,
                formBean.getInterestRate().doubleValue(), disbursementDate, formBean.getDisbursalPaymentTypeId(),
                formBean.getNumberOfInstallments().intValue(), formBean.getMinNumberOfInstallments().intValue(),
                formBean.getMaxNumberOfInstallments().intValue(), formBean.getGraceDuration().intValue(),
                formBean.getFundId(), formBean.getLoanPurposeId(), formBean.getCollateralTypeId(),
                formBean.getCollateralNotes(), formBean.getExternalId(),
                formBean.isRepaymentScheduleIndependentOfCustomerMeeting(), recurringSchedule, accountFees,
                accountPenalties);

        List<LoanPaymentDto> backdatedLoanPayments = new ArrayList<LoanPaymentDto>();
        int index = 0;
        List<Number> actualPaymentAmountDetails = cashFlowSummaryFormBean.getActualPaymentAmounts();
        if (actualPaymentAmountDetails.isEmpty()) {
            actualPaymentAmountDetails = loanScheduleFormBean.getActualPaymentAmounts();
        }
        for (Number actualPaymentAmount : actualPaymentAmountDetails) {
            if (actualPaymentAmount.doubleValue() > 0) {
                LocalDate transactionDate = new LocalDate(loanScheduleFormBean.getActualPaymentDates().get(index));
                backdatedLoanPayments.add(new LoanPaymentDto(actualPaymentAmount.toString(), transactionDate,
                        loanScheduleFormBean.getActualPaymentTypes().get(index), null));
            }
            index++;
        }

        LoanCreationResultDto loanCreationResultDto = null;
        if (formBean.isGlimApplicable()) {

            List<GroupMemberAccountDto> memberAccounts = createGroupMemberAccounts(formBean);
            BigDecimal totalLoanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());

            CreateGlimLoanAccount createGroupLoanAccount = new CreateGlimLoanAccount(memberAccounts,
                    totalLoanAmount, loanAccountDetails);

            loanCreationResultDto = loanAccountServiceFacade.createBackdatedGroupLoanWithIndividualMonitoring(
                    createGroupLoanAccount, backdatedLoanPayments,
                    loanAccountQuestionGroupFormBean.getQuestionGroups(), loanAccountCashFlow);

        } else if (formBean.isVariableInstallmentsAllowed()) {
            List<DateTime> installmentDates = cashFlowSummaryFormBean.getInstallments();
            List<Number> installmentPrincipalAmounts = cashFlowSummaryFormBean.getInstallmentAmounts();
            if (installmentDates.isEmpty()) {
                installmentDates = loanScheduleFormBean.getInstallments();
                installmentPrincipalAmounts = loanScheduleFormBean.getInstallmentAmounts();
            }
            // api for creating loan with premade loan schedule
            loanCreationResultDto = loanAccountServiceFacade.createBackdatedLoan(loanAccountDetails,
                    backdatedLoanPayments, loanAccountQuestionGroupFormBean.getQuestionGroups(),
                    loanAccountCashFlow, installmentDates, installmentPrincipalAmounts);
        } else {
            loanCreationResultDto = loanAccountServiceFacade.createBackdatedLoan(loanAccountDetails,
                    backdatedLoanPayments, loanAccountQuestionGroupFormBean.getQuestionGroups(),
                    loanAccountCashFlow);
        }

        return loanCreationResultDto;
    }

    private LoanCreationResultDto submitLoanApplication(Integer accountState, LoanAccountFormBean formBean,
            LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
            LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean,
            LoanScheduleFormBean loanScheduleFormBean) {

        LocalDate disbursementDate = LoanCreationHelper.translateDisbursementDateToLocalDate(formBean);
        RecurringSchedule recurringSchedule = LoanCreationHelper.determineRecurringSchedule(formBean);
        List<CreateAccountFeeDto> accountFees = LoanCreationHelper.translateToAccountFeeDtos(formBean);
        List<CreateAccountFeeDto> additionalAccountFees = LoanCreationHelper
                .translateToAdditionalAccountFeeDtos(formBean);
        List<CreateAccountPenaltyDto> accountPenalties = LoanCreationHelper.translateToAccountPenaltyDtos(formBean);
        accountFees.addAll(additionalAccountFees);

        BigDecimal loanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
        BigDecimal minAllowedLoanAmount = BigDecimal.valueOf(formBean.getMinAllowedAmount().doubleValue());
        BigDecimal maxAllowedLoanAmount = BigDecimal.valueOf(formBean.getMaxAllowedAmount().doubleValue());

        CreateLoanAccount loanAccountDetails = new CreateLoanAccount(formBean.getCustomerId(),
                formBean.getProductId(), accountState, loanAmount, minAllowedLoanAmount, maxAllowedLoanAmount,
                formBean.getInterestRate().doubleValue(), disbursementDate, null,
                formBean.getNumberOfInstallments().intValue(), formBean.getMinNumberOfInstallments().intValue(),
                formBean.getMaxNumberOfInstallments().intValue(), formBean.getGraceDuration().intValue(),
                formBean.getFundId(), formBean.getLoanPurposeId(), formBean.getCollateralTypeId(),
                formBean.getCollateralNotes(), formBean.getExternalId(),
                formBean.isRepaymentScheduleIndependentOfCustomerMeeting(), recurringSchedule, accountFees,
                accountPenalties);

        LoanCreationResultDto loanCreationResultDto = null;

        if (formBean.isGlimApplicable()) {

            List<GroupMemberAccountDto> memberAccounts = createGroupMemberAccounts(formBean);
            BigDecimal totalLoanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());

            CreateGlimLoanAccount createGroupLoanAccount = new CreateGlimLoanAccount(memberAccounts,
                    totalLoanAmount, loanAccountDetails);

            loanCreationResultDto = loanAccountServiceFacade.createGroupLoanWithIndividualMonitoring(
                    createGroupLoanAccount, loanAccountQuestionGroupFormBean.getQuestionGroups(),
                    loanAccountCashFlow);
        } else {

            if (formBean.isVariableInstallmentsAllowed()) {
                List<DateTime> installmentDates = cashFlowSummaryFormBean.getInstallments();
                List<Number> totalInstallmentAmounts = cashFlowSummaryFormBean.getInstallmentAmounts();
                if (installmentDates.isEmpty()) {
                    installmentDates = loanScheduleFormBean.getInstallments();
                    totalInstallmentAmounts = loanScheduleFormBean.getInstallmentAmounts();
                }
                // api for creating loan with premade loan schedule

                loanCreationResultDto = loanAccountServiceFacade.createLoan(loanAccountDetails,
                        loanAccountQuestionGroupFormBean.getQuestionGroups(), loanAccountCashFlow, installmentDates,
                        totalInstallmentAmounts);
            } else {
                loanCreationResultDto = loanAccountServiceFacade.createLoan(loanAccountDetails,
                        loanAccountQuestionGroupFormBean.getQuestionGroups(), loanAccountCashFlow);
            }
        }

        List<CommonsMultipartFile> formFiles = formBean.getFiles();
        List<UploadedFileDto> filesMetadata = formBean.getFilesMetadata();

        for (int i = 0; i < formFiles.size(); i++) {
            if (formFiles.get(i).getSize() != 0) {
                InputStream inputStream;
                try {
                    inputStream = formFiles.get(i).getInputStream();
                } catch (IOException e) {
                    throw new MifosRuntimeException();
                }
                UploadedFileDto fileMetadata = filesMetadata.get(i);
                loanAccountServiceFacade.uploadFile(loanCreationResultDto.getAccountId(), inputStream,
                        fileMetadata);
            }
        }

        return loanCreationResultDto;
    }

    @SuppressWarnings("PMD")
    private List<GroupMemberAccountDto> createGroupMemberAccounts(LoanAccountFormBean formBean) {

        List<GroupMemberAccountDto> memberAccounts = new ArrayList<GroupMemberAccountDto>();

        int index = 0;
        for (Boolean clientSelected : formBean.getClientSelectForGroup()) {
            if (clientSelected != null && clientSelected.booleanValue()) {
                String globalId = formBean.getClientGlobalId()[index];
                BigDecimal loanAmount = BigDecimal.valueOf(formBean.getClientAmount()[index].doubleValue());
                Integer loanPurposeId = formBean.getClientLoanPurposeId()[index];
                GroupMemberAccountDto memberAccount = new GroupMemberAccountDto(globalId, loanAmount,
                        loanPurposeId);

                memberAccounts.add(memberAccount);
            }
            index++;
        }

        return memberAccounts;
    }
}