org.mifos.application.servicefacade.CollectionSheetServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.mifos.application.servicefacade.CollectionSheetServiceImpl.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.application.servicefacade;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ObjectUtils;
import org.hibernate.HibernateException;
import org.joda.time.LocalDate;
import org.mifos.accounts.business.AccountBO;
import org.mifos.accounts.business.AccountPaymentEntity;
import org.mifos.accounts.loan.business.LoanBO;
import org.mifos.accounts.loan.persistance.ClientAttendanceDao;
import org.mifos.accounts.loan.persistance.LegacyLoanDao;
import org.mifos.accounts.persistence.LegacyAccountDao;
import org.mifos.accounts.savings.business.SavingsBO;
import org.mifos.accounts.savings.persistence.SavingsDao;
import org.mifos.application.collectionsheet.persistence.CollectionSheetDao;
import org.mifos.core.MifosRuntimeException;
import org.mifos.customers.api.CustomerLevel;
import org.mifos.customers.client.business.ClientAttendanceBO;
import org.mifos.customers.persistence.CustomerPersistence;
import org.mifos.framework.hibernate.helper.StaticHibernateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * implementation of CollectionSheetService
 *
 */
public class CollectionSheetServiceImpl implements CollectionSheetService {

    private static final Logger logger = LoggerFactory.getLogger(CollectionSheetServiceImpl.class);

    private final ClientAttendanceDao clientAttendanceDao;

    @Autowired
    private LegacyLoanDao legacyLoanDao;

    @Autowired
    private LegacyAccountDao legacyAccountDao;
    private final SavingsDao savingsDao;
    private final CollectionSheetDao collectionSheetDao;

    @Autowired
    private SaveCollectionSheetAssembler saveCollectionSheetAssembler;

    @Autowired
    public CollectionSheetServiceImpl(final ClientAttendanceDao clientAttendanceDao, final SavingsDao savingsDao,
            final CollectionSheetDao collectionSheetDao) {
        this.clientAttendanceDao = clientAttendanceDao;
        this.savingsDao = savingsDao;
        this.collectionSheetDao = collectionSheetDao;
    }

    public CollectionSheetServiceImpl(final ClientAttendanceDao clientAttendanceDao,
            final LegacyLoanDao legacyLoanDao, final LegacyAccountDao legacyAccountDao, final SavingsDao savingsDao,
            final CollectionSheetDao collectionSheetDao) {
        this.clientAttendanceDao = clientAttendanceDao;
        this.legacyLoanDao = legacyLoanDao;
        this.legacyAccountDao = legacyAccountDao;
        this.savingsDao = savingsDao;
        this.collectionSheetDao = collectionSheetDao;
    }

    /**
     * The method saves a collection sheet.
     *
     * @throws SaveCollectionSheetException
     * */
    @Override
    public CollectionSheetErrorsDto saveCollectionSheet(final SaveCollectionSheetDto saveCollectionSheet)
            throws SaveCollectionSheetException {

        Long totalTime;
        Long totalTimeStart = System.currentTimeMillis();
        Long readTime;
        Long saveTime = null;
        Long saveTimeStart;

        Integer topCustomerId = saveCollectionSheet.getSaveCollectionSheetCustomers().get(0).getCustomerId();
        CollectionSheetCustomerDto collectionSheetTopCustomer = new CustomerPersistence()
                .findCustomerWithNoAssocationsLoaded(topCustomerId);
        if (collectionSheetTopCustomer == null) {
            List<InvalidSaveCollectionSheetReason> invalidSaveCollectionSheetReasons = new ArrayList<InvalidSaveCollectionSheetReason>();
            List<String> invalidSaveCollectionSheetReasonsExtended = new ArrayList<String>();
            invalidSaveCollectionSheetReasons.add(InvalidSaveCollectionSheetReason.INVALID_TOP_CUSTOMER);
            invalidSaveCollectionSheetReasonsExtended
                    .add(InvalidSaveCollectionSheetReason.INVALID_TOP_CUSTOMER.toString() + ": Customer Id: "
                            + topCustomerId);
            throw new SaveCollectionSheetException(invalidSaveCollectionSheetReasons,
                    invalidSaveCollectionSheetReasonsExtended);
        }
        Short branchId = collectionSheetTopCustomer.getBranchId();
        String searchId = collectionSheetTopCustomer.getSearchId();

        // session caching: prefetch collection sheet data
        // done prior to structure validation because it loads
        // the customers and accounts to be validated into the session
        SaveCollectionSheetSessionCache saveCollectionSheetSessionCache = new SaveCollectionSheetSessionCache();
        saveCollectionSheetSessionCache.loadSessionCacheWithCollectionSheetData(saveCollectionSheet, branchId,
                searchId);

        try {
            new SaveCollectionSheetStructureValidator().execute(saveCollectionSheet);
        } catch (SaveCollectionSheetException e) {
            System.out.println(e.printInvalidSaveCollectionSheetReasons());
            throw e;
        }

        /*
         * With preprocessing complete...
         *
         * only errors and warnings from the business model remain
         */

        final List<String> failedSavingsDepositAccountNums = new ArrayList<String>();
        final List<String> failedSavingsWithdrawalNums = new ArrayList<String>();
        final List<String> failedLoanDisbursementAccountNumbers = new ArrayList<String>();
        final List<String> failedLoanRepaymentAccountNumbers = new ArrayList<String>();
        final List<String> failedCustomerAccountPaymentNums = new ArrayList<String>();

        final List<ClientAttendanceBO> clientAttendances = saveCollectionSheetAssembler
                .clientAttendanceAssemblerfromDto(saveCollectionSheet.getSaveCollectionSheetCustomers(),
                        saveCollectionSheet.getTransactionDate(), branchId, searchId);

        final AccountPaymentEntity payment = saveCollectionSheetAssembler.accountPaymentAssemblerFromDto(
                saveCollectionSheet.getTransactionDate(), saveCollectionSheet.getPaymentType(),
                saveCollectionSheet.getReceiptId(), saveCollectionSheet.getReceiptDate(),
                saveCollectionSheet.getUserId());

        final List<SavingsBO> savingsAccounts = saveCollectionSheetAssembler.savingsAccountAssemblerFromDto(
                saveCollectionSheet.getSaveCollectionSheetCustomers(), payment, failedSavingsDepositAccountNums,
                failedSavingsWithdrawalNums);

        final List<LoanBO> loanAccounts = saveCollectionSheetAssembler.loanAccountAssemblerFromDto(
                saveCollectionSheet.getSaveCollectionSheetCustomers(), payment,
                failedLoanDisbursementAccountNumbers, failedLoanRepaymentAccountNumbers);

        final List<AccountBO> customerAccounts = saveCollectionSheetAssembler.customerAccountAssemblerFromDto(
                saveCollectionSheet.getSaveCollectionSheetCustomers(), payment, failedCustomerAccountPaymentNums);

        boolean databaseErrorOccurred = false;
        Throwable databaseError = null;
        readTime = System.currentTimeMillis() - totalTimeStart;

        try {
            saveTimeStart = System.currentTimeMillis();
            persistCollectionSheet(clientAttendances, loanAccounts, customerAccounts, savingsAccounts);
            saveTime = System.currentTimeMillis() - saveTimeStart;
        } catch (HibernateException e) {
            logger.error("database error saving collection sheet", e);
            databaseErrorOccurred = true;
            databaseError = e;
        }

        totalTime = System.currentTimeMillis() - totalTimeStart;
        printTiming(saveCollectionSheet.printSummary(), totalTime, saveTime, readTime,
                saveCollectionSheetSessionCache);

        return new CollectionSheetErrorsDto(failedSavingsDepositAccountNums, failedSavingsWithdrawalNums,
                failedLoanDisbursementAccountNumbers, failedLoanRepaymentAccountNumbers,
                failedCustomerAccountPaymentNums, databaseErrorOccurred, databaseError);
    }

    private void printTiming(String printSummary, Long totalTime, Long saveTime, Long readTime,
            SaveCollectionSheetSessionCache saveCollectionSheetSessionCache) {

        final StringBuilder builder = new StringBuilder();
        final String comma = ", ";

        builder.append(printSummary);
        builder.append(comma);
        builder.append("Collection Sheet Timing:");
        builder.append(comma);
        builder.append(totalTime);
        builder.append(comma);
        builder.append(saveTime);
        builder.append(comma);
        builder.append(readTime);
        builder.append(comma);
        builder.append("Cache Use Timing:");
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchCustomerHierarchyTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchCustomerHierarchyCount());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchAccountDataTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchAccountDataCount());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchLoanSchedulesTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchLoanSchedulesCount());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchAccountFeeDetailsTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchAccountFeeDetailsCount());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchCustomerSchedulesTotalTime());
        builder.append(comma);
        builder.append(saveCollectionSheetSessionCache.getPrefetchCustomerSchedulesCount());

        doLog(builder.toString());

    }

    private void persistCollectionSheet(final List<ClientAttendanceBO> clientAttendances,
            final List<LoanBO> loanAccounts, final List<AccountBO> customerAccountList,
            final List<SavingsBO> savingAccounts) {

        try {
            StaticHibernateUtil.startTransaction();

            clientAttendanceDao.save(clientAttendances);
            legacyLoanDao.save(loanAccounts);
            legacyAccountDao.save(customerAccountList);
            savingsDao.save(savingAccounts);

            StaticHibernateUtil.commitTransaction();

        } catch (HibernateException e) {
            StaticHibernateUtil.rollbackTransaction();
            throw e;
        } finally {
            StaticHibernateUtil.closeSession();
        }
    }

    @Override
    public CollectionSheetDto retrieveCollectionSheet(final Integer customerId, final LocalDate transactionDate) {

        if (customerId == null) {
            throw new IllegalArgumentException("Invalid Null Customer Id");
        }
        if (transactionDate == null) {
            throw new IllegalArgumentException("Invalid Null Transaction Date: ");
        }

        final List<CollectionSheetCustomerDto> customerHierarchy = collectionSheetDao
                .findCustomerHierarchy(customerId, transactionDate);

        if (customerHierarchy == null || customerHierarchy.size() == 0) {
            throw new IllegalArgumentException("Invalid Customer Id: " + customerId);
        }

        final Short branchId = customerHierarchy.get(0).getBranchId();
        final String searchId = customerHierarchy.get(0).getSearchId() + ".%";

        final CustomerHierarchyParams customerHierarchyParams = new CustomerHierarchyParams(customerId, branchId,
                searchId, transactionDate);

        final Map<Integer, List<CollectionSheetCustomerLoanDto>> allLoanRepaymentsGroupedByCustomerId = collectionSheetDao
                .findAllLoanRepaymentsForCustomerHierarchy(branchId, searchId, transactionDate, customerId);

        final Map<Integer, Map<Integer, List<CollectionSheetLoanFeeDto>>> allLoanFeesGroupedByCustomerIdAndAccountId = collectionSheetDao
                .findOutstandingFeesForLoansOnCustomerHierarchy(branchId, searchId, transactionDate, customerId);

        final Map<Integer, List<CollectionSheetCustomerAccountCollectionDto>> allAccountCollectionsByCustomerId = collectionSheetDao
                .findAccountCollectionsOnCustomerAccount(branchId, searchId, transactionDate, customerId);

        final Map<Integer, List<CollectionSheetCustomerAccountCollectionDto>> feesAssociatedWithAccountCollectionsByCustomerId = collectionSheetDao
                .findOutstandingFeesForCustomerAccountOnCustomerHierarchy(branchId, searchId, transactionDate,
                        customerId);

        final Map<Integer, List<CollectionSheetCustomerLoanDto>> allLoanDisbursements = collectionSheetDao
                .findLoanDisbursementsForCustomerHierarchy(branchId, searchId, transactionDate, customerId);

        // Retrieve Each Savings Account
        final List<CollectionSheetCustomerSavingsAccountDto> savingsAccounts = collectionSheetDao
                .findAllSavingAccountsForCustomerHierarchy(customerHierarchyParams);
        Map<Integer, List<CollectionSheetCustomerSavingDto>> allSavingsDepositsGroupedByCustomerId = new HashMap<Integer, List<CollectionSheetCustomerSavingDto>>();
        Map<Integer, List<CollectionSheetCustomerSavingDto>> allSavingsAccountsToBePaidByIndividualClientsGroupedByCustomerId = new HashMap<Integer, List<CollectionSheetCustomerSavingDto>>();
        // No need to look for unpaid Savings Account transactions if no Savings Accounts
        if (savingsAccounts != null && savingsAccounts.size() > 0) {
            allSavingsDepositsGroupedByCustomerId = collectionSheetDao
                    .findSavingsDepositsforCustomerHierarchy(customerHierarchyParams);

            // only need to look for unpaid installments for the CLIENTS underneath center or group individual savings
            // account if those accounts exist
            if (containsIndividualAccount(savingsAccounts)) {
                allSavingsAccountsToBePaidByIndividualClientsGroupedByCustomerId = collectionSheetDao
                        .findAllSavingsAccountsPayableByIndividualClientsForCustomerHierarchy(
                                customerHierarchyParams);
            }
        }

        //
        final List<CollectionSheetCustomerDto> populatedCollectionSheetCustomer = new ArrayList<CollectionSheetCustomerDto>();
        for (CollectionSheetCustomerDto collectionSheetCustomer : customerHierarchy) {

            final Integer customerInHierarchyId = collectionSheetCustomer.getCustomerId();
            final List<CollectionSheetCustomerLoanDto> associatedLoanRepayments = allLoanRepaymentsGroupedByCustomerId
                    .get(customerInHierarchyId);

            final Map<Integer, List<CollectionSheetLoanFeeDto>> outstandingFeesOnLoanRepayments = allLoanFeesGroupedByCustomerIdAndAccountId
                    .get(customerInHierarchyId);

            final List<CollectionSheetCustomerLoanDto> associatedLoanDisbursements = allLoanDisbursements
                    .get(customerInHierarchyId);

            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollections = allAccountCollectionsByCustomerId
                    .get(customerInHierarchyId);
            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollectionFees = feesAssociatedWithAccountCollectionsByCustomerId
                    .get(customerInHierarchyId);

            final CollectionSheetCustomerAccountDto customerAccount = sumAssociatedCustomerAccountCollectionFees(
                    customerAccountCollections, customerAccountCollectionFees);

            // process savings accounts
            List<CollectionSheetCustomerSavingDto> associatedSavingAccounts = ensureAllSavingsAccountsRepresented(
                    allSavingsDepositsGroupedByCustomerId.get(customerInHierarchyId), savingsAccounts,
                    customerInHierarchyId);
            List<CollectionSheetCustomerSavingDto> associatedIndividualSavingsAccounts = ensureAllClientIndividualSavingsAccountsRepresented(
                    allSavingsAccountsToBePaidByIndividualClientsGroupedByCustomerId.get(customerInHierarchyId),
                    getIndividualSavingsAccounts(savingsAccounts), collectionSheetCustomer);

            //
            populatedCollectionSheetCustomer.add(createNullSafeCollectionSheetCustomer(collectionSheetCustomer,
                    associatedLoanRepayments, outstandingFeesOnLoanRepayments, associatedLoanDisbursements,
                    associatedSavingAccounts, associatedIndividualSavingsAccounts, customerAccount));

        }

        return new CollectionSheetDto(populatedCollectionSheetCustomer, transactionDate);
    }

    /*
     * Each savings account should be represented in the collection sheet. The previous retrievals only bring back
     * savings accounts that have unpaid installments. The following code adds a zero entry for any savings accounts not
     * there. This is because it is possible to deposit or withdraw without an outstanding unpaid installment.
     */
    private List<CollectionSheetCustomerSavingDto> ensureAllSavingsAccountsRepresented(
            List<CollectionSheetCustomerSavingDto> associatedSavingAccountsWithUnpaidInstallments,
            final List<CollectionSheetCustomerSavingsAccountDto> savingsAccounts, final Integer customerId) {

        if (savingsAccounts == null || savingsAccounts.size() == 0) {
            return null;
        }

        List<CollectionSheetCustomerSavingDto> combinedSavingsAccountsList = new ArrayList<CollectionSheetCustomerSavingDto>();
        if (associatedSavingAccountsWithUnpaidInstallments != null) {
            combinedSavingsAccountsList.addAll(associatedSavingAccountsWithUnpaidInstallments);
        }

        for (CollectionSheetCustomerSavingsAccountDto savingsAccount : savingsAccounts) {

            if (savingsAccount.getCustomerId().compareTo(customerId) == 0) {
                // matches on customer, now account not already in list then add it
                if (!isAccountInCombinedSavingsAccountsList(combinedSavingsAccountsList,
                        savingsAccount.getAccountId())) {

                    CollectionSheetCustomerSavingDto zeroValueSavingsAccount = new CollectionSheetCustomerSavingDto();
                    zeroValueSavingsAccount.setCustomerId(savingsAccount.getCustomerId());
                    zeroValueSavingsAccount.setAccountId(savingsAccount.getAccountId());
                    zeroValueSavingsAccount.setProductId(savingsAccount.getProductId());
                    zeroValueSavingsAccount.setProductShortName(savingsAccount.getProductShortName());
                    zeroValueSavingsAccount.setRecommendedAmountUnitId(savingsAccount.getRecommendedAmountUnitId());
                    zeroValueSavingsAccount.setCurrencyId(savingsAccount.getCurrencyId());
                    zeroValueSavingsAccount.setDepositDue(BigDecimal.ZERO);
                    zeroValueSavingsAccount.setDepositPaid(BigDecimal.ZERO);

                    combinedSavingsAccountsList.add(zeroValueSavingsAccount);
                }
            }
        }

        return combinedSavingsAccountsList;
    }

    /*
     * Each client individual savings account should be represented in the collection sheet. The previous retrievals
     * only bring back client individual savings accounts that have unpaid installments. The following code adds a zero
     * entry for any client individual savings accounts not there. This is because it is possible to deposit or withdraw
     * without an outstanding unpaid installment.
     */
    private List<CollectionSheetCustomerSavingDto> ensureAllClientIndividualSavingsAccountsRepresented(
            List<CollectionSheetCustomerSavingDto> clientIndividualSavingAccountsWithUnpaidInstallments,
            final List<CollectionSheetCustomerSavingsAccountDto> clientIndividualSavingsAccounts,
            CollectionSheetCustomerDto customer) {

        if (clientIndividualSavingsAccounts == null) {
            return null;
        }

        // Only clients have client individual savings accounts (the account actually belongs to a "group individual" or
        // a "center" savings account.
        if (customer.getLevelId().compareTo(CustomerLevel.CLIENT.getValue()) != 0) {
            if (clientIndividualSavingAccountsWithUnpaidInstallments != null) {
                throw new MifosRuntimeException("Customer Id: " + customer.getCustomerId()
                        + " is not a client... but has client individual savings");
            }
            return null;
        }

        List<CollectionSheetCustomerSavingDto> combinedSavingsAccountsList = new ArrayList<CollectionSheetCustomerSavingDto>();
        if (clientIndividualSavingAccountsWithUnpaidInstallments != null) {
            combinedSavingsAccountsList.addAll(clientIndividualSavingAccountsWithUnpaidInstallments);
        }

        for (CollectionSheetCustomerSavingsAccountDto individualSavingsAccount : clientIndividualSavingsAccounts) {

            //
            if ((individualSavingsAccount.getCustomerLevelId().compareTo(CustomerLevel.CENTER.getValue()) == 0)
                    || (individualSavingsAccount.getCustomerId().compareTo(customer.getParentCustomerId())) == 0) {
                if (!isAccountInCombinedSavingsAccountsList(combinedSavingsAccountsList,
                        individualSavingsAccount.getAccountId())) {

                    CollectionSheetCustomerSavingDto zeroValueSavingsAccount = new CollectionSheetCustomerSavingDto();
                    zeroValueSavingsAccount.setCustomerId(individualSavingsAccount.getCustomerId());
                    zeroValueSavingsAccount.setAccountId(individualSavingsAccount.getAccountId());
                    zeroValueSavingsAccount.setProductId(individualSavingsAccount.getProductId());
                    zeroValueSavingsAccount.setProductShortName(individualSavingsAccount.getProductShortName());
                    zeroValueSavingsAccount
                            .setRecommendedAmountUnitId(individualSavingsAccount.getRecommendedAmountUnitId());
                    zeroValueSavingsAccount.setCurrencyId(individualSavingsAccount.getCurrencyId());
                    zeroValueSavingsAccount.setDepositDue(BigDecimal.ZERO);
                    zeroValueSavingsAccount.setDepositPaid(BigDecimal.ZERO);

                    combinedSavingsAccountsList.add(zeroValueSavingsAccount);
                }
            }
        }

        return combinedSavingsAccountsList;
    }

    /*
     * Method returns null if accountId parameter is found
     */
    private Boolean isAccountInCombinedSavingsAccountsList(
            List<CollectionSheetCustomerSavingDto> combinedSavingsAccountsList, Integer accountId) {

        for (Integer i = 0; i < combinedSavingsAccountsList.size(); i++) {
            if (combinedSavingsAccountsList.get(i).getAccountId().compareTo(accountId) == 0) {
                return true;
            }
        }
        return false;
    }

    private Boolean containsIndividualAccount(List<CollectionSheetCustomerSavingsAccountDto> savingsAccounts) {

        for (CollectionSheetCustomerSavingsAccountDto savingsAccount : savingsAccounts) {

            if (isIndividualSavingsAccount(savingsAccount.getCustomerLevelId(),
                    savingsAccount.getRecommendedAmountUnitId())) {
                return true;
            }
        }
        return false;
    }

    private List<CollectionSheetCustomerSavingsAccountDto> getIndividualSavingsAccounts(
            List<CollectionSheetCustomerSavingsAccountDto> savingsAccounts) {

        if (savingsAccounts != null && savingsAccounts.size() > 0) {

            List<CollectionSheetCustomerSavingsAccountDto> individualSavingsAccounts = new ArrayList<CollectionSheetCustomerSavingsAccountDto>();
            for (CollectionSheetCustomerSavingsAccountDto savingsAccount : savingsAccounts) {
                if (isIndividualSavingsAccount(savingsAccount.getCustomerLevelId(),
                        savingsAccount.getRecommendedAmountUnitId())) {
                    individualSavingsAccounts.add(savingsAccount);
                }
            }

            if (individualSavingsAccounts.size() > 0) {
                return individualSavingsAccounts;
            }
        }
        return null;
    }

    private Boolean isIndividualSavingsAccount(Short customerLevelId, Short recommendedAmountUnitId) {
        if (customerLevelId.compareTo(CustomerLevel.CENTER.getValue()) == 0) {
            return true;
        }
        if ((customerLevelId.compareTo(CustomerLevel.GROUP.getValue()) == 0) && (recommendedAmountUnitId != null)
                && (recommendedAmountUnitId.compareTo(Short.valueOf("1")) == 0)) {
            return true;
        }
        return false;
    }

    private CollectionSheetCustomerAccountDto sumAssociatedCustomerAccountCollectionFees(
            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollections,
            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollectionFees) {

        final CollectionSheetCustomerAccountDto totalCollection = sumAccountCollections(customerAccountCollections);
        final CollectionSheetCustomerAccountDto totalCollectionFee = sumAccountCollectionFees(
                customerAccountCollectionFees);

        final int accountId = Math.max(totalCollection.getAccountId(), totalCollectionFee.getAccountId());
        final int currencyId = Math.max(totalCollection.getCurrencyId(), totalCollectionFee.getCurrencyId());

        return new CollectionSheetCustomerAccountDto(accountId, (short) currencyId,
                totalCollection.getTotalCustomerAccountCollectionFee()
                        + totalCollectionFee.getTotalCustomerAccountCollectionFee());
    }

    private CollectionSheetCustomerAccountDto sumAccountCollectionFees(
            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollectionFees) {
        Double totalFee = Double.valueOf("0.0");

        if (customerAccountCollectionFees == null) {
            return new CollectionSheetCustomerAccountDto(-1, Short.valueOf("1"), totalFee);
        }

        if (customerAccountCollectionFees.size() > 1) {
            throw new IllegalStateException("Multiple currency");
        }

        return new CollectionSheetCustomerAccountDto(customerAccountCollectionFees.get(0).getAccountId(),
                customerAccountCollectionFees.get(0).getCurrencyId(),
                customerAccountCollectionFees.get(0).getTotalFeeAmountDue());
    }

    private CollectionSheetCustomerAccountDto sumAccountCollections(
            final List<CollectionSheetCustomerAccountCollectionDto> customerAccountCollections) {
        Double totalFee = Double.valueOf("0.0");

        if (customerAccountCollections == null) {
            return new CollectionSheetCustomerAccountDto(-1, Short.valueOf("-1"), totalFee);
        }

        if (customerAccountCollections.size() > 1) {
            throw new IllegalStateException("Multiple currency");
        }

        return new CollectionSheetCustomerAccountDto(customerAccountCollections.get(0).getAccountId(),
                customerAccountCollections.get(0).getCurrencyId(),
                customerAccountCollections.get(0).getAccountCollectionPayment());
    }

    @SuppressWarnings("unchecked")
    private CollectionSheetCustomerDto createNullSafeCollectionSheetCustomer(
            final CollectionSheetCustomerDto collectionSheetCustomer,
            final List<CollectionSheetCustomerLoanDto> associatedLoanRepayments,
            final Map<Integer, List<CollectionSheetLoanFeeDto>> outstandingFeesOnLoanRepayments,
            final List<CollectionSheetCustomerLoanDto> allLoanDisbursements,
            final List<CollectionSheetCustomerSavingDto> associatedSavingAccount,
            final List<CollectionSheetCustomerSavingDto> associatedIndividualSavingsAccounts,
            final CollectionSheetCustomerAccountDto customerAccount) {

        final List<CollectionSheetCustomerSavingDto> savingAccounts = (List<CollectionSheetCustomerSavingDto>) ObjectUtils
                .defaultIfNull(associatedSavingAccount, new ArrayList<CollectionSheetCustomerSavingDto>());

        final List<CollectionSheetCustomerSavingDto> individualSavingAccounts = (List<CollectionSheetCustomerSavingDto>) ObjectUtils
                .defaultIfNull(associatedIndividualSavingsAccounts,
                        new ArrayList<CollectionSheetCustomerSavingDto>());

        if (outstandingFeesOnLoanRepayments == null) {

            List<CollectionSheetCustomerLoanDto> loanRepaymentsAndDisbursements = new ArrayList<CollectionSheetCustomerLoanDto>();

            if (associatedLoanRepayments != null) {
                loanRepaymentsAndDisbursements.addAll(associatedLoanRepayments);
            }

            if (allLoanDisbursements != null) {
                loanRepaymentsAndDisbursements.addAll(allLoanDisbursements);
            }

            return new CollectionSheetCustomerDto(collectionSheetCustomer, loanRepaymentsAndDisbursements,
                    savingAccounts, individualSavingAccounts, customerAccount);
        }

        final List<CollectionSheetCustomerLoanDto> loanRepaymentsAndDisbursementsWithFees = new ArrayList<CollectionSheetCustomerLoanDto>();

        if (associatedLoanRepayments != null) {
            for (CollectionSheetCustomerLoanDto collectionSheetCustomerLoan : associatedLoanRepayments) {
                final List<CollectionSheetLoanFeeDto> loanFeesAgainstAccountOfCustomer = outstandingFeesOnLoanRepayments
                        .get(collectionSheetCustomerLoan.getAccountId());

                loanRepaymentsAndDisbursementsWithFees.add(populateCollectionSheetCustomerLoan(
                        collectionSheetCustomerLoan, loanFeesAgainstAccountOfCustomer));
            }
        }

        if (allLoanDisbursements != null) {
            loanRepaymentsAndDisbursementsWithFees.addAll(allLoanDisbursements);
        }

        return new CollectionSheetCustomerDto(collectionSheetCustomer, loanRepaymentsAndDisbursementsWithFees,
                savingAccounts, individualSavingAccounts, customerAccount);
    }

    private CollectionSheetCustomerLoanDto populateCollectionSheetCustomerLoan(
            final CollectionSheetCustomerLoanDto loan, final List<CollectionSheetLoanFeeDto> loanFees) {

        if (loanFees == null || loanFees.isEmpty()) {
            return loan;
        }

        if (loanFees.size() > 1) {
            throw new IllegalStateException(
                    "Multiple summed fees exist against loan account [" + loan.getAccountId()
                            + "]. This most likey due to multiple currencies existing which is not supported.");
        }

        loan.setTotalAccountFees(loanFees.get(0).getTotalFeeAmountDue());
        return loan;
    }

    private void doLog(String str) {
        logger.info(str);
    }
}