package org.mifos.clientportfolio.loan.ui;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.mifos.application.servicefacade.GroupLoanAccountServiceFacade;
import org.mifos.application.servicefacade.LoanAccountServiceFacade;
import org.mifos.clientportfolio.loan.service.RecurringSchedule;
import org.mifos.clientportfolio.loan.ui.helper.LoanControllerHelper;
import org.mifos.clientportfolio.newloan.applicationservice.CreateGroupLoanAccount;
import org.mifos.clientportfolio.newloan.applicationservice.CreateLoanAccount;
import org.mifos.clientportfolio.newloan.applicationservice.LoanAccountCashFlow;
import org.mifos.clientportfolio.newloan.applicationservice.LoanApplicationStateDto;
import org.mifos.dto.domain.CreateAccountFeeDto;
import org.mifos.dto.domain.CreateAccountPenaltyDto;
import org.mifos.dto.domain.LoanPaymentDto;
import org.mifos.dto.screen.GroupLoanScheduleDto;
import org.mifos.dto.screen.LoanCreationResultDto;
import org.mifos.dto.screen.LoanScheduleDto;
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;
@SuppressWarnings("PMD")
@Controller
public class GroupLoanAccountController {
private final LoanAccountServiceFacade loanAccountServiceFacade;
private final GroupLoanAccountServiceFacade groupLoanAccountServiceFacade;
private LoanControllerHelper loanControllerHelper;
@Autowired
public GroupLoanAccountController(LoanAccountServiceFacade loanAccountServiceFacade,
GroupLoanAccountServiceFacade groupLoanAccountServiceFacade,
LoanControllerHelper loanControllerHelper) {
this.loanAccountServiceFacade = loanAccountServiceFacade;
this.groupLoanAccountServiceFacade = groupLoanAccountServiceFacade;
this.loanControllerHelper = loanControllerHelper;
}
public LoanCreationResultDto saveLoanApplicationForLater(LoanAccountFormBean formBean, LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean, LoanScheduleFormBean loanScheduleFormBean) {
LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();
return submitGroupLoanApplication(applicationState.getPartialApplicationId(), formBean, loanAccountQuestionGroupFormBean, loanAccountCashFlow, cashFlowSummaryFormBean, loanScheduleFormBean);
}
public LoanCreationResultDto saveGroupLoanApplication(LoanAccountFormBean formBean, LoanAccountQuestionGroupFormBean loanAccountQuestionGroupFormBean,
LoanAccountCashFlow loanAccountCashFlow, CashFlowSummaryFormBean cashFlowSummaryFormBean, LoanScheduleFormBean loanScheduleFormBean) {
LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();
return submitGroupLoanApplication(applicationState.getConfiguredApplicationId(), formBean, loanAccountQuestionGroupFormBean, loanAccountCashFlow, cashFlowSummaryFormBean, loanScheduleFormBean);
}
public LoanCreationResultDto submitGroupLoanApplication(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);
Map<String, List<CreateAccountFeeDto>> memberAccountsFees =
LoanCreationHelper.translateToMemberAccountsFeeDtos(formBean);
Map<String, List<CreateAccountFeeDto>> memberAccountsAdditionalFees =
LoanCreationHelper.translateToMemberAccountsAdditionalFeeDtos(formBean);
for (Map.Entry<String, List<CreateAccountFeeDto>> memberAccountEntry : memberAccountsAdditionalFees.entrySet()) {
memberAccountsFees.get(memberAccountEntry.getKey()).addAll(memberAccountsAdditionalFees.get(memberAccountEntry.getKey()));
}
BigDecimal loanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
BigDecimal minAllowedLoanAmount = BigDecimal.valueOf(formBean.getMinAllowedAmount().doubleValue());
BigDecimal maxAllowedLoanAmount = BigDecimal.valueOf(formBean.getMaxAllowedAmount().doubleValue());
CreateLoanAccount loanAccountDetails = prepareLoanAccount(accountState, formBean, disbursementDate,
recurringSchedule, accountFees, accountPenalties, loanAmount, minAllowedLoanAmount,
maxAllowedLoanAmount);
LoanCreationResultDto loanCreationResultDto = null;
List<CreateLoanAccount> memberAccounts = createGroupLoanMembers(accountState, formBean, disbursementDate, recurringSchedule, memberAccountsFees,
accountPenalties, loanAmount, minAllowedLoanAmount, maxAllowedLoanAmount);
BigDecimal totalLoanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
CreateGroupLoanAccount createGroupLoanAccount = new CreateGroupLoanAccount(memberAccounts, totalLoanAmount, loanAccountDetails);
loanCreationResultDto = groupLoanAccountServiceFacade.createGroupLoan(createGroupLoanAccount, loanAccountQuestionGroupFormBean.getQuestionGroups(), loanAccountCashFlow);
return loanCreationResultDto;
}
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;
}
}
public LoanScheduleDto retrieveLoanSchedule(int customerId, int productId, LoanAccountFormBean formBean,
LoanScheduleFormBean loanScheduleFormBean, boolean resetRedoLoanAccountDetails) {
LoanApplicationStateDto applicationState = loanAccountServiceFacade.retrieveLoanApplicationState();
Integer accountState = applicationState.getConfiguredApplicationId();
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);
Map<String, List<CreateAccountFeeDto>> memberAccountsFees =
LoanCreationHelper.translateToMemberAccountsFeeDtos(formBean);
Map<String, List<CreateAccountFeeDto>> memberAccountsAdditionalFees =
LoanCreationHelper.translateToMemberAccountsAdditionalFeeDtos(formBean);
for (Map.Entry<String, List<CreateAccountFeeDto>> memberAccountEntry : memberAccountsAdditionalFees.entrySet()) {
memberAccountsFees.get(memberAccountEntry.getKey()).addAll(memberAccountsAdditionalFees.get(memberAccountEntry.getKey()));
}
BigDecimal loanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
BigDecimal minAllowedLoanAmount = BigDecimal.valueOf(formBean.getMinAllowedAmount().doubleValue());
BigDecimal maxAllowedLoanAmount = BigDecimal.valueOf(formBean.getMaxAllowedAmount().doubleValue());
CreateLoanAccount loanAccountDetails = prepareLoanAccount(accountState, formBean, disbursementDate,
recurringSchedule, accountFees, accountPenalties, loanAmount, minAllowedLoanAmount,
maxAllowedLoanAmount);
List<CreateLoanAccount> memberAccounts = createGroupLoanMembers(accountState, formBean, disbursementDate, recurringSchedule, memberAccountsFees,
accountPenalties, loanAmount, minAllowedLoanAmount, maxAllowedLoanAmount);
BigDecimal totalLoanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
CreateGroupLoanAccount createGroupLoanAccount = new CreateGroupLoanAccount(memberAccounts, totalLoanAmount, loanAccountDetails);
GroupLoanScheduleDto groupLoanScheduleDto = groupLoanAccountServiceFacade.getGroupLoanScheduleDto(
createGroupLoanAccount, memberAccounts);
List<String> globalMemberIds = loanControllerHelper.getSelectedMemberGlobalIds(formBean);
List<Integer> memberIds = loanControllerHelper.getSelectedMemberIdsFromFormBean(formBean);
List<BigDecimal> memberAmounts = loanControllerHelper.getSelectedMemberAmounts(formBean);
loanScheduleFormBean.setVariableInstallments(groupLoanScheduleDto.getInstallments());
for (int i = 0; i < memberIds.size(); ++i) {
Integer memberId = memberIds.get(i);
String memberIdString = memberId.toString();
LoanScheduleFormBean memberScheduleBean = loanScheduleFormBean.getMemberSchedules().get(memberIdString);
if (memberScheduleBean == null) {
memberScheduleBean = new LoanScheduleFormBean();
}
memberScheduleBean.setGlobalCustomerId(globalMemberIds.get(i));
loanScheduleFormBean.getMemberSchedules().put(memberIdString, memberScheduleBean);
LoanScheduleDto memberLoanSchedule = groupLoanScheduleDto.getMemberSchedules().get(memberId);
loanControllerHelper.populateFormBeanFromDto(memberId, productId, formBean,
memberScheduleBean, disbursementDate, memberLoanSchedule, resetRedoLoanAccountDetails);
memberScheduleBean.setLoanPrincipal(memberAmounts.get(i));
loanScheduleFormBean.setInstallments(memberScheduleBean.getInstallments());
}
loanScheduleFormBean.setActualPaymentAmounts(new ArrayList<Number>());
return groupLoanScheduleDto;
}
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);
Map<String, List<CreateAccountFeeDto>> memberAccountsFees =
LoanCreationHelper.translateToMemberAccountsFeeDtos(formBean);
Map<String, List<CreateAccountFeeDto>> memberAccountsAdditionalFees =
LoanCreationHelper.translateToMemberAccountsAdditionalFeeDtos(formBean);
for (Map.Entry<String, List<CreateAccountFeeDto>> memberAccountEntry : memberAccountsAdditionalFees.entrySet()) {
memberAccountsFees.get(memberAccountEntry.getKey()).addAll(memberAccountsAdditionalFees.get(memberAccountEntry.getKey()));
}
BigDecimal loanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
BigDecimal minAllowedLoanAmount = BigDecimal.valueOf(formBean.getMinAllowedAmount().doubleValue());
BigDecimal maxAllowedLoanAmount = BigDecimal.valueOf(formBean.getMaxAllowedAmount().doubleValue());
Map<Integer, List<LoanPaymentDto>> backdatedMemberLoanPayments = new HashMap<Integer, List<LoanPaymentDto>>();
List<Integer> memberIds = loanControllerHelper.getSelectedMemberIdsFromFormBean(formBean);
for (Integer memberId : memberIds) {
String memberIdString = memberId.toString();
List<Number> actualPaymentAmountDetails = loanScheduleFormBean.getMemberSchedules().get(memberIdString).getActualPaymentAmounts();
List<LoanPaymentDto> backdatedLoanPayments = new ArrayList<LoanPaymentDto>();
List<DateTime> actualPaymentDates = loanScheduleFormBean.getMemberSchedules().get(memberIdString).getActualPaymentDates();
List<Short> actualPaymentTypes = loanScheduleFormBean.getMemberSchedules().get(memberIdString).getActualPaymentTypes();
for (int i = 0; i < actualPaymentAmountDetails.size(); ++i) {
Number actualPaymentAmount = actualPaymentAmountDetails.get(i);
if (actualPaymentAmount.doubleValue() > 0) {
LocalDate transactionDate = new LocalDate(actualPaymentDates.get(i));
backdatedLoanPayments.add(new LoanPaymentDto(actualPaymentAmount.toString(), transactionDate, actualPaymentTypes.get(i), null));
}
}
backdatedMemberLoanPayments.put(memberId, backdatedLoanPayments);
}
CreateLoanAccount loanAccountDetails = prepareLoanAccount(accountState, formBean, disbursementDate,
recurringSchedule, accountFees, accountPenalties, loanAmount, minAllowedLoanAmount,
maxAllowedLoanAmount);
List<CreateLoanAccount> memberAccounts = createGroupLoanMembers(accountState, formBean, disbursementDate, recurringSchedule, memberAccountsFees,
accountPenalties, loanAmount, minAllowedLoanAmount, maxAllowedLoanAmount);
BigDecimal totalLoanAmount = BigDecimal.valueOf(formBean.getAmount().doubleValue());
CreateGroupLoanAccount createGroupLoanAccount = new CreateGroupLoanAccount(memberAccounts, totalLoanAmount, loanAccountDetails);
return groupLoanAccountServiceFacade.createBackdatedGroupLoan(createGroupLoanAccount, backdatedMemberLoanPayments,
loanAccountQuestionGroupFormBean.getQuestionGroups(), loanAccountCashFlow);
}
private CreateLoanAccount prepareLoanAccount(Integer accountState, LoanAccountFormBean formBean,
LocalDate disbursementDate, RecurringSchedule recurringSchedule, List<CreateAccountFeeDto> accountFees,
List<CreateAccountPenaltyDto> accountPenalties, BigDecimal loanAmount, BigDecimal minAllowedLoanAmount,
BigDecimal maxAllowedLoanAmount) {
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);
return loanAccountDetails;
}
private CreateLoanAccount prepareGroupLoanAccountMember(Integer accountState, LoanAccountFormBean formBean,
LocalDate disbursementDate, RecurringSchedule recurringSchedule, List<CreateAccountFeeDto> accountFees,
List<CreateAccountPenaltyDto> accountPenalties, BigDecimal loanAmount, BigDecimal minAllowedLoanAmount,
BigDecimal maxAllowedLoanAmount, int index) {
Integer memberId = this.groupLoanAccountServiceFacade.getMemberClientId(formBean.getClientGlobalId()[index]);
CreateLoanAccount loanAccountDetails = new CreateLoanAccount(memberId,
formBean.getProductId(), accountState, BigDecimal.valueOf(formBean.getClientAmount()[index].doubleValue()), minAllowedLoanAmount, maxAllowedLoanAmount,
formBean.getInterestRate().doubleValue(), disbursementDate, null, formBean.getNumberOfInstallments().intValue(),
formBean.getMinNumberOfInstallments().intValue(), formBean.getMaxNumberOfInstallments().intValue(),
formBean.getGraceDuration().intValue(), formBean.getFundId(),
formBean.getClientLoanPurposeId()[index], formBean.getCollateralTypeId(), formBean.getCollateralNotes(),
formBean.getExternalId(), formBean.isRepaymentScheduleIndependentOfCustomerMeeting(), recurringSchedule, accountFees, accountPenalties);
return loanAccountDetails;
}
private List<CreateLoanAccount> createGroupLoanMembers(Integer accountState, LoanAccountFormBean formBean,
LocalDate disbursementDate, RecurringSchedule recurringSchedule, Map<String,List<CreateAccountFeeDto>> accountFees,
List<CreateAccountPenaltyDto> accountPenalties, BigDecimal loanAmount, BigDecimal minAllowedLoanAmount,
BigDecimal maxAllowedLoanAmount) {
List<CreateLoanAccount> memberAccounts = new ArrayList<CreateLoanAccount>();
int index = 0;
for (Boolean clientSelected : formBean.getClientSelectForGroup()) {
if (clientSelected != null && clientSelected.booleanValue()) {
String clientGlobalId = formBean.getClientGlobalId()[index];
CreateLoanAccount memberAccount = prepareGroupLoanAccountMember(accountState, formBean, disbursementDate, recurringSchedule, accountFees.get(clientGlobalId), accountPenalties,
BigDecimal.valueOf(formBean.getClientAmount()[index].doubleValue()), minAllowedLoanAmount, maxAllowedLoanAmount, index);
memberAccounts.add(memberAccount);
}
index++;
}
return memberAccounts;
}
}