/*
* 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.financial.business.service.activity.accountingentry;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.sql.Timestamp;
import java.util.Iterator;
import org.joda.time.DateMidnight;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifos.accounts.business.AccountPaymentEntity;
import org.mifos.accounts.financial.business.COABO;
import org.mifos.accounts.financial.business.FinancialActionTypeEntity;
import org.mifos.accounts.financial.business.FinancialTransactionBO;
import org.mifos.accounts.financial.business.GLCategoryType;
import org.mifos.accounts.financial.business.GLCodeEntity;
import org.mifos.accounts.financial.business.service.FinancialBusinessService;
import org.mifos.accounts.financial.business.service.activity.SavingsAdjustmentFinancialActivity;
import org.mifos.accounts.financial.exceptions.FinancialException;
import org.mifos.accounts.financial.util.helpers.FinancialActionConstants;
import org.mifos.accounts.financial.util.helpers.FinancialConstants;
import org.mifos.accounts.productdefinition.business.SavingsOfferingBO;
import org.mifos.accounts.productdefinition.business.SavingsTypeEntity;
import org.mifos.accounts.productdefinition.util.helpers.SavingsType;
import org.mifos.accounts.savings.business.SavingsBO;
import org.mifos.accounts.savings.business.SavingsTrxnDetailEntity;
import org.mifos.accounts.savings.util.helpers.SavingsHelper;
import org.mifos.accounts.util.helpers.AccountActionTypes;
import org.mifos.application.master.business.MifosCurrency;
import org.mifos.customers.personnel.business.PersonnelBO;
import org.mifos.framework.TestUtils;
import org.mifos.framework.util.helpers.Money;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
/**
* I test {@link SavingsAdjustmentAccountingEntry}.
*/
@RunWith(MockitoJUnitRunner.class)
public class SavingsAdjustmentAccountingEntryTest extends BaseAccountingEntryTestCase {
@Mock
private SavingsAdjustmentFinancialActivity mockedFinancialActivity;
@Mock
private SavingsTrxnDetailEntity mockedIncomingTransaction;
@Mock
private SavingsBO mockedSavingsBO;
@Mock
private SavingsOfferingBO mockedSavingsOffering;
@Mock
private SavingsTypeEntity mockedSavingsType;
@Mock
private GLCodeEntity mockedBankGLCode;
@Mock
private GLCodeEntity mockedSavingsDepositGLCode;
@Mock
private FinancialBusinessService mockedFinancialBusinessService;
@Mock
private COABO mockedBankGLAccount;
@Mock
private COABO mockedSavingsGLAccount;
@Mock
private FinancialActionTypeEntity mockedFinancialAction;
@Mock
private SavingsHelper mockedSavingsHelper;
@Mock
private PersonnelBO mockedTransactionCreator;
// Test parameters set up the same for all tests
private Money withdrawalAmount;
private Money depositAmount;
private MifosCurrency currency;
private DateMidnight transactionActionDate;
private DateMidnight transactionPostedDate;
private String savingsDepositGLCodeString;
private String bankGLCodeString;
private String commentString;
private short expectedAccountingUpdatedFlag;
@Before
public void setupForAllTests() {
// Refresh mocks before each test
mockedFinancialActivity = mock(SavingsAdjustmentFinancialActivity.class);
mockedIncomingTransaction = mock(SavingsTrxnDetailEntity.class);
mockedSavingsBO = mock(SavingsBO.class);
mockedSavingsOffering = mock(SavingsOfferingBO.class);
mockedSavingsType = mock(SavingsTypeEntity.class);
// mockedAccountPayment = mock(AccountPaymentEntity.class);
// mockedLastTransaction = mock(AccountTrxnEntity.class);
// mockedAccountAction = mock(AccountActionEntity.class);
mockedBankGLCode = mock(GLCodeEntity.class);
mockedSavingsDepositGLCode = mock(GLCodeEntity.class);
mockedFinancialBusinessService = mock(FinancialBusinessService.class);
// mockedSavingsGLCategory = mock(COABO.class);
// mockedBankGLCategory = mock(COABO.class);
mockedBankGLAccount = mock(COABO.class);
mockedSavingsGLAccount = mock(COABO.class);
mockedFinancialAction = mock(FinancialActionTypeEntity.class);
mockedSavingsHelper = mock(SavingsHelper.class);
// Hard-coded values that are just passed through and thus not relevant to what's being tested
currency = TestUtils.RUPEE;
withdrawalAmount = new Money(currency, "20");
depositAmount = new Money(currency, "30");
transactionActionDate = new DateMidnight(2009, 9, 9);
transactionPostedDate = new DateMidnight(2009, 1, 1);
commentString = "test comment";
expectedAccountingUpdatedFlag = (short) 1; // Always set to 1
/*
* The method under test creates a set with two transactions, a transaction on the savings account and a
* transaction on the bank's account, each of which is verified differently. In order to know which is which,
* the set is converted to a list that is sorted on GL code.
*/
bankGLCodeString = "1"; // trans on asset acccount sorts first
savingsDepositGLCodeString = "2"; // trans on savings account sorts second
}
private void setUpOneMandatorySavingsTest(SavingsType savingsType, AccountActionTypes accountActionType,
GLCategoryType bankCategoryType, GLCategoryType savingsCategoryType,
FinancialConstants debitOrCreditToBankGLAccount, FinancialActionConstants financialAction)
throws FinancialException {
when(mockedFinancialActivity.getAccountTrxn()).thenReturn(mockedIncomingTransaction);
when(mockedIncomingTransaction.getAccount()).thenReturn(mockedSavingsBO);
when(mockedIncomingTransaction.getWithdrawlAmount()).thenReturn(withdrawalAmount);
when(mockedIncomingTransaction.getDepositAmount()).thenReturn(depositAmount);
when(mockedIncomingTransaction.getActionDate()).thenReturn(transactionActionDate.toDate());
when(mockedIncomingTransaction.getTrxnCreatedDate()).thenReturn(
new Timestamp(transactionPostedDate.getMillis()));
when(mockedIncomingTransaction.getPersonnel()).thenReturn(mockedTransactionCreator);
when(mockedIncomingTransaction.getComments()).thenReturn(commentString);
when(mockedSavingsBO.getSavingsOffering()).thenReturn(mockedSavingsOffering);
when(mockedSavingsBO.isMandatory()).thenReturn(true);
when(mockedSavingsOffering.getDepositGLCode()).thenReturn(mockedSavingsDepositGLCode);
when(mockedSavingsDepositGLCode.getGlcode()).thenReturn(savingsDepositGLCodeString);
when(mockedSavingsGLAccount.getGlCode()).thenReturn(savingsDepositGLCodeString);
when(mockedSavingsGLAccount.getAccountName()).thenReturn("Clients Accounts");
when(mockedSavingsGLAccount.getTopLevelCategoryType()).thenReturn(savingsCategoryType);
when(mockedBankGLAccount.getAssociatedGlcode()).thenReturn(mockedBankGLCode);
when(mockedBankGLAccount.getGlCode()).thenReturn(bankGLCodeString);
when(mockedBankGLAccount.getTopLevelCategoryType()).thenReturn(bankCategoryType);
when(mockedBankGLCode.getGlcode()).thenReturn(bankGLCodeString);
when(mockedFinancialBusinessService.getGlAccount(savingsDepositGLCodeString))
.thenReturn(mockedSavingsGLAccount);
when(mockedFinancialBusinessService.getGlAccount(bankGLCodeString)).thenReturn(mockedBankGLAccount);
when(mockedFinancialBusinessService.getFinancialAction(financialAction)).thenReturn(mockedFinancialAction);
if (debitOrCreditToBankGLAccount.equals(FinancialConstants.DEBIT)) {
when(mockedFinancialAction.getApplicableDebitCharts()).thenReturn(setWith(mockedBankGLAccount));
} else {
when(mockedFinancialAction.getApplicableCreditCharts()).thenReturn(setWith(mockedBankGLAccount));
}
when(mockedSavingsType.getId()).thenReturn(savingsType.getValue());
when(mockedSavingsHelper.getPaymentActionType((AccountPaymentEntity) any())).thenReturn(
accountActionType.getValue());
}
private void setUpOneVoluntarySavingsTest(SavingsType savingsType, AccountActionTypes accountActionType,
GLCategoryType bankCategoryType, GLCategoryType savingsCategoryType,
FinancialConstants debitOrCreditToBankGLAccount, FinancialActionConstants financialAction)
throws FinancialException {
when(mockedFinancialActivity.getAccountTrxn()).thenReturn(mockedIncomingTransaction);
when(mockedIncomingTransaction.getAccount()).thenReturn(mockedSavingsBO);
when(mockedIncomingTransaction.getWithdrawlAmount()).thenReturn(withdrawalAmount);
when(mockedIncomingTransaction.getDepositAmount()).thenReturn(depositAmount);
when(mockedIncomingTransaction.getActionDate()).thenReturn(transactionActionDate.toDate());
when(mockedIncomingTransaction.getTrxnCreatedDate()).thenReturn(
new Timestamp(transactionPostedDate.getMillis()));
when(mockedIncomingTransaction.getPersonnel()).thenReturn(mockedTransactionCreator);
when(mockedIncomingTransaction.getComments()).thenReturn(commentString);
when(mockedSavingsBO.getSavingsOffering()).thenReturn(mockedSavingsOffering);
when(mockedSavingsBO.isMandatory()).thenReturn(false);
when(mockedSavingsBO.isVoluntary()).thenReturn(true);
when(mockedSavingsOffering.getDepositGLCode()).thenReturn(mockedSavingsDepositGLCode);
when(mockedSavingsDepositGLCode.getGlcode()).thenReturn(savingsDepositGLCodeString);
when(mockedSavingsGLAccount.getGlCode()).thenReturn(savingsDepositGLCodeString);
when(mockedSavingsGLAccount.getAccountName()).thenReturn("Clients Accounts");
when(mockedSavingsGLAccount.getTopLevelCategoryType()).thenReturn(savingsCategoryType);
when(mockedBankGLAccount.getAssociatedGlcode()).thenReturn(mockedBankGLCode);
when(mockedBankGLAccount.getGlCode()).thenReturn(bankGLCodeString);
when(mockedBankGLAccount.getTopLevelCategoryType()).thenReturn(bankCategoryType);
when(mockedBankGLCode.getGlcode()).thenReturn(bankGLCodeString);
when(mockedFinancialBusinessService.getGlAccount(savingsDepositGLCodeString))
.thenReturn(mockedSavingsGLAccount);
when(mockedFinancialBusinessService.getGlAccount(bankGLCodeString)).thenReturn(mockedBankGLAccount);
when(mockedFinancialBusinessService.getFinancialAction(financialAction)).thenReturn(mockedFinancialAction);
if (debitOrCreditToBankGLAccount.equals(FinancialConstants.DEBIT)) {
when(mockedFinancialAction.getApplicableDebitCharts()).thenReturn(setWith(mockedBankGLAccount));
} else {
when(mockedFinancialAction.getApplicableCreditCharts()).thenReturn(setWith(mockedBankGLAccount));
}
when(mockedSavingsType.getId()).thenReturn(savingsType.getValue());
when(mockedSavingsHelper.getPaymentActionType((AccountPaymentEntity) any())).thenReturn(
accountActionType.getValue());
}
// @Test
// public void testBuildAccountEntryAdjustSavingsWithdrawalForMandatorySavings() throws FinancialException {
//
// runOneTest(SavingsType.MANDATORY, AccountActionTypes.SAVINGS_WITHDRAWAL, GLCategoryType.ASSET,
// GLCategoryType.LIABILITY, FinancialActionConstants.MANDATORYWITHDRAWAL_ADJUSTMENT,
// FinancialConstants.DEBIT, FinancialConstants.CREDIT, withdrawalAmount);
// }
//
// @Test
// public void testBuildAccountEntryAdjustSavingsWithdrawalForVoluntarySavings() throws FinancialException {
//
// runOneTest(SavingsType.VOLUNTARY, AccountActionTypes.SAVINGS_WITHDRAWAL, GLCategoryType.ASSET,
// GLCategoryType.LIABILITY, FinancialActionConstants.VOLUNTARYWITHDRAWAL_ADJUSTMENT,
// FinancialConstants.DEBIT, FinancialConstants.CREDIT, withdrawalAmount);
// }
@Test
public void testBuildAccountEntryAdjustSavingsDepositForMandatorySavings() throws FinancialException {
runOneTest(SavingsType.MANDATORY, AccountActionTypes.SAVINGS_DEPOSIT, GLCategoryType.ASSET,
GLCategoryType.LIABILITY, FinancialActionConstants.MANDATORYDEPOSIT_ADJUSTMENT,
FinancialConstants.CREDIT, FinancialConstants.DEBIT, depositAmount);
}
@Test
public void testBuildAccountEntryAdjustSavingsDepositForVoluntarySavings() throws FinancialException {
runOneTest(SavingsType.VOLUNTARY, AccountActionTypes.SAVINGS_DEPOSIT, GLCategoryType.ASSET,
GLCategoryType.LIABILITY, FinancialActionConstants.VOLUNTARYDEPOSIT_ADJUSTMENT,
FinancialConstants.CREDIT, FinancialConstants.DEBIT, depositAmount);
}
// @Test(expected = FinancialException.class)
// public void testReThrowsFinancialExceptionAdjustSavingsWithdrawalForMandatorySavings() throws FinancialException {
//
// runOneTestMockFinancialBusinessServiceThrowsException(SavingsType.MANDATORY,
// AccountActionTypes.SAVINGS_WITHDRAWAL, GLCategoryType.ASSET, GLCategoryType.LIABILITY,
// FinancialActionConstants.MANDATORYWITHDRAWAL_ADJUSTMENT, FinancialConstants.DEBIT);
// }
//
// @Test(expected = FinancialException.class)
// public void testReThrowsFinancialExceptionAdjustSavingsWithdrawalForVoluntarySavings() throws FinancialException {
//
// runOneTestMockFinancialBusinessServiceThrowsException(SavingsType.VOLUNTARY,
// AccountActionTypes.SAVINGS_WITHDRAWAL, GLCategoryType.ASSET, GLCategoryType.LIABILITY,
// FinancialActionConstants.VOLUNTARYWITHDRAWAL_ADJUSTMENT, FinancialConstants.DEBIT);
// }
@Test(expected = FinancialException.class)
public void testReThrowsFinancialExceptionAdjustSavingsDepositForMandatorySavings() throws FinancialException {
runOneTestMockFinancialBusinessServiceThrowsException(SavingsType.MANDATORY,
AccountActionTypes.SAVINGS_DEPOSIT, GLCategoryType.ASSET, GLCategoryType.LIABILITY,
FinancialActionConstants.MANDATORYDEPOSIT_ADJUSTMENT, FinancialConstants.CREDIT);
}
/**
* ignoring, too hard to debug due to complicated setup.
*/
@Ignore
@Test(expected = FinancialException.class)
public void testReThrowsFinancialExceptionAdjustSavingsDepositForVoluntarySavings() throws FinancialException {
runOneTestMockFinancialBusinessServiceThrowsException(SavingsType.VOLUNTARY,
AccountActionTypes.SAVINGS_DEPOSIT, GLCategoryType.ASSET, GLCategoryType.LIABILITY,
FinancialActionConstants.VOLUNTARYDEPOSIT_ADJUSTMENT, FinancialConstants.CREDIT);
}
private void runOneTest(SavingsType savingsType, AccountActionTypes accountActionType,
GLCategoryType bankCategoryType, GLCategoryType savingsCategoryType,
FinancialActionConstants financialAction, FinancialConstants bankDebitCredit,
FinancialConstants savingsDebitCredit, Money amount) throws FinancialException {
/*
* Test-specific settings
*/
if (savingsType.equals(SavingsType.MANDATORY)) {
setUpOneMandatorySavingsTest(savingsType, accountActionType, bankCategoryType, savingsCategoryType,
bankDebitCredit, financialAction);
} else {
setUpOneVoluntarySavingsTest(savingsType, accountActionType, bankCategoryType, savingsCategoryType,
bankDebitCredit, financialAction);
}
doBuild(new SavingsAdjustmentAccountingEntry(), mockedFinancialBusinessService, mockedSavingsHelper,
mockedFinancialActivity);
// verify the two transactions created
verifyCreatedTransactions(amount, mockedFinancialActivity, mockedIncomingTransaction, mockedFinancialAction,
mockedBankGLCode, mockedSavingsDepositGLCode, bankCategoryType, bankDebitCredit, savingsCategoryType,
savingsDebitCredit);
}
private void doBuild(SavingsAdjustmentAccountingEntry entry, FinancialBusinessService financialBusinessService,
SavingsHelper savingsHelper, SavingsAdjustmentFinancialActivity financialActivity)
throws FinancialException {
injectMocks(entry, financialBusinessService, savingsHelper);
entry.buildAccountEntryForAction(financialActivity);
}
private void injectMocks(SavingsAdjustmentAccountingEntry entry, FinancialBusinessService financialBusinessService,
SavingsHelper savingsHelper) {
entry.setFinancialBusinessService(financialBusinessService);
entry.setSavingsHelper(savingsHelper);
}
private void runOneTestMockFinancialBusinessServiceThrowsException(SavingsType savingsType,
AccountActionTypes accountActionType, GLCategoryType bankCategoryType, GLCategoryType savingsCategoryType,
FinancialActionConstants financialAction, FinancialConstants bankDebitCredit) throws FinancialException {
/*
* Test-specific settings
*/
setUpOneMandatorySavingsTest(savingsType, accountActionType, bankCategoryType, savingsCategoryType, bankDebitCredit,
financialAction);
SavingsAdjustmentAccountingEntry entry = new SavingsAdjustmentAccountingEntry();
when(mockedFinancialBusinessService.getFinancialAction(financialAction)).thenThrow(
new FinancialException("a FinancialException"));
doBuild(entry, mockedFinancialBusinessService, mockedSavingsHelper, mockedFinancialActivity);
}
private void verifyCreatedTransactions(Money transactionAmount,
SavingsAdjustmentFinancialActivity mockedFinancialActivity,
SavingsTrxnDetailEntity mockedIncomingTransaction, FinancialActionTypeEntity mockedFinancialAction,
GLCodeEntity mockedBankGLCode, GLCodeEntity mockedSavingsDepositGLCode, GLCategoryType bankCategoryType,
FinancialConstants bankDebitCredit, GLCategoryType savingsCategoryType,
FinancialConstants savingsDebitCredit) {
Iterator<FinancialTransactionBO> it = getIteratorOnSortedTransactions(mockedFinancialActivity, 2);
/*
* Verify the post to the bank's asset account
*/
verifyCreatedFinancialTransaction(it.next(), mockedIncomingTransaction, null, mockedFinancialAction,
mockedBankGLCode, transactionActionDate.toDate(), mockedTransactionCreator,
expectedAccountingUpdatedFlag, transactionAmount, commentString, bankDebitCredit.getValue(), transactionPostedDate.toDate());
/*
* Verify the post to the savings liability account
*/
verifyCreatedFinancialTransaction(it.next(), mockedIncomingTransaction, null, mockedFinancialAction,
mockedSavingsDepositGLCode, transactionActionDate.toDate(), mockedTransactionCreator,
expectedAccountingUpdatedFlag, transactionAmount, commentString, savingsDebitCredit.getValue(), transactionPostedDate
.toDate());
}
}