/* * 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.business.service; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import org.mifos.accounts.business.AccountActionEntity; import org.mifos.accounts.business.AccountBO; import org.mifos.accounts.business.AccountStateEntity; import org.mifos.accounts.business.AccountStateMachines; import org.mifos.accounts.fees.business.AmountFeeBO; import org.mifos.accounts.fees.business.FeeBO; import org.mifos.accounts.fees.business.FeePaymentEntity; import org.mifos.accounts.fees.business.RateFeeBO; import org.mifos.accounts.fees.util.helpers.FeeCategory; import org.mifos.accounts.fees.util.helpers.FeeFormula; import org.mifos.accounts.fees.util.helpers.FeeFrequencyType; import org.mifos.accounts.fees.util.helpers.FeePayment; import org.mifos.accounts.fees.util.helpers.RateAmountFlag; import org.mifos.accounts.loan.business.LoanBO; import org.mifos.accounts.persistence.LegacyAccountDao; import org.mifos.accounts.util.helpers.AccountConstants; import org.mifos.accounts.util.helpers.AccountExceptionConstants; import org.mifos.accounts.util.helpers.AccountState; import org.mifos.accounts.util.helpers.AccountStateFlag; import org.mifos.accounts.util.helpers.AccountTypes; import org.mifos.accounts.util.helpers.WaiveEnum; import org.mifos.application.master.persistence.LegacyMasterDao; import org.mifos.application.meeting.business.MeetingBO; import org.mifos.application.meeting.util.helpers.MeetingHelper; import org.mifos.application.servicefacade.ApplicationContextProvider; import org.mifos.config.AccountingRules; import org.mifos.customers.api.CustomerLevel; import org.mifos.customers.business.CustomerAccountBO; import org.mifos.customers.business.CustomerBO; import org.mifos.customers.checklist.business.AccountCheckListBO; import org.mifos.customers.exceptions.CustomerException; import org.mifos.dto.domain.ApplicableCharge; import org.mifos.framework.business.AbstractBusinessObject; import org.mifos.framework.business.service.BusinessService; import org.mifos.framework.exceptions.ApplicationException; import org.mifos.framework.exceptions.PersistenceException; import org.mifos.framework.exceptions.ServiceException; import org.mifos.framework.util.LocalizationConverter; import org.mifos.security.util.ActivityMapper; import org.mifos.security.util.SecurityConstants; import org.mifos.security.util.UserContext; public class AccountBusinessService implements BusinessService { @Override public AbstractBusinessObject getBusinessObject(@SuppressWarnings("unused") UserContext userContext) { return null; } public AccountBO findBySystemId(String accountGlobalNum) throws ServiceException { try { return getlegacyAccountDao().findBySystemId(accountGlobalNum); } catch (PersistenceException e) { throw new ServiceException(AccountExceptionConstants.FINDBYGLOBALACCNTEXCEPTION, e, new Object[] { accountGlobalNum }); } } public AccountTypes getTypeBySystemId(String accountGlobalNum) throws ServiceException { AccountBO accountBO = findBySystemId(accountGlobalNum); if (accountBO != null) { return accountBO.getType(); } return null; } public AccountBO getAccount(Integer accountId) throws ServiceException { try { return getlegacyAccountDao().getAccount(accountId); } catch (PersistenceException e) { throw new ServiceException(e); } } public AccountActionEntity getAccountAction(Short actionType, Short localeId) throws ServiceException { AccountActionEntity accountAction = null; try { accountAction = ApplicationContextProvider.getBean(LegacyMasterDao.class).getPersistentObject( AccountActionEntity.class, actionType); } catch (PersistenceException e) { throw new ServiceException(e); } return accountAction; } public List<AccountStateEntity> retrieveAllAccountStateList(AccountTypes accountTypes) throws ServiceException { try { return getlegacyAccountDao().retrieveAllAccountStateList(accountTypes.getValue()); } catch (PersistenceException e) { throw new ServiceException(e); } } public List<AccountStateEntity> retrieveAllActiveAccountStateList(AccountTypes accountTypes) throws ServiceException { try { return getlegacyAccountDao().retrieveAllActiveAccountStateList(accountTypes.getValue()); } catch (PersistenceException e) { throw new ServiceException(e); } } public List<AccountCheckListBO> getStatusChecklist(Short accountStatusId, Short accountTypeId) throws ServiceException { try { return getlegacyAccountDao().getStatusChecklist(accountStatusId, accountTypeId); } catch (PersistenceException e) { throw new ServiceException(e); } } public List<ApplicableCharge> getAppllicableFees(Integer accountId, UserContext userContext) throws ServiceException { List<ApplicableCharge> applicableChargeList = null; try { AccountBO account = getlegacyAccountDao().getAccount(accountId); FeeCategory categoryType = getCategoryType(account.getCustomer()); if (account.getType() == AccountTypes.LOAN_ACCOUNT || account.getType() == AccountTypes.GROUP_LOAN_ACCOUNT) { applicableChargeList = getLoanApplicableCharges(getlegacyAccountDao().getAllApplicableFees( accountId, FeeCategory.LOAN), userContext, (LoanBO) account); } else if (account.getType() == AccountTypes.CUSTOMER_ACCOUNT) { if (account.getCustomer().getCustomerMeeting() == null) { throw new ServiceException(AccountExceptionConstants.APPLY_CAHRGE_NO_CUSTOMER_MEETING_EXCEPTION); } applicableChargeList = getCustomerApplicableCharges(getlegacyAccountDao().getAllApplicableFees( accountId, categoryType), userContext, ((CustomerAccountBO) account).getCustomer() .getCustomerMeeting().getMeeting().getMeetingDetails().getRecurrenceType().getRecurrenceId()); } addMiscFeeAndPenalty(applicableChargeList); } catch (PersistenceException pe) { throw new ServiceException(pe); } return applicableChargeList; } private FeeCategory getCategoryType(CustomerBO customer) { if (customer.getCustomerLevel().getId().equals(CustomerLevel.CLIENT.getValue())) { return FeeCategory.CLIENT; } else if (customer.getCustomerLevel().getId().equals(CustomerLevel.GROUP.getValue())) { return FeeCategory.GROUP; } else if (customer.getCustomerLevel().getId().equals(CustomerLevel.CENTER.getValue())) { return FeeCategory.CENTER; } return null; } private List<ApplicableCharge> getCustomerApplicableCharges(List<FeeBO> feeList, UserContext userContext, Short accountMeetingRecurrance) { List<ApplicableCharge> applicableChargeList = new ArrayList<ApplicableCharge>(); if (feeList != null && !feeList.isEmpty()) { filterBasedOnRecurranceType(feeList, accountMeetingRecurrance); populaleApplicableCharge(applicableChargeList, feeList, userContext); } return applicableChargeList; } private List<ApplicableCharge> getLoanApplicableCharges(List<FeeBO> feeList, UserContext userContext, LoanBO loanBO) { List<ApplicableCharge> applicableChargeList = new ArrayList<ApplicableCharge>(); if (feeList != null && !feeList.isEmpty()) { Short accountMeetingRecurrance = loanBO.getCustomer().getCustomerMeeting().getMeeting().getMeetingDetails() .getRecurrenceType().getRecurrenceId(); filterBasedOnRecurranceType(feeList, accountMeetingRecurrance); filterDisbursementFee(feeList, loanBO); filterTimeOfFirstRepaymentFee(feeList, loanBO); if(AccountingRules.isMultiCurrencyEnabled()){ filterBasedOnCurrencyOfLoan(feeList, loanBO); } filterForVariableInstallmentLoanType(feeList,loanBO); populaleApplicableCharge(applicableChargeList, feeList, userContext); } return applicableChargeList; } private void filterForVariableInstallmentLoanType(List<FeeBO> feeList, LoanBO loanBO) { if (loanBO.isOfType(AccountTypes.LOAN_ACCOUNT)) { if (loanBO.getLoanOffering().isVariableInstallmentsAllowed()) { for (Iterator<FeeBO> iter = feeList.iterator(); iter.hasNext();) { FeeBO fee = iter.next(); if (fee.isPeriodic()) { iter.remove(); } else if (fee.getFeeType().equals(RateAmountFlag.RATE)) { FeeFormula feeFormula = ((RateFeeBO) fee).getFeeFormula().getFeeFormula(); if (feeFormula != null) { if (feeFormula.equals(FeeFormula.AMOUNT_AND_INTEREST) || (feeFormula.equals(FeeFormula.INTEREST))) { iter.remove(); } } } } } } } private void filterBasedOnCurrencyOfLoan(List<FeeBO> feeList, LoanBO loanBO) { // remove fees where the currency of fee doesn't match the currency of loan. for (Iterator<FeeBO> iter = feeList.iterator(); iter.hasNext();) { FeeBO fee = iter.next(); if (fee.getFeeType().equals(RateAmountFlag.AMOUNT)) { if (!((AmountFeeBO) fee).getFeeAmount().getCurrency().equals(loanBO.getCurrency())) { iter.remove(); } } } } private void populaleApplicableCharge(List<ApplicableCharge> applicableChargeList, List<FeeBO> feeList, UserContext userContext) { for (FeeBO fee : feeList) { ApplicableCharge applicableCharge = new ApplicableCharge(); applicableCharge.setFeeId(fee.getFeeId().toString()); applicableCharge.setFeeName(fee.getFeeName()); applicableCharge.setIsPenaltyType(false); if (fee.getFeeType().getValue().equals(RateAmountFlag.RATE.getValue())) { applicableCharge.setAmountOrRate(new LocalizationConverter().getDoubleStringForInterest(((RateFeeBO) fee).getRate())); applicableCharge.setFormula(((RateFeeBO) fee).getFeeFormula().getFormulaStringThatHasName()); applicableCharge.setIsRateType(true); } else { applicableCharge.setAmountOrRate(((AmountFeeBO) fee).getFeeAmount().toString()); applicableCharge.setIsRateType(false); } MeetingBO meeting = fee.getFeeFrequency().getFeeMeetingFrequency(); if (meeting != null) { applicableCharge .setPeriodicity(new MeetingHelper().getDetailMessageWithFrequency(meeting, userContext)); } else { applicableCharge.setPaymentType(fee.getFeeFrequency().getFeePayment().getName()); } applicableChargeList.add(applicableCharge); } } private void filterBasedOnRecurranceType(List<FeeBO> feeList, Short accountMeetingRecurrance) { for (Iterator<FeeBO> iter = feeList.iterator(); iter.hasNext();) { FeeBO fee = iter.next(); if (fee.getFeeFrequency().getFeeFrequencyType().getId().equals(FeeFrequencyType.PERIODIC.getValue())) { Short feeRecurrance = fee.getFeeFrequency().getFeeMeetingFrequency().getMeetingDetails() .getRecurrenceTypeEnum().getValue(); if (!feeRecurrance.equals(accountMeetingRecurrance)) { iter.remove(); } } } } private void filterDisbursementFee(List<FeeBO> feeList, AccountBO account) { for (Iterator<FeeBO> iter = feeList.iterator(); iter.hasNext();) { FeeBO fee = iter.next(); FeePaymentEntity feePaymentEntity = fee.getFeeFrequency().getFeePayment(); if (feePaymentEntity != null) { Short paymentType = feePaymentEntity.getId(); if (paymentType.equals(FeePayment.TIME_OF_DISBURSEMENT.getValue())) { AccountState accountState = account.getState(); if (accountState == AccountState.LOAN_PARTIAL_APPLICATION || accountState == AccountState.LOAN_PENDING_APPROVAL || accountState == AccountState.LOAN_APPROVED || accountState == AccountState.LOAN_DISBURSED_TO_LOAN_OFFICER) { continue; } else { iter.remove(); } } } } } private void filterTimeOfFirstRepaymentFee(List<FeeBO> feeList, LoanBO loanBO) { for (Iterator<FeeBO> iter = feeList.iterator(); iter.hasNext();) { FeeBO fee = iter.next(); FeePaymentEntity feePaymentEntity = fee.getFeeFrequency().getFeePayment(); if (feePaymentEntity != null) { Short paymentType = feePaymentEntity.getId(); if (paymentType.equals(FeePayment.TIME_OF_FIRSTLOANREPAYMENT.getValue()) && loanBO.isCurrentDateGreaterThanFirstInstallment()) { iter.remove(); } } } } private void addMiscFeeAndPenalty(List<ApplicableCharge> applicableChargeList) { ApplicableCharge applicableCharge = new ApplicableCharge(); applicableCharge.setFeeId(AccountConstants.MISC_FEES); applicableCharge.setFeeName("Misc Fees"); applicableCharge.setIsRateType(false); applicableCharge.setIsPenaltyType(false); applicableChargeList.add(applicableCharge); applicableCharge = new ApplicableCharge(); applicableCharge.setFeeId(AccountConstants.MISC_PENALTY); applicableCharge.setFeeName("Misc Penalty"); applicableCharge.setIsRateType(false); applicableCharge.setIsPenaltyType(false); applicableChargeList.add(applicableCharge); } public String getStatusName(AccountState accountState, AccountTypes accountType) { return AccountStateMachines.getInstance().getAccountStatusName(accountState, accountType); } public String getFlagName(AccountStateFlag accountStateFlag, AccountTypes accountType) { return AccountStateMachines.getInstance().getAccountFlagName(accountStateFlag, accountType); } public List<AccountStateEntity> getStatusList(AccountStateEntity accountStateEntity, AccountTypes accountType, Short localeId) { List<AccountStateEntity> statusList = AccountStateMachines.getInstance().getStatusList(accountStateEntity, accountType); return statusList; } public void checkPermissionForStatusChange(Short newState, UserContext userContext, Short flagSelected, Short recordOfficeId, Short recordLoanOfficerId) throws ServiceException { if (!isPermissionAllowedForStatusChange(newState, userContext, flagSelected, recordOfficeId, recordLoanOfficerId)) { throw new ServiceException(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED); } } private boolean isPermissionAllowedForStatusChange(Short newState, UserContext userContext, Short flagSelected, Short recordOfficeId, Short recordLoanOfficerId) { return getActivityMapper().isStateChangePermittedForAccount(newState.shortValue(), null != flagSelected ? flagSelected.shortValue() : 0, userContext, recordOfficeId, recordLoanOfficerId); } public void checkPermissionForAdjustment(AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) throws ServiceException { if (!isPermissionAllowedForAdjustment(accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId)) { throw new ServiceException(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED); } } private boolean isPermissionAllowedForAdjustment(AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) { return getActivityMapper().isAdjustmentPermittedForAccounts(accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId); } ActivityMapper getActivityMapper() { return ActivityMapper.getInstance(); } public void checkPermissionForWaiveDue(WaiveEnum waiveEnum, AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) throws ApplicationException { if (!isPermissionAllowedForWaiveDue(waiveEnum, accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId)) { throw new CustomerException(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED); } } private boolean isPermissionAllowedForWaiveDue(WaiveEnum waiveEnum, AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) { return getActivityMapper().isWaiveDuePermittedForCustomers(waiveEnum, accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId); } public void checkPermissionForRemoveFees(AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) throws ApplicationException { if (!isPermissionAllowedForRemoveFees(accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId)) { throw new CustomerException(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED); } } private boolean isPermissionAllowedForRemoveFees(AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) { return getActivityMapper().isRemoveFeesPermittedForAccounts(accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId); } private LegacyAccountDao getlegacyAccountDao() { return ApplicationContextProvider.getBean(LegacyAccountDao.class); } public List<CustomerBO> getCoSigningClientsForGlim(Integer accountId) throws ServiceException { try { return getlegacyAccountDao().getCoSigningClientsForGlim(accountId); } catch (PersistenceException e) { throw new ServiceException(e); } } public void checkPermissionForAdjustmentOnBackDatedPayments(Date lastPaymentDate, UserContext userContext, Short recordOfficeId, Short recordLoanOfficer) throws ServiceException{ if (!getActivityMapper().isAdjustmentPermittedForBackDatedPayments(lastPaymentDate, userContext, recordOfficeId, recordLoanOfficer)) { throw new ServiceException(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED); } } public Object checkPermissionForRemovePenalties(AccountTypes accountTypes, CustomerLevel customerLevel, UserContext userContext, Short recordOfficeId, Short recordLoanOfficerId) { return getActivityMapper().isRemovePenaltiesPermittedForAccounts(accountTypes, customerLevel, userContext, recordOfficeId, recordLoanOfficerId); } }