/*
* 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.accounts.loan.struts.action;
import static org.mifos.accounts.loan.util.helpers.LoanConstants.METHODCALLED;
import static org.mifos.framework.util.helpers.DateUtils.getUserLocaleDate;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.joda.time.LocalDate;
import org.mifos.accounts.acceptedpaymenttype.persistence.LegacyAcceptedPaymentTypeDao;
import org.mifos.accounts.api.AccountService;
import org.mifos.accounts.business.AccountBO;
import org.mifos.accounts.business.AccountFeesActionDetailEntity;
import org.mifos.accounts.business.service.AccountBusinessService;
import org.mifos.accounts.exceptions.AccountException;
import org.mifos.accounts.fees.util.helpers.RateAmountFlag;
import org.mifos.accounts.loan.business.LoanBO;
import org.mifos.accounts.loan.business.LoanScheduleEntity;
import org.mifos.accounts.loan.struts.actionforms.LoanDisbursementActionForm;
import org.mifos.accounts.loan.util.helpers.LoanConstants;
import org.mifos.accounts.servicefacade.AccountPaymentDto;
import org.mifos.application.master.business.PaymentTypeEntity;
import org.mifos.application.master.util.helpers.MasterConstants;
import org.mifos.application.master.util.helpers.PaymentTypes;
import org.mifos.application.questionnaire.struts.DefaultQuestionnaireServiceFacadeLocator;
import org.mifos.application.questionnaire.struts.QuestionnaireFlowAdapter;
import org.mifos.application.servicefacade.ApplicationContextProvider;
import org.mifos.application.util.helpers.ActionForwards;
import org.mifos.application.util.helpers.TrxnTypes;
import org.mifos.config.AccountingRulesConstants;
import org.mifos.core.MifosRuntimeException;
import org.mifos.dto.domain.AccountPaymentParametersDto;
import org.mifos.dto.domain.AccountReferenceDto;
import org.mifos.dto.domain.CustomerDto;
import org.mifos.dto.domain.PaymentTypeDto;
import org.mifos.dto.domain.UserReferenceDto;
import org.mifos.dto.screen.LoanDisbursalDto;
import org.mifos.dto.screen.LoanInformationDto;
import org.mifos.framework.exceptions.ServiceException;
import org.mifos.framework.struts.action.BaseAction;
import org.mifos.framework.util.helpers.CloseSession;
import org.mifos.framework.util.helpers.Constants;
import org.mifos.framework.util.helpers.DateUtils;
import org.mifos.framework.util.helpers.SessionUtils;
import org.mifos.framework.util.helpers.TransactionDemarcate;
import org.mifos.security.util.UserContext;
import org.mifos.service.BusinessRuleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoanDisbursementAction extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(LoanDisbursementAction.class);
private LegacyAcceptedPaymentTypeDao legacyAcceptedPaymentTypeDao = ApplicationContextProvider
.getBean(LegacyAcceptedPaymentTypeDao.class);
@TransactionDemarcate(joinToken = true)
public ActionForward load(final ActionMapping mapping, final ActionForm form, final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
LoanDisbursementActionForm loanDisbursementActionForm = (LoanDisbursementActionForm) form;
loanDisbursementActionForm.clear();
loanDisbursementActionForm.setAmountCannotBeZero(false);
Integer loanAccountId = Integer.valueOf(loanDisbursementActionForm.getAccountId());
LoanDisbursalDto loanDisbursalDto = loanAccountServiceFacade.retrieveLoanDisbursalDetails(loanAccountId);
UserContext uc = getUserContext(request);
SessionUtils.setAttribute(LoanConstants.PROPOSED_DISBURSAL_DATE, loanDisbursalDto.getProposedDate(), request);
loanDisbursementActionForm.setTransactionDate(getUserLocaleDate(uc.getPreferredLocale(), loanDisbursalDto.getProposedDate()));
loanDisbursementActionForm.setAmount(loanDisbursalDto.getAmountPaidAtDisbursement());
loanDisbursementActionForm.setLoanAmount(loanDisbursalDto.getLoanAmount());
if (loanDisbursalDto.isMultiCurrencyEnabled()) {
loanDisbursementActionForm.setCurrencyId(loanDisbursalDto.getCurrencyId());
}
Short repaymentIndependentOfMeetingScheduleValue = loanDisbursalDto.isRepaymentIndependentOfMeetingSchedule() ? Short.valueOf("1") : Short.valueOf("0");
SessionUtils.setAttribute(LoanConstants.REPAYMENT_SCHEDULES_INDEPENDENT_OF_MEETING_IS_ENABLED, repaymentIndependentOfMeetingScheduleValue, request);
SessionUtils.setAttribute(AccountingRulesConstants.BACKDATED_TRANSACTIONS_ALLOWED, loanDisbursalDto.isBackDatedTransactionsAllowed(), request);
List<PaymentTypeEntity> disbursementTypes = legacyAcceptedPaymentTypeDao.getAcceptedPaymentTypesForATransaction(uc.getLocaleId(), TrxnTypes.loan_disbursement.getValue());
SessionUtils.setCollectionAttribute(MasterConstants.PAYMENT_TYPE, disbursementTypes, request);
List<PaymentTypeEntity> feesTypes = legacyAcceptedPaymentTypeDao.getAcceptedPaymentTypesForATransaction(uc.getLocaleId(), TrxnTypes.loan_repayment.getValue());
SessionUtils.setCollectionAttribute(MasterConstants.FEE_PAYMENT_TYPE, feesTypes, request);
SessionUtils.setAttribute(LoanConstants.PAYMENT_TYPE_TRANSFER_FROM_SAVINGS_ID,
legacyAcceptedPaymentTypeDao.getSavingsTransferId(), request);
SessionUtils.setCollectionAttribute(Constants.ACCOUNTS_FOR_TRANSFER,
accountServiceFacade.getActiveSavingsAccountsForClientByLoanId(loanAccountId), request);
return mapping.findForward(Constants.LOAD_SUCCESS);
}
@TransactionDemarcate(joinToken = true)
public ActionForward preview(final ActionMapping mapping, final ActionForm form, final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
LoanDisbursementActionForm loanDisbursementActionForm = (LoanDisbursementActionForm) form;
return createGroupQuestionnaire.fetchAppliedQuestions(mapping, loanDisbursementActionForm, request, ActionForwards.preview_success);
}
@TransactionDemarcate(joinToken = true)
public ActionForward previous(final ActionMapping mapping, @SuppressWarnings("unused") final ActionForm form, @SuppressWarnings("unused") final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
return mapping.findForward(Constants.PREVIOUS_SUCCESS);
}
@TransactionDemarcate(validateAndResetToken = true)
@CloseSession
public ActionForward update(final ActionMapping mapping, final ActionForm form, final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
LoanDisbursementActionForm actionForm = (LoanDisbursementActionForm) form;
UserContext uc = getUserContext(request);
Date trxnDate = getDateFromString(actionForm.getTransactionDate(), uc.getPreferredLocale());
trxnDate = DateUtils.getDateWithoutTimeStamp(trxnDate.getTime());
Date receiptDate = getDateFromString(actionForm.getReceiptDate(), uc.getPreferredLocale());
Integer loanAccountId = Integer.valueOf(actionForm.getAccountId());
Integer accountForTransferId = (StringUtils.isBlank(actionForm.getAccountForTransfer())) ? null
: legacyAccountDao.getAccountIdByGlobalAccountNumber(actionForm.getAccountForTransfer());
AccountBO accountBO = new AccountBusinessService().getAccount(loanAccountId);
Date originalDisbursementDate = DateUtils.getDateWithoutTimeStamp(((LoanBO)accountBO).getDisbursementDate());
createGroupQuestionnaire.saveResponses(request, actionForm, loanAccountId);
try {
String paymentTypeIdStringForDisbursement = actionForm.getPaymentTypeId();
String paymentTypeIdStringForFees = actionForm.getPaymentModeOfPayment();
Short paymentTypeIdForDisbursement = StringUtils.isEmpty(paymentTypeIdStringForDisbursement) ? PaymentTypes.CASH.getValue() : Short
.valueOf(paymentTypeIdStringForDisbursement);
Short paymentTypeIdForFees = StringUtils.isEmpty(paymentTypeIdStringForFees) ? PaymentTypes.CASH.getValue()
: Short.valueOf(paymentTypeIdStringForFees);
Short paymentTypeId = Short.valueOf(paymentTypeIdForDisbursement);
final String comment = "";
final BigDecimal disbursalAmount = new BigDecimal(actionForm.getLoanAmount());
CustomerDto customerDto = null;
PaymentTypeDto paymentType = null;
AccountPaymentParametersDto loanDisbursement = new AccountPaymentParametersDto(new UserReferenceDto(uc.getId()), new AccountReferenceDto(
loanAccountId), disbursalAmount, new LocalDate(trxnDate), paymentType, comment,
new LocalDate(receiptDate), actionForm.getReceiptId(), customerDto);
monthClosingServiceFacade.validateTransactionDate(trxnDate);
// GLIM
List<LoanBO> individualLoans = this.loanDao.findIndividualLoans(loanAccountId);
for (LoanBO individual : individualLoans) {
if (!loanAccountServiceFacade.isTrxnDateValid(Integer.valueOf(individual.getAccountId()), trxnDate)) {
throw new BusinessRuleException("errors.invalidTxndateOfDisbursal");
}
}
this.loanAccountServiceFacade.disburseLoan(loanDisbursement, paymentTypeId, paymentTypeIdForFees, accountForTransferId);
for (LoanBO individual : individualLoans) {
loanDisbursement = new AccountPaymentParametersDto(new UserReferenceDto(uc.getId()), new AccountReferenceDto(
individual.getAccountId()), individual.getLoanAmount().getAmount(), new LocalDate(trxnDate), paymentType, comment,
new LocalDate(receiptDate), actionForm.getReceiptId(), customerDto);
this.loanAccountServiceFacade.disburseLoan(loanDisbursement, paymentTypeId, paymentTypeIdForFees, accountForTransferId);
}
if (!((LoanBO)accountBO).isFixedRepaymentSchedule() &&
!originalDisbursementDate.equals(((LoanBO)accountBO).getDisbursementDate())) {
this.loanAccountServiceFacade.updateMemberLoansFeeAmounts(loanAccountId);
}
} catch (BusinessRuleException e) {
throw new AccountException(e.getMessage());
} catch (MifosRuntimeException e) {
if (e.getCause() != null && e.getCause() instanceof AccountException) {
throw new AccountException(e.getCause().getMessage());
}
String msg = "errors.cannotDisburseLoan.because.disburseFailed";
logger.error(msg, e);
throw new AccountException(msg);
} catch (Exception e) {
String msg = "errors.cannotDisburseLoan.because.disburseFailed";
logger.error(msg, e);
throw new AccountException(msg);
}
return mapping.findForward(Constants.UPDATE_SUCCESS);
}
@TransactionDemarcate(joinToken = true)
public ActionForward validate(final ActionMapping mapping, @SuppressWarnings("unused") final ActionForm form, final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
String method = (String) request.getAttribute("methodCalled");
String forward = null;
if (method != null) {
forward = method + "_failure";
}
return mapping.findForward(forward);
}
@Override
protected boolean isNewBizRequired(@SuppressWarnings("unused") final HttpServletRequest request) throws ServiceException {
return false;
}
@TransactionDemarcate(joinToken = true)
public ActionForward captureQuestionResponses(
final ActionMapping mapping, final ActionForm form, final HttpServletRequest request,
@SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
request.setAttribute(METHODCALLED, "captureQuestionResponses");
ActionErrors errors = createGroupQuestionnaire.validateResponses(request, (LoanDisbursementActionForm) form);
if (errors != null && !errors.isEmpty()) {
addErrors(request, errors);
return mapping.findForward(ActionForwards.captureQuestionResponses.toString());
}
return createGroupQuestionnaire.rejoinFlow(mapping);
}
@TransactionDemarcate(joinToken = true)
public ActionForward editQuestionResponses(
final ActionMapping mapping, final ActionForm form,
final HttpServletRequest request, @SuppressWarnings("unused") final HttpServletResponse response) throws Exception {
request.setAttribute(METHODCALLED, "editQuestionResponses");
return createGroupQuestionnaire.editResponses(mapping, request, (LoanDisbursementActionForm) form);
}
private QuestionnaireFlowAdapter createGroupQuestionnaire = new QuestionnaireFlowAdapter("Disburse", "Loan",
ActionForwards.preview_success, "clientsAndAccounts.ftl",
new DefaultQuestionnaireServiceFacadeLocator());
}