From 9599c1197ac2d281dac5f054b281b6a654cd9bcb Mon Sep 17 00:00:00 2001 From: Madhukar Date: Wed, 9 Jul 2014 15:28:08 +0530 Subject: [PATCH] MIFOSX-1398,MIFOSX-1403 --- .../AccountingScenarioIntegrationTest.java | 71 +-- .../ClientSavingsIntegrationTest.java | 72 ++- .../integrationtests/FixedDepositTest.java | 364 ++++++++++-- .../GroupSavingsIntegrationTest.java | 60 +- .../RecurringDepositTest.java | 539 ++++++++++++++++-- .../FinancialActivityAccountHelper.java | 3 +- .../common/savings/SavingsAccountHelper.java | 14 +- .../common/savings/SavingsProductHelper.java | 14 + ...ountTransfersWritePlatformServiceImpl.java | 28 +- ...ructionHistoryReadPlatformServiceImpl.java | 15 +- .../loanproduct/service/LoanEnumerations.java | 2 +- .../savings/SavingsApiConstants.java | 4 +- .../SavingsTransactionBooleanValues.java | 41 ++ ...avingsAccountTransactionDataValidator.java | 39 +- .../DepositAccountDomainServiceJpa.java | 23 +- .../savings/domain/SavingsAccount.java | 4 +- .../domain/SavingsAccountDomainService.java | 4 +- .../SavingsAccountDomainServiceJpa.java | 17 +- ...WritePlatformServiceJpaRepositoryImpl.java | 43 +- 19 files changed, 1177 insertions(+), 180 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsTransactionBooleanValues.java diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenarioIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenarioIntegrationTest.java index a7a006115..a19581ec0 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenarioIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenarioIntegrationTest.java @@ -422,7 +422,7 @@ public class AccountingScenarioIntegrationTest { final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String EXPECTED_FIRST_DEPOSIT_ON_DATE = dateFormat.format(todaysDate.getTime()); - + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; @@ -432,7 +432,8 @@ public class AccountingScenarioIntegrationTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, assetAccount, liabilityAccount, incomeAccount, expenseAccount); + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, assetAccount, liabilityAccount, + incomeAccount, expenseAccount); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -450,23 +451,26 @@ public class AccountingScenarioIntegrationTest { recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.activateRecurringDeposit(recurringDepositAccountId, ACTIVATION_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsActive(recurringDepositAccountStatusHashMap); - - HashMap recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, this.responseSpec, recurringDepositAccountId); + + HashMap recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); Float depositAmount = (Float) recurringDepositAccountData.get("mandatoryRecommendedDepositAmount"); - - Integer depositTransactionId = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, depositAmount, EXPECTED_FIRST_DEPOSIT_ON_DATE); + + Integer depositTransactionId = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, + depositAmount, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(depositTransactionId); - - // Checking initial Journal entries after Activation. + + // Checking initial Journal entries after Activation. final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.DEBIT) }; final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.CREDIT) }; this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, assetAccountInitialEntry); - this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, liablilityAccountInitialEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, + liablilityAccountInitialEntry); Integer interestPostingTransactionId = this.recurringDepositAccountHelper .postInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(interestPostingTransactionId); - + HashMap accountSummary = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); @@ -508,8 +512,7 @@ public class AccountingScenarioIntegrationTest { System.out.println("------------------------------CREATING NEW RECURRING DEPOSIT PRODUCT ---------------------------------------"); RecurringDepositProductHelper recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); final String recurringDepositProductJSON = recurringDepositProductHelper // - .withAccountingRuleAsCashBased(accounts) - .build(validFrom, validTo); + .withAccountingRuleAsCashBased(accounts).build(validFrom, validTo); return RecurringDepositProductHelper.createRecurringDepositProduct(recurringDepositProductJSON, requestSpec, responseSpec); } @@ -568,7 +571,8 @@ public class AccountingScenarioIntegrationTest { final float FIRST_PRINCIPAL = 2000.0f; final float FEE_PORTION = 0.0f; final float PENALTY_PORTION = 0.0f; - this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[1]), FIRST_INTEREST, FEE_PORTION, PENALTY_PORTION, loanID); + this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[1]), FIRST_INTEREST, + FEE_PORTION, PENALTY_PORTION, loanID); this.loanTransactionHelper.makeRepayment(this.REPAYMENT_DATE[1], this.REPAYMENT_AMOUNT[1], loanID); float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD; this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID); @@ -584,19 +588,23 @@ public class AccountingScenarioIntegrationTest { final float SECOND_AND_THIRD_INTEREST = 400.0f; final float SECOND_PRINCIPAL = this.REPAYMENT_AMOUNT[2] - SECOND_AND_THIRD_INTEREST; expected_value = expected_value - PRINCIPAL_VALUE_FOR_EACH_PERIOD; - this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[2]), FIRST_INTEREST, FEE_PORTION, PENALTY_PORTION, loanID); - this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[3]), FIRST_INTEREST, FEE_PORTION, PENALTY_PORTION, loanID); + this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[2]), FIRST_INTEREST, + FEE_PORTION, PENALTY_PORTION, loanID); + this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[3]), FIRST_INTEREST, + FEE_PORTION, PENALTY_PORTION, loanID); this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(2, expected_value, loanID); final JournalEntry[] assetAccountSecondEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[2], JournalEntry.TransactionType.DEBIT), new JournalEntry(SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT), new JournalEntry(SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT), }; this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[2], assetAccountSecondEntry); System.out.println("Repayment 2 Done ......"); - + // WAIVE INTEREST System.out.println("Waive Interest ......"); - this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[4]), FIRST_INTEREST, FEE_PORTION, PENALTY_PORTION, loanID); - this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[5]), FIRST_INTEREST, FEE_PORTION, PENALTY_PORTION, loanID); + this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[4]), FIRST_INTEREST, + FEE_PORTION, PENALTY_PORTION, loanID); + this.loanTransactionHelper.checkAccrualTransactionForRepayment(getDateAsLocalDate(this.REPAYMENT_DATE[5]), FIRST_INTEREST, + FEE_PORTION, PENALTY_PORTION, loanID); this.loanTransactionHelper.waiveInterest(this.REPAYMENT_DATE[4], this.AMOUNT_TO_BE_WAIVE.toString(), loanID); final JournalEntry waivedEntry = new JournalEntry(this.AMOUNT_TO_BE_WAIVE, JournalEntry.TransactionType.CREDIT); @@ -605,7 +613,7 @@ public class AccountingScenarioIntegrationTest { final JournalEntry expenseJournalEntry = new JournalEntry(this.AMOUNT_TO_BE_WAIVE, JournalEntry.TransactionType.DEBIT); this.journalEntryHelper.checkJournalEntryForExpenseAccount(expenseAccount, this.REPAYMENT_DATE[4], expenseJournalEntry); System.out.println("Waive Interest Done......"); - + // REPAYMENT 3 System.out.println("Repayment 3 ......"); this.loanTransactionHelper.makeRepayment(this.REPAYMENT_DATE[3], this.REPAYMENT_AMOUNT[3], loanID); @@ -646,7 +654,7 @@ public class AccountingScenarioIntegrationTest { .build(null); return this.loanTransactionHelper.getLoanProductId(loanProductJSON); } - + @Test public void checkCashBasedAccountingFlow() { final Account assetAccount = this.accountHelper.createAssetAccount(); @@ -677,7 +685,7 @@ public class AccountingScenarioIntegrationTest { final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(this.LP_PRINCIPAL, JournalEntry.TransactionType.CREDIT), new JournalEntry(this.LP_PRINCIPAL, JournalEntry.TransactionType.DEBIT) }; this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.EXPECTED_DISBURSAL_DATE, assetAccountInitialEntry); - + // MAKE 1 System.out.println("Repayment 1 ......"); this.loanTransactionHelper.makeRepayment(this.REPAYMENT_DATE[1], this.REPAYMENT_AMOUNT[1], loanID); @@ -707,15 +715,15 @@ public class AccountingScenarioIntegrationTest { this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, this.REPAYMENT_DATE[2], new JournalEntry( SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT)); System.out.println("Repayment 2 Done ......"); - + // WAIVE INTEREST System.out.println("Waive Interest ......"); - Integer transactionId = this.loanTransactionHelper.waiveInterestAndReturnTransactionId(this.REPAYMENT_DATE[4], this.AMOUNT_TO_BE_WAIVE.toString(), loanID); - // waive of fees and interest are not considered in cash based accounting, - this.journalEntryHelper.ensureNoAccountingTransactionsWithTransactionId("L"+transactionId); - - - + Integer transactionId = this.loanTransactionHelper.waiveInterestAndReturnTransactionId(this.REPAYMENT_DATE[4], + this.AMOUNT_TO_BE_WAIVE.toString(), loanID); + // waive of fees and interest are not considered in cash based + // accounting, + this.journalEntryHelper.ensureNoAccountingTransactionsWithTransactionId("L" + transactionId); + // REPAYMENT 3 System.out.println("Repayment 3 ......"); this.loanTransactionHelper.makeRepayment(this.REPAYMENT_DATE[3], this.REPAYMENT_AMOUNT[3], loanID); @@ -725,7 +733,7 @@ public class AccountingScenarioIntegrationTest { this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(3, expected_value, loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[3], assetAccountThirdEntry); System.out.println("Repayment 3 Done ......"); - + // REPAYMENT 4 System.out.println("Repayment 4 ......"); this.loanTransactionHelper.makeRepayment(this.REPAYMENT_DATE[4], this.REPAYMENT_AMOUNT[4], loanID); @@ -746,14 +754,13 @@ public class AccountingScenarioIntegrationTest { this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[5], assetAccountFifthEntry); System.out.println("Repayment 5 Done ......"); } - + private Integer createLoanProductWithCashBasedAccountingEnabled(final Account... accounts) { System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(this.LP_PRINCIPAL.toString()).withRepaymentTypeAsMonth() .withRepaymentAfterEvery(this.LP_REPAYMENT_PERIOD).withNumberOfRepayments(this.LP_REPAYMENTS).withRepaymentTypeAsMonth() .withinterestRatePerPeriod(this.LP_INTEREST_RATE).withInterestRateFrequencyTypeAsMonths() - .withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRuleAsCashBased(accounts) - .build(null); + .withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRuleAsCashBased(accounts).build(null); return this.loanTransactionHelper.getLoanProductId(loanProductJSON); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java index 30e457893..473d9c9f9 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java @@ -60,8 +60,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -101,8 +104,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = "5000"; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -135,15 +141,21 @@ public class ClientSavingsIntegrationTest { } + @SuppressWarnings("unchecked") @Test public void testSavingsAccount_CLOSE_APPLICATION() { this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(400).build(); + final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; - - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, null, minBalanceForInterestCalculation); + final String minRequiredBalance = "1000.0"; + final String enforceMinRequiredBalance = "true"; + final boolean allowOverdraft = false; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -158,7 +170,14 @@ public class ClientSavingsIntegrationTest { savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId); SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - savingsStatusHashMap = this.savingsAccountHelper.closeSavingsAccount(savingsId); + String withdrawBalance = "false"; + ArrayList savingsAccountErrorData = (ArrayList) validationErrorHelper.closeSavingsAccountAndGetBackRequiredField( + savingsId, withdrawBalance, CommonConstants.RESPONSE_ERROR); + assertEquals("validation.msg.savingsaccount.close.results.in.balance.not.zero", + savingsAccountErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + withdrawBalance = "true"; + savingsStatusHashMap = this.savingsAccountHelper.closeSavingsAccount(savingsId, withdrawBalance); SavingsStatusChecker.verifySavingsAccountIsClosed(savingsStatusHashMap); } @@ -173,7 +192,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, null, minBalanceForInterestCalculation); + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -212,8 +235,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -254,8 +280,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -279,8 +308,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -374,8 +406,11 @@ public class ClientSavingsIntegrationTest { final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = false; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -502,8 +537,11 @@ public class ClientSavingsIntegrationTest { * enabled */ final String zeroOpeningBalance = "0.0"; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final boolean allowOverdraft = true; final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, zeroOpeningBalance, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance, allowOverdraft); Assert.assertNotNull(savingsProductID); /*** @@ -617,16 +655,22 @@ public class ClientSavingsIntegrationTest { } private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance, String minBalanceForInterestCalculation) { + final String minOpenningBalance, String minBalanceForInterestCalculation, String minRequiredBalance, + String enforceMinRequiredBalance, final boolean allowOverdraft) { System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); - final String overDraftLimit = "2000.0"; + if (allowOverdraft) { + final String overDraftLimit = "2000.0"; + savingsProductHelper = savingsProductHelper.withOverDraft(overDraftLimit); + } + final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // .withInterestCalculationPeriodTypeAsDailyBalance() // .withMinBalanceForInterestCalculation(minBalanceForInterestCalculation)// - .withOverDraft(overDraftLimit) + .withMinRequiredBalance(minRequiredBalance) + .withEnforceMinRequiredBalance(enforceMinRequiredBalance) .withMinimumOpenningBalance(minOpenningBalance).build(); return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FixedDepositTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FixedDepositTest.java index ba86d13e8..9b761da46 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FixedDepositTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/FixedDepositTest.java @@ -18,11 +18,16 @@ import org.joda.time.Months; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mifosplatform.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY; import org.mifosplatform.integrationtests.common.ClientHelper; import org.mifosplatform.integrationtests.common.CommonConstants; import org.mifosplatform.integrationtests.common.Utils; import org.mifosplatform.integrationtests.common.accounting.Account; import org.mifosplatform.integrationtests.common.accounting.AccountHelper; +import org.mifosplatform.integrationtests.common.accounting.FinancialActivityAccountHelper; +import org.mifosplatform.integrationtests.common.accounting.JournalEntry; +import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper; +import org.mifosplatform.integrationtests.common.accounting.Account.AccountType; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountHelper; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountStatusChecker; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositProductHelper; @@ -46,6 +51,8 @@ public class FixedDepositTest { private FixedDepositAccountHelper fixedDepositAccountHelper; private AccountHelper accountHelper; private SavingsAccountHelper savingsAccountHelper; + private JournalEntryHelper journalEntryHelper; + private FinancialActivityAccountHelper financialActivityAccountHelper; public static final String WHOLE_TERM = "1"; public static final String TILL_PREMATURE_WITHDRAWAL = "2"; @@ -59,6 +66,9 @@ public class FixedDepositTest { private static final String DAYS_360 = "360"; private static final String DAYS_365 = "365"; + private static final String NONE = "1"; + private static final String CASH_BASED = "2"; + public static final String MINIMUM_OPENING_BALANCE = "1000.0"; public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; public static final String CLOSURE_TYPE_WITHDRAW_DEPOSIT = "100"; @@ -77,17 +87,31 @@ public class FixedDepositTest { this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.requestSpec.header("X-Mifos-Platform-TenantId", "default"); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec); } + /*** + * Test case for Fixed Deposit Account premature closure with + * transaction type withdrawal and Cash Based accounting enabled + */ @Test public void testFixedDepositAccountWithPrematureClosureTypeWithdrawal() { this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec); + + /*** + * Create GL Accounts for product account mapping + */ + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -101,15 +125,28 @@ public class FixedDepositTest { final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create FD product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, liabilityAccount, + incomeAccount, expenseAccount); Assert.assertNotNull(fixedDepositProductId); + /*** + * Apply for FD account with created product and verify status + */ Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM); Assert.assertNotNull(fixedDepositAccountId); @@ -118,18 +155,57 @@ public class FixedDepositTest { this.responseSpec, fixedDepositAccountId.toString()); FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap); + /*** + * Approve the FD account and verify whether account is approved + */ fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE); FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap); + /*** + * Activate the FD Account and verify whether account is activated + */ fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE); FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap); + + HashMap accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + Float depositAmount = (Float) accountSummary.get("totalDeposits"); + + /*** + * Verify journal entries posted for initial deposit transaction which + * happened at activation time + */ + final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, ACTIVATION_DATE, assetAccountInitialEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, ACTIVATION_DATE, liablilityAccountInitialEntry); + + /*** + * Update interest earned of FD account + */ fixedDepositAccountId = this.fixedDepositAccountHelper.calculateInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(fixedDepositAccountId); + /*** + * Post interest and verify the account summary + */ Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); + + accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + /*** + * Verify journal entries transactions for interest posting transaction + */ + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + + /*** + * Preclose the FD account verify whether account is preClosed + */ HashMap fixedDepositPrematureData = this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE); @@ -141,17 +217,42 @@ public class FixedDepositTest { this.responseSpec, fixedDepositAccountId.toString()); FixedDepositAccountStatusChecker.verifyFixedDepositAccountIsPrematureClosed(fixedDepositAccountStatusHashMap); + /*** + * Verify journal entry transactions for preclosure transaction + */ + HashMap accountDetails = this.fixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec, + fixedDepositAccountId); + Float maturityAmount = Float.valueOf(accountDetails.get("maturityAmount").toString()); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.CREDIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.DEBIT)); + } + /*** + * Test case for FD Account premature closure with transaction transfers to + * savings account and Cash Based accounting enabled + */ @Test public void testFixedDepositAccountWithPrematureClosureTypeTransferToSavings() { this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec); + this.financialActivityAccountHelper = new FinancialActivityAccountHelper(this.requestSpec); + + /*** + * Create GL Accounts for product account mapping + */ + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -165,13 +266,23 @@ public class FixedDepositTest { final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); + Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + /*** + * Create Savings product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, accountingRule, + assetAccount, liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientId, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); @@ -186,7 +297,11 @@ public class FixedDepositTest { savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId); SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create FD product with CashBased accounting enabled + */ + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, liabilityAccount, + incomeAccount, expenseAccount); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -203,19 +318,56 @@ public class FixedDepositTest { fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE); FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap); + HashMap accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + + Float depositAmount = (Float) accountSummary.get("totalDeposits"); + + /*** + * Verify journal entries posted for initial deposit transaction which + * happened at activation time + */ + final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, ACTIVATION_DATE, assetAccountInitialEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, ACTIVATION_DATE, liablilityAccountInitialEntry); + + /*** + * Update interest earned of FD account + */ fixedDepositAccountId = this.fixedDepositAccountHelper.calculateInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(fixedDepositAccountId); + /*** + * Post interest and verify the account summary + */ Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); - HashMap savingsSummaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId); + accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + /*** + * Verify journal entries transactions for interest posting transaction + */ + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + + HashMap savingsSummaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId); Float balanceBefore = (Float) savingsSummaryBefore.get("accountBalance"); + + /*** + * Retrieve mapped financial account for liability transfer + */ + Account financialAccount = getMappedLiabilityFinancialAccount(); HashMap fixedDepositPrematureData = this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE); + /*** + * Preclose the account and verify journal entries + */ Integer prematureClosureTransactionId = (Integer) this.fixedDepositAccountHelper.prematureCloseForFixedDeposit( fixedDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_TRANSFER_TO_SAVINGS, savingsId, CommonConstants.RESPONSE_RESOURCE_ID); Assert.assertNotNull(prematureClosureTransactionId); @@ -228,6 +380,17 @@ public class FixedDepositTest { fixedDepositAccountId); Float prematurityAmount = (Float) fixedDepositData.get("maturityAmount"); + /*** + * Verify journal entry transactions for preclosure transaction As this + * transaction is an account transfer you should get financial account + * mapping details and verify amounts + */ + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, CLOSED_ON_DATE, new JournalEntry(prematurityAmount, + JournalEntry.TransactionType.CREDIT), new JournalEntry(prematurityAmount, JournalEntry.TransactionType.DEBIT)); + + this.journalEntryHelper.checkJournalEntryForAssetAccount(financialAccount, CLOSED_ON_DATE, new JournalEntry(prematurityAmount, + JournalEntry.TransactionType.DEBIT), new JournalEntry(prematurityAmount, JournalEntry.TransactionType.CREDIT)); + HashMap savingsSummaryAfter = this.savingsAccountHelper.getSavingsSummary(savingsId); Float balanceAfter = (Float) savingsSummaryAfter.get("accountBalance"); Float expectedSavingsBalance = balanceBefore + prematurityAmount; @@ -236,6 +399,10 @@ public class FixedDepositTest { } + /*** + * Test case for Fixed Deposit Account premature closure with + * transaction type ReInvest and Cash Based accounting enabled + */ @Test public void testFixedDepositAccountWithPrematureClosureTypeReinvest() { this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); @@ -246,8 +413,17 @@ public class FixedDepositTest { FixedDepositAccountHelper fixedDepositAccountHelperValidationError = new FixedDepositAccountHelper(this.requestSpec, new ResponseSpecBuilder().build()); + /*** + * Create GL Accounts for product account mapping + */ + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -261,13 +437,23 @@ public class FixedDepositTest { final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create FD product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, liabilityAccount, + incomeAccount, expenseAccount); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -283,6 +469,19 @@ public class FixedDepositTest { fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE); FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap); + + HashMap accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + + Float depositAmount = (Float) accountSummary.get("totalDeposits"); + + /*** + * Verify journal entries posted for initial deposit transaction which + * happened at activation time + */ + final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(depositAmount, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, ACTIVATION_DATE, assetAccountInitialEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, ACTIVATION_DATE, liablilityAccountInitialEntry); fixedDepositAccountId = this.fixedDepositAccountHelper.calculateInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(fixedDepositAccountId); @@ -290,6 +489,17 @@ public class FixedDepositTest { Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); + accountSummary = this.fixedDepositAccountHelper.getFixedDepositSummary(fixedDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + + /*** + * Verify journal entries transactions for interest posting transaction + */ + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + HashMap fixedDepositPrematureData = this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE); @@ -323,7 +533,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); ArrayList allFixedDepositProductsData = this.fixedDepositProductHelper.retrieveAllFixedDepositProducts(this.requestSpec, @@ -366,7 +577,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -408,7 +620,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -448,7 +661,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -486,7 +700,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -528,7 +743,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -597,7 +813,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -673,7 +890,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -717,7 +935,6 @@ public class FixedDepositTest { todaysDate.add(Calendar.DATE, daysInMonth); System.out.println(monthDayFormat.format(todaysDate.getTime())); - currentDate = currentDate - 1; interestPerMonth = (float) (interestPerDay * principal * currentDate); System.out.println("IPM = " + interestPerMonth); principal += interestPerMonth; @@ -777,7 +994,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -825,7 +1043,6 @@ public class FixedDepositTest { todaysDate.add(Calendar.DATE, daysInMonth); System.out.println(monthDayFormat.format(todaysDate.getTime())); - currentDate = currentDate - 1; interestPerMonth = (float) (interestPerDay * principal * currentDate); System.out.println("IPM = " + interestPerMonth); principal += interestPerMonth; @@ -885,7 +1102,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -938,7 +1156,6 @@ public class FixedDepositTest { todaysDate.add(Calendar.DATE, daysInMonth); System.out.println(monthDayFormat.format(todaysDate.getTime())); - currentDate = currentDate - 1; interestPerMonth = (float) (interestPerDay * principal * currentDate); System.out.println("IPM = " + interestPerMonth); principal += interestPerMonth; @@ -997,7 +1214,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1054,7 +1272,6 @@ public class FixedDepositTest { todaysDate.add(Calendar.DATE, daysInMonth); System.out.println(monthDayFormat.format(todaysDate.getTime())); - currentDate = currentDate - 1; interestPerMonth = (float) (interestPerDay * principal * currentDate); System.out.println("IPM = " + interestPerMonth); principal += interestPerMonth; @@ -1109,7 +1326,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1184,7 +1402,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1265,7 +1484,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1348,7 +1568,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1432,7 +1653,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1513,7 +1735,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1594,7 +1817,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1674,7 +1898,8 @@ public class FixedDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(fixedDepositProductId); Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), VALID_FROM, @@ -1720,9 +1945,15 @@ public class FixedDepositTest { Assert.assertEquals("Verifying Pre-Closure maturity amount", expectedPrematureAmount, maturityAmount); } - private Integer createFixedDepositProduct(final String validFrom, final String validTo) { + private Integer createFixedDepositProduct(final String validFrom, final String validTo, final String accountingRule, + Account... accounts) { System.out.println("------------------------------CREATING NEW FIXED DEPOSIT PRODUCT ---------------------------------------"); FixedDepositProductHelper fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); + if (accountingRule.equals(CASH_BASED)) { + fixedDepositProductHelper = fixedDepositProductHelper.withAccountingRuleAsCashBased(accounts); + } else if (accountingRule.equals(NONE)) { + fixedDepositProductHelper = fixedDepositProductHelper.withAccountingRuleAsNone(); + } final String fixedDepositProductJSON = fixedDepositProductHelper // .build(validFrom, validTo); return FixedDepositProductHelper.createFixedDepositProduct(fixedDepositProductJSON, requestSpec, responseSpec); @@ -1738,9 +1969,16 @@ public class FixedDepositTest { } private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance) { + final String minOpenningBalance, final String accountingRule, Account... accounts) { System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); + SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); + if (accountingRule.equals(CASH_BASED)) { + savingsProductHelper = savingsProductHelper.withAccountingRuleAsCashBased(accounts); + } else if (accountingRule.equals(NONE)) { + savingsProductHelper = savingsProductHelper.withAccountingRuleAsNone(); + } + final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // @@ -1748,4 +1986,58 @@ public class FixedDepositTest { .withMinimumOpenningBalance(minOpenningBalance).build(); return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); } + + private Account getMappedLiabilityFinancialAccount() { + final Integer liabilityTransferFinancialActivityId = FINANCIAL_ACTIVITY.LIABILITY_TRANSFER.getValue(); + List financialActivities = this.financialActivityAccountHelper.getAllFinancialActivityAccounts(this.responseSpec); + final Account financialAccount; + /*** + * if no financial activities are defined for account transfers, create + * liability financial accounting mappings + */ + if (financialActivities.isEmpty()) { + financialAccount = createLiabilityFinancialAccountTransferType(liabilityTransferFinancialActivityId); + } else { + /*** + * extract mapped liability financial account + */ + Account mappedLiabilityAccount = null; + for (HashMap financialActivity : financialActivities) { + HashMap financialActivityData = (HashMap) financialActivity.get("financialActivityData"); + if (financialActivityData.get("id").equals(liabilityTransferFinancialActivityId)) { + HashMap glAccountData = (HashMap) financialActivity.get("glAccountData"); + mappedLiabilityAccount = new Account((Integer) glAccountData.get("id"), AccountType.LIABILITY); + break; + } + } + /*** + * If liability transfer is not defined create liability transfer + */ + if (mappedLiabilityAccount == null) { + mappedLiabilityAccount = createLiabilityFinancialAccountTransferType(liabilityTransferFinancialActivityId); + } + financialAccount = mappedLiabilityAccount; + } + return financialAccount; + } + + private Account createLiabilityFinancialAccountTransferType(final Integer liabilityTransferFinancialActivityId) { + /*** + * Create and verify financial account transfer type is created + */ + final Account liabilityAccountForMapping = this.accountHelper.createLiabilityAccount(); + Integer financialActivityAccountId = (Integer) financialActivityAccountHelper.createFinancialActivityAccount( + liabilityTransferFinancialActivityId, liabilityAccountForMapping.getAccountID(), this.responseSpec, + CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(financialActivityAccountId); + assertFinancialActivityAccountCreation(financialActivityAccountId, liabilityTransferFinancialActivityId, liabilityAccountForMapping); + return liabilityAccountForMapping; + } + + private void assertFinancialActivityAccountCreation(Integer financialActivityAccountId, Integer financialActivityId, Account glAccount) { + HashMap mappingDetails = this.financialActivityAccountHelper.getFinancialActivityAccount(financialActivityAccountId, + this.responseSpec); + Assert.assertEquals(financialActivityId, ((HashMap) mappingDetails.get("financialActivityData")).get("id")); + Assert.assertEquals(glAccount.getAccountID(), ((HashMap) mappingDetails.get("glAccountData")).get("id")); + } } \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java index af1db0bb5..c0fdc7b23 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java @@ -65,7 +65,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -95,9 +99,12 @@ public class GroupSavingsIntegrationTest { final Object savingsInterest = this.savingsAccountHelper.getSavingsInterest(savingsId); } + @SuppressWarnings("unchecked") @Test public void testSavingsAccount_CLOSE_APPLICATION() { this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); + final ResponseSpecification errorResponse = new ResponseSpecBuilder().expectStatusCode(400).build(); + final SavingsAccountHelper validationErrorHelper = new SavingsAccountHelper(this.requestSpec, errorResponse); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientID); @@ -108,7 +115,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, null); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = "1000.0"; + final String enforceMinRequiredBalance = "true"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -123,7 +134,14 @@ public class GroupSavingsIntegrationTest { savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId); SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - savingsStatusHashMap = this.savingsAccountHelper.closeSavingsAccount(savingsId); + String withdrawBalance = "false"; + ArrayList savingsAccountErrorData = (ArrayList) validationErrorHelper.closeSavingsAccountAndGetBackRequiredField( + savingsId, withdrawBalance, CommonConstants.RESPONSE_ERROR); + assertEquals("validation.msg.savingsaccount.close.results.in.balance.not.zero", + savingsAccountErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + withdrawBalance = "true"; + savingsStatusHashMap = this.savingsAccountHelper.closeSavingsAccount(savingsId, withdrawBalance); SavingsStatusChecker.verifySavingsAccountIsClosed(savingsStatusHashMap); } @@ -144,7 +162,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, null); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -189,7 +211,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -235,7 +261,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -265,7 +295,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -365,7 +399,11 @@ public class GroupSavingsIntegrationTest { groupID = GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupID.toString(), clientID.toString()); Assert.assertNotNull(groupID); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final String minBalanceForInterestCalculation = null; + final String minRequiredBalance = null; + final String enforceMinRequiredBalance = "false"; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + minBalanceForInterestCalculation, minRequiredBalance, enforceMinRequiredBalance); Assert.assertNotNull(savingsProductID); final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(groupID, savingsProductID, ACCOUNT_TYPE_GROUP); @@ -471,13 +509,17 @@ public class GroupSavingsIntegrationTest { } public static Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance) { + final String minOpenningBalance, final String minBalanceForInterestCalculation, final String minRequiredBalance, + final String enforceMinRequiredBalance) { System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // .withInterestCalculationPeriodTypeAsDailyBalance() // + .withMinBalanceForInterestCalculation(minBalanceForInterestCalculation) // + .withMinRequiredBalance(minRequiredBalance) // + .withEnforceMinRequiredBalance(enforceMinRequiredBalance) // .withMinimumOpenningBalance(minOpenningBalance).build(); return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/RecurringDepositTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/RecurringDepositTest.java index ad3a472f2..b8799b7ed 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/RecurringDepositTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/RecurringDepositTest.java @@ -8,6 +8,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; +import java.util.List; import net.sf.ehcache.transaction.xa.EhcacheXAException; @@ -16,11 +17,16 @@ import org.joda.time.Months; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mifosplatform.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY; import org.mifosplatform.integrationtests.common.ClientHelper; import org.mifosplatform.integrationtests.common.CommonConstants; import org.mifosplatform.integrationtests.common.Utils; import org.mifosplatform.integrationtests.common.accounting.Account; +import org.mifosplatform.integrationtests.common.accounting.Account.AccountType; import org.mifosplatform.integrationtests.common.accounting.AccountHelper; +import org.mifosplatform.integrationtests.common.accounting.FinancialActivityAccountHelper; +import org.mifosplatform.integrationtests.common.accounting.JournalEntry; +import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountHelper; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositAccountStatusChecker; import org.mifosplatform.integrationtests.common.fixeddeposit.FixedDepositProductHelper; @@ -46,6 +52,8 @@ public class RecurringDepositTest { private SavingsAccountHelper savingsAccountHelper; private AccountHelper accountHelper; private RecurringDepositAccountHelper recurringDepositAccountHelper; + private JournalEntryHelper journalEntryHelper; + private FinancialActivityAccountHelper financialActivityAccountHelper; public static final String WHOLE_TERM = "1"; private static final String TILL_PREMATURE_WITHDRAWAL = "2"; @@ -58,6 +66,8 @@ public class RecurringDepositTest { private static final String INTEREST_CALCULATION_USING_AVERAGE_DAILY_BALANCE = "2"; private static final String DAYS_360 = "360"; private static final String DAYS_365 = "365"; + private static final String NONE = "1"; + private static final String CASH_BASED = "2"; public static final String MINIMUM_OPENING_BALANCE = "1000.0"; public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; @@ -79,16 +89,30 @@ public class RecurringDepositTest { this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.requestSpec.header("X-Mifos-Platform-TenantId", "default"); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec); } + /*** + * Test case for Recurring Deposit Account premature closure with + * transaction type withdrawal and Cash Based accounting enabled + */ @Test public void testRecurringDepositAccountWithPrematureClosureTypeWithdrawal() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.recurringDepositAccountHelper = new RecurringDepositAccountHelper(this.requestSpec, this.responseSpec); + /*** + * Create GL Accounts for product account mapping + */ + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -103,15 +127,31 @@ public class RecurringDepositTest { final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String EXPECTED_FIRST_DEPOSIT_ON_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); + + /*** + * Create client for applying Deposit account + */ Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create RD product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, + liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(recurringDepositProductId); + /*** + * Apply for RD account with created product and verify status + */ Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(recurringDepositAccountId); @@ -120,28 +160,67 @@ public class RecurringDepositTest { this.requestSpec, this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsPending(recurringDepositAccountStatusHashMap); + /*** + * Approve the RD account and verify whether account is approved + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.approveRecurringDeposit(recurringDepositAccountId, APPROVED_ON_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsApproved(recurringDepositAccountStatusHashMap); + /*** + * Activate the RD Account and verify whether account is activated + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.activateRecurringDeposit(recurringDepositAccountId, ACTIVATION_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsActive(recurringDepositAccountStatusHashMap); + HashMap recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); + Float depositAmount = (Float) recurringDepositAccountData.get("mandatoryRecommendedDepositAmount"); + + /*** + * Perform Deposit transaction and verify journal entries are posted for + * the transaction + */ Integer depositTransactionId = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, - DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); + depositAmount, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(depositTransactionId); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.DEBIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.CREDIT)); + + /*** + * Update interest earned field for RD account + */ recurringDepositAccountId = this.recurringDepositAccountHelper.calculateInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(recurringDepositAccountId); + /*** + * Post interest and verify journal entries + */ Integer transactionIdForPostInterest = this.recurringDepositAccountHelper .postInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); + HashMap accountSummary = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + + /*** + * Calculate expected premature closure amount + */ HashMap recurringDepositPrematureData = this.recurringDepositAccountHelper.calculatePrematureAmountForRecurringDeposit( recurringDepositAccountId, CLOSED_ON_DATE); + /*** + * Preclose the RD account verify whether account is preClosed + */ Integer prematureClosureTransactionId = (Integer) this.recurringDepositAccountHelper.prematureCloseForRecurringDeposit( recurringDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_WITHDRAW_DEPOSIT, null, CommonConstants.RESPONSE_RESOURCE_ID); Assert.assertNotNull(prematureClosureTransactionId); @@ -150,15 +229,35 @@ public class RecurringDepositTest { this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositAccountIsPrematureClosed(recurringDepositAccountStatusHashMap); + /*** + * Verify journal entry transactions for preclosure transaction + */ + recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); + Float maturityAmount = Float.valueOf(recurringDepositAccountData.get("maturityAmount").toString()); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.CREDIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.DEBIT)); + } + /*** + * Test case for Recurring Deposit Account premature closure with + * transaction transfers to savings account and Cash Based accounting + * enabled + */ @Test public void testRecurringDepositAccountWithPrematureClosureTypeTransferToSavings() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.recurringDepositAccountHelper = new RecurringDepositAccountHelper(this.requestSpec, this.responseSpec); + this.financialActivityAccountHelper = new FinancialActivityAccountHelper(this.requestSpec); + /*** + * Create GL Accounts for product account mapping + */ final Account assetAccount = this.accountHelper.createAssetAccount(); final Account incomeAccount = this.accountHelper.createIncomeAccount(); final Account expenseAccount = this.accountHelper.createExpenseAccount(); @@ -166,6 +265,7 @@ public class RecurringDepositTest { DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -180,30 +280,59 @@ public class RecurringDepositTest { final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String EXPECTED_FIRST_DEPOSIT_ON_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); + + /*** + * Create client for applying Deposit and Savings accounts + */ Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + /*** + * Create Savings product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + final Integer savingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, accountingRule, + assetAccount, liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(savingsProductID); + /*** + * Create Savings account and verify status is pending + */ final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientId, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL); Assert.assertNotNull(savingsProductID); HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, savingsId); SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap); + /*** + * Approve the savings account and verify account is approved + */ savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsId); SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap); + /*** + * Activate the savings account and verify account is activated + */ savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId); SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create RD product with CashBased accounting enabled + */ + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, + liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(recurringDepositProductId); + /*** + * Apply for RD account with created product and verify status + */ Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(recurringDepositAccountId); @@ -212,32 +341,75 @@ public class RecurringDepositTest { this.requestSpec, this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsPending(recurringDepositAccountStatusHashMap); + /*** + * Approve the RD account and verify whether account is approved + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.approveRecurringDeposit(recurringDepositAccountId, APPROVED_ON_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsApproved(recurringDepositAccountStatusHashMap); + /*** + * Activate the RD Account and verify whether account is activated + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.activateRecurringDeposit(recurringDepositAccountId, ACTIVATION_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsActive(recurringDepositAccountStatusHashMap); + HashMap recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); + Float depositAmount = (Float) recurringDepositAccountData.get("mandatoryRecommendedDepositAmount"); + + /*** + * Perform Deposit transaction and verify journal entries are posted for + * the transaction + */ Integer depositTransactionId = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, - DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); + depositAmount, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(depositTransactionId); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.DEBIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.CREDIT)); + + /*** + * Update interest earned field for RD account + */ recurringDepositAccountId = this.recurringDepositAccountHelper.calculateInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(recurringDepositAccountId); + /*** + * Post interest and verify journal entries + */ Integer transactionIdForPostInterest = this.recurringDepositAccountHelper .postInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); - HashMap savingsSummaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId); + HashMap accountSummary = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + + /*** + * Get saving account balance before preClosing RD account + */ + HashMap savingsSummaryBefore = this.savingsAccountHelper.getSavingsSummary(savingsId); Float balanceBefore = (Float) savingsSummaryBefore.get("accountBalance"); HashMap recurringDepositPrematureData = this.recurringDepositAccountHelper.calculatePrematureAmountForRecurringDeposit( recurringDepositAccountId, CLOSED_ON_DATE); + /*** + * Retrieve mapped financial account for liability transfer + */ + Account financialAccount = getMappedLiabilityFinancialAccount(); + + /*** + * Preclose the RD account verify whether account is preClosed + */ Integer prematureClosureTransactionId = (Integer) this.recurringDepositAccountHelper.prematureCloseForRecurringDeposit( recurringDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_TRANSFER_TO_SAVINGS, savingsId, CommonConstants.RESPONSE_RESOURCE_ID); @@ -247,6 +419,22 @@ public class RecurringDepositTest { this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositAccountIsPrematureClosed(recurringDepositAccountStatusHashMap); + recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); + Float maturityAmount = Float.valueOf(recurringDepositAccountData.get("maturityAmount").toString()); + /*** + * Verify journal entry transactions for preclosure transaction As this + * transaction is an account transfer you should get financial account + * mapping details and verify amounts + */ + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.CREDIT), new JournalEntry(maturityAmount, JournalEntry.TransactionType.DEBIT)); + + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(financialAccount, CLOSED_ON_DATE, new JournalEntry(maturityAmount, + JournalEntry.TransactionType.DEBIT), new JournalEntry(maturityAmount, JournalEntry.TransactionType.CREDIT)); + /*** + * Verify rd account maturity amount and savings account balance + */ HashMap recurringDepositData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, this.responseSpec, recurringDepositAccountId); Float prematurityAmount = (Float) recurringDepositData.get("maturityAmount"); @@ -263,6 +451,10 @@ public class RecurringDepositTest { } + /*** + * Test case for Recurring Deposit Account premature closure with + * transaction type ReInvest and Cash Based accounting enabled + */ @Test public void testRecurringDepositAccountWithPrematureClosureTypeReinvest() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -273,8 +465,17 @@ public class RecurringDepositTest { RecurringDepositAccountHelper recurringDepositAccountHelperValidationError = new RecurringDepositAccountHelper(this.requestSpec, new ResponseSpecBuilder().build()); + /*** + * Create GL Accounts for product account mapping + */ + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); DateFormat monthDayFormat = new SimpleDateFormat("dd MMM"); + DateFormat currentDateFormat = new SimpleDateFormat("dd"); Calendar todaysDate = Calendar.getInstance(); todaysDate.add(Calendar.MONTH, -3); @@ -289,13 +490,26 @@ public class RecurringDepositTest { final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); final String EXPECTED_FIRST_DEPOSIT_ON_DATE = dateFormat.format(todaysDate.getTime()); final String MONTH_DAY = monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + Integer currentDate = new Integer(currentDateFormat.format(todaysDate.getTime())); + Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); + Integer numberOfDaysLeft = (daysInMonth - currentDate) + 1; + todaysDate.add(Calendar.DATE, numberOfDaysLeft); + final String INTEREST_POSTED_DATE = dateFormat.format(todaysDate.getTime()); + final String CLOSED_ON_DATE = dateFormat.format(Calendar.getInstance().getTime()); + + /*** + * Create client for applying Deposit account + */ Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create RD product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, + liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(recurringDepositProductId); ArrayList allRecurringDepositProductsData = this.recurringDepositProductHelper.retrieveAllRecurringDepositProducts( @@ -303,6 +517,9 @@ public class RecurringDepositTest { HashMap recurringDepositProductData = this.recurringDepositProductHelper.retrieveRecurringDepositProductById(this.requestSpec, this.responseSpec, recurringDepositProductId.toString()); + /*** + * Apply for RD account with created product and verify status + */ Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(recurringDepositAccountId); @@ -311,28 +528,68 @@ public class RecurringDepositTest { this.requestSpec, this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsPending(recurringDepositAccountStatusHashMap); + /*** + * Approve the RD account and verify whether account is approved + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.approveRecurringDeposit(recurringDepositAccountId, APPROVED_ON_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsApproved(recurringDepositAccountStatusHashMap); + /*** + * Activate the RD Account and verify whether account is activated + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.activateRecurringDeposit(recurringDepositAccountId, ACTIVATION_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsActive(recurringDepositAccountStatusHashMap); + HashMap recurringDepositAccountData = this.recurringDepositAccountHelper.getRecurringDepositAccountById(this.requestSpec, + this.responseSpec, recurringDepositAccountId); + Float depositAmount = (Float) recurringDepositAccountData.get("mandatoryRecommendedDepositAmount"); + + /*** + * Perform Deposit transaction and verify journal entries are posted for + * the transaction + */ Integer depositTransactionId = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, DEPOSIT_AMOUNT, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(depositTransactionId); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.DEBIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, EXPECTED_FIRST_DEPOSIT_ON_DATE, new JournalEntry( + depositAmount, JournalEntry.TransactionType.CREDIT)); + + /*** + * Update interest earned field for RD account + */ recurringDepositAccountId = this.recurringDepositAccountHelper.calculateInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(recurringDepositAccountId); + /*** + * Post interest and verify journal entries + */ Integer transactionIdForPostInterest = this.recurringDepositAccountHelper .postInterestForRecurringDeposit(recurringDepositAccountId); Assert.assertNotNull(transactionIdForPostInterest); + HashMap accountSummary = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); + Float totalInterestPosted = (Float) accountSummary.get("totalInterestPosted"); + + final JournalEntry[] expenseAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.DEBIT) }; + final JournalEntry[] liablilityAccountEntry = { new JournalEntry(totalInterestPosted, JournalEntry.TransactionType.CREDIT) }; + this.journalEntryHelper.checkJournalEntryForAssetAccount(expenseAccount, INTEREST_POSTED_DATE, expenseAccountEntry); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, INTEREST_POSTED_DATE, liablilityAccountEntry); + + /*** + * Calculate expected premature closure amount + */ HashMap recurringDepositPrematureData = this.recurringDepositAccountHelper.calculatePrematureAmountForRecurringDeposit( recurringDepositAccountId, CLOSED_ON_DATE); + /*** + * Expected to get an error response from api because re-invest option + * is not supported for account preClosure + */ ArrayList errorResponse = (ArrayList) recurringDepositAccountHelperValidationError .prematureCloseForRecurringDeposit(recurringDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_REINVEST, null, CommonConstants.RESPONSE_ERROR); @@ -342,6 +599,9 @@ public class RecurringDepositTest { } + /*** + * Test case for Update Recurring Deposit Account details + */ @Test public void testRecurringDepositAccountUpdation() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -365,7 +625,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -381,6 +642,9 @@ public class RecurringDepositTest { } + /*** + * Test case for Approve and Undo Approval of Recurring Deposit Account + */ @Test public void testRecurringDepositAccountUndoApproval() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -405,7 +669,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -424,6 +689,9 @@ public class RecurringDepositTest { RecurringDepositAccountStatusChecker.verifyRecurringDepositIsPending(recurringDepositAccountStatusHashMap); } + /*** + * Test case for Closure of Recurring Deposit Account(Reject Application) + */ @Test public void testRecurringDepositAccountRejectedAndClosed() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -449,7 +717,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -466,6 +735,10 @@ public class RecurringDepositTest { RecurringDepositAccountStatusChecker.verifyRecurringDepositAccountIsClosed(recurringDepositAccountStatusHashMap); } + /*** + * Test case for Closure of Recurring Deposit Account(Withdrawn by + * applicant) + */ @Test public void testRecurringDepositAccountWithdrawnByClientAndClosed() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -491,7 +764,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -508,6 +782,9 @@ public class RecurringDepositTest { RecurringDepositAccountStatusChecker.verifyRecurringDepositAccountIsClosed(recurringDepositAccountStatusHashMap); } + /*** + * Test case for Delete of Recurring Deposit Account. + */ @Test public void testRecurringDepositAccountIsDeleted() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -531,7 +808,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -547,12 +825,18 @@ public class RecurringDepositTest { Assert.assertNotNull(recurringDepositAccountId); } + /*** + * Test case for update Recurring deposit account transactions + */ @Test public void testUpdateAndUndoTransactionForRecurringDepositAccount() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.recurringDepositAccountHelper = new RecurringDepositAccountHelper(this.requestSpec, this.responseSpec); + /*** + * Create GL Accounts for product account mapping + */ final Account assetAccount = this.accountHelper.createAssetAccount(); final Account incomeAccount = this.accountHelper.createIncomeAccount(); final Account expenseAccount = this.accountHelper.createExpenseAccount(); @@ -577,12 +861,23 @@ public class RecurringDepositTest { todaysDate.add(Calendar.MONTH, 1); final String DEPOSIT_DATE = dateFormat.format(todaysDate.getTime()); + /*** + * Create client for applying Deposit account + */ Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + /*** + * Create RD product with CashBased accounting enabled + */ + final String accountingRule = CASH_BASED; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule, assetAccount, + liabilityAccount, incomeAccount, expenseAccount); Assert.assertNotNull(recurringDepositProductId); + /*** + * Apply for RD account with created product and verify status + */ Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(recurringDepositAccountId); @@ -591,10 +886,16 @@ public class RecurringDepositTest { this.requestSpec, this.responseSpec, recurringDepositAccountId.toString()); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsPending(recurringDepositAccountStatusHashMap); + /*** + * Approve the RD account and verify whether account is approved + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.approveRecurringDeposit(recurringDepositAccountId, APPROVED_ON_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsApproved(recurringDepositAccountStatusHashMap); + /*** + * Activate the RD Account and verify whether account is activated + */ recurringDepositAccountStatusHashMap = this.recurringDepositAccountHelper.activateRecurringDeposit(recurringDepositAccountId, ACTIVATION_DATE); RecurringDepositAccountStatusChecker.verifyRecurringDepositIsActive(recurringDepositAccountStatusHashMap); @@ -602,22 +903,41 @@ public class RecurringDepositTest { HashMap recurringDepositSummaryBefore = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); Float balanceBefore = (Float) recurringDepositSummaryBefore.get("accountBalance"); + /*** + * Perform Deposit transaction and verify journal entries are posted for + * the transaction + */ Integer transactionIdForDeposit = this.recurringDepositAccountHelper.depositToRecurringDepositAccount(recurringDepositAccountId, DEPOSIT_AMOUNT, DEPOSIT_DATE); Assert.assertNotNull(transactionIdForDeposit); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, DEPOSIT_DATE, new JournalEntry(DEPOSIT_AMOUNT, + JournalEntry.TransactionType.DEBIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, DEPOSIT_DATE, new JournalEntry(DEPOSIT_AMOUNT, + JournalEntry.TransactionType.CREDIT)); + + /*** + * verify account balances after transactions + */ Float expectedBalanceAfter = balanceBefore + DEPOSIT_AMOUNT; HashMap recurringDepositSummaryAfter = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); Float balanceAfter = (Float) recurringDepositSummaryAfter.get("accountBalance"); Assert.assertEquals("Verifying account balance after deposit", expectedBalanceAfter, balanceAfter); + /*** + * Update transaction and verify account balance after transaction + */ Float updatedTransactionAmount = DEPOSIT_AMOUNT - 1000.0f; - Integer updateTransactionId = this.recurringDepositAccountHelper.updateTransactionForRecurringDeposit(recurringDepositAccountId, transactionIdForDeposit, DEPOSIT_DATE, updatedTransactionAmount); Assert.assertNotNull(updateTransactionId); + this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, DEPOSIT_DATE, new JournalEntry(updatedTransactionAmount, + JournalEntry.TransactionType.DEBIT)); + this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, DEPOSIT_DATE, new JournalEntry( + updatedTransactionAmount, JournalEntry.TransactionType.CREDIT)); + expectedBalanceAfter = DEPOSIT_AMOUNT - updatedTransactionAmount; recurringDepositSummaryAfter = this.recurringDepositAccountHelper.getRecurringDepositSummary(recurringDepositAccountId); balanceAfter = (Float) recurringDepositSummaryAfter.get("accountBalance"); @@ -636,6 +956,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify maturity amount with monthly compounding and monthly + * posting with 365 days in year + */ @Test public void testMaturityAmountForMonthlyCompoundingAndMonthlyPosting_With_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -664,7 +988,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -711,6 +1036,10 @@ public class RecurringDepositTest { Assert.assertEquals("Verifying Maturity amount for Recurring Deposit Account", principal, maturityAmount); } + /*** + * Test case for verify maturity amount with monthly compounding and monthly + * posting with 360 days in year + */ @Test public void testMaturityAmountForMonthlyCompoundingAndMonthlyPosting_With_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -739,7 +1068,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -791,6 +1121,9 @@ public class RecurringDepositTest { Assert.assertEquals("Verifying Maturity amount for Recurring Deposit Account", principal, maturityAmount); } + /*** + * Test case for verify interest posting of RD account + */ @Test public void testPostInterestForRecurringDeposit() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -817,7 +1150,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -882,6 +1216,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with penal interest for + * whole term with closure transaction type withdrawal and 365 days in year + */ @Test public void testPrematureClosureAmountWithPenalInterestForWholeTerm_With_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -917,7 +1255,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1004,6 +1343,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with penal interest for + * whole term with closure transaction type withdrawal and 360 days in year + */ @Test public void testPrematureClosureAmountWithPenalInterestForWholeTerm_With_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1039,7 +1382,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1131,6 +1475,11 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with penal interest till + * maturity date with closure transaction type withdrawal and 365 days in + * year + */ @Test public void testPrematureClosureAmountWithPenalInterestTillPrematureWithdrawal_With_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1168,7 +1517,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1265,6 +1615,11 @@ public class RecurringDepositTest { } + /*** + * Test case verify premature closure amount with penal interest till + * maturity date with closure transaction type withdrawal and 360 days in + * year + */ @Test public void testPrematureClosureAmountWithPenalInterestTillPrematureWithdrawal_With_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1302,7 +1657,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1404,6 +1760,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify maturity amount with daily compounding and monthly + * posting with 365 days in year + */ @Test public void testMaturityAmountForDailyCompoundingAndMonthlyPosting_With_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1432,9 +1792,9 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); - Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE); Assert.assertNotNull(recurringDepositAccountId); @@ -1484,6 +1844,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify maturity amount with daily compounding and monthly + * posting with 360 days in year + */ @Test public void testMaturityAmountForDailyCompoundingAndMonthlyPosting_With_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1512,7 +1876,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1564,6 +1929,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with Bi-annual interest + * compounding and Bi-annual interest posting with 365 days in year + */ @Test public void testRecurringDepositWithBi_AnnualCompoundingAndPosting_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1599,7 +1968,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1650,6 +2020,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with Bi-annual interest + * compounding and Bi-annual interest posting with 360 days in year + */ @Test public void testRecurringDepositWithBi_AnnualCompoundingAndPosting_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1685,7 +2059,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1736,6 +2111,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify maturity amount with Daily interest compounding and + * annual interest posting with 365 days in year + */ @Test public void testMaturityAmountForDailyCompoundingAndAnnuallyPosting_With_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1770,7 +2149,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1822,6 +2202,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify maturity amount with Daily interest compounding and + * annual interest posting with 360 days in year + */ @Test public void testMaturityAmountForDailyCompoundingAndAnnuallyPosting_With_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1856,7 +2240,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1908,6 +2293,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with Quarterly interest + * compounding and Quarterly interest posting with 365 days in year + */ @Test public void testRecurringDepositQuarterlyCompoundingAndQuarterlyPosting_365_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -1943,7 +2332,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -1994,6 +2384,10 @@ public class RecurringDepositTest { } + /*** + * Test case for verify premature closure amount with Quarterly interest + * compounding and Quarterly interest posting with 360 days in year + */ @Test public void testRecurringDepositQuarterlyCompoundingAndQuarterlyPosting_360_Days() { this.recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); @@ -2029,7 +2423,8 @@ public class RecurringDepositTest { Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assert.assertNotNull(clientId); - Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO); + final String accountingRule = NONE; + Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, accountingRule); Assert.assertNotNull(recurringDepositProductId); Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(), @@ -2080,11 +2475,16 @@ public class RecurringDepositTest { } - private Integer createRecurringDepositProduct(final String validFrom, final String validTo, Account... accounts) { + private Integer createRecurringDepositProduct(final String validFrom, final String validTo, final String accountingRule, + Account... accounts) { System.out.println("------------------------------CREATING NEW RECURRING DEPOSIT PRODUCT ---------------------------------------"); RecurringDepositProductHelper recurringDepositProductHelper = new RecurringDepositProductHelper(this.requestSpec, this.responseSpec); - final String recurringDepositProductJSON = recurringDepositProductHelper // - .build(validFrom, validTo); + if (accountingRule.equals(CASH_BASED)) { + recurringDepositProductHelper = recurringDepositProductHelper.withAccountingRuleAsCashBased(accounts); + } else if (accountingRule.equals(NONE)) { + recurringDepositProductHelper = recurringDepositProductHelper.withAccountingRuleAsNone(); + } + final String recurringDepositProductJSON = recurringDepositProductHelper.build(validFrom, validTo); return RecurringDepositProductHelper.createRecurringDepositProduct(recurringDepositProductJSON, requestSpec, responseSpec); } @@ -2099,9 +2499,14 @@ public class RecurringDepositTest { } private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance) { + final String minOpenningBalance, final String accountingRule, Account... accounts) { System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); + if (accountingRule.equals(CASH_BASED)) { + savingsProductHelper = savingsProductHelper.withAccountingRuleAsCashBased(accounts); + } else if (accountingRule.equals(NONE)) { + savingsProductHelper = savingsProductHelper.withAccountingRuleAsNone(); + } final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // @@ -2109,4 +2514,58 @@ public class RecurringDepositTest { .withMinimumOpenningBalance(minOpenningBalance).build(); return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); } + + private Account getMappedLiabilityFinancialAccount() { + final Integer liabilityTransferFinancialActivityId = FINANCIAL_ACTIVITY.LIABILITY_TRANSFER.getValue(); + List financialActivities = this.financialActivityAccountHelper.getAllFinancialActivityAccounts(this.responseSpec); + final Account financialAccount; + /*** + * if no financial activities are defined for account transfers, create + * liability financial accounting mappings + */ + if (financialActivities.isEmpty()) { + financialAccount = createLiabilityFinancialAccountTransferType(liabilityTransferFinancialActivityId); + } else { + /*** + * extract mapped liability financial account + */ + Account mappedLiabilityAccount = null; + for (HashMap financialActivity : financialActivities) { + HashMap financialActivityData = (HashMap) financialActivity.get("financialActivityData"); + if (financialActivityData.get("id").equals(liabilityTransferFinancialActivityId)) { + HashMap glAccountData = (HashMap) financialActivity.get("glAccountData"); + mappedLiabilityAccount = new Account((Integer) glAccountData.get("id"), AccountType.LIABILITY); + break; + } + } + /*** + * If liability transfer is not defined create liability transfer + */ + if (mappedLiabilityAccount == null) { + mappedLiabilityAccount = createLiabilityFinancialAccountTransferType(liabilityTransferFinancialActivityId); + } + financialAccount = mappedLiabilityAccount; + } + return financialAccount; + } + + private Account createLiabilityFinancialAccountTransferType(final Integer liabilityTransferFinancialActivityId) { + /*** + * Create and verify financial account transfer type is created + */ + final Account liabilityAccountForMapping = this.accountHelper.createLiabilityAccount(); + Integer financialActivityAccountId = (Integer) financialActivityAccountHelper.createFinancialActivityAccount( + liabilityTransferFinancialActivityId, liabilityAccountForMapping.getAccountID(), this.responseSpec, + CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(financialActivityAccountId); + assertFinancialActivityAccountCreation(financialActivityAccountId, liabilityTransferFinancialActivityId, liabilityAccountForMapping); + return liabilityAccountForMapping; + } + + private void assertFinancialActivityAccountCreation(Integer financialActivityAccountId, Integer financialActivityId, Account glAccount) { + HashMap mappingDetails = this.financialActivityAccountHelper.getFinancialActivityAccount(financialActivityAccountId, + this.responseSpec); + Assert.assertEquals(financialActivityId, ((HashMap) mappingDetails.get("financialActivityData")).get("id")); + Assert.assertEquals(glAccount.getAccountID(), ((HashMap) mappingDetails.get("glAccountData")).get("id")); + } } \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/FinancialActivityAccountHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/FinancialActivityAccountHelper.java index 4e7bed114..7290610d7 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/FinancialActivityAccountHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/FinancialActivityAccountHelper.java @@ -1,6 +1,7 @@ package org.mifosplatform.integrationtests.common.accounting; import java.util.HashMap; +import java.util.List; import org.mifosplatform.integrationtests.common.Utils; @@ -36,7 +37,7 @@ public class FinancialActivityAccountHelper { return Utils.performServerGet(requestSpec, responseSpecification, url, ""); } - public HashMap getAllFinancialActivityAccounts(final ResponseSpecification responseSpecification) { + public List getAllFinancialActivityAccounts(final ResponseSpecification responseSpecification) { final String url = FINANCIAL_ACTIVITY_ACCOUNT_MAPPING_URL + "?" + Utils.TENANT_IDENTIFIER; return Utils.performServerGet(this.requestSpec, responseSpecification, url, ""); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java index 6bed1ccf1..db0fb304e 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsAccountHelper.java @@ -104,9 +104,9 @@ public class SavingsAccountHelper { return performSavingApplicationActions(createSavingsOperationURL(ACTIVATE_SAVINGS_COMMAND, savingsID), getActivatedSavingsAsJSON()); } - public HashMap closeSavingsAccount(final Integer savingsID) { + public HashMap closeSavingsAccount(final Integer savingsID, String withdrawBalance) { System.out.println("---------------------------------- CLOSE SAVINGS APPLICATION ----------------------------------"); - return performSavingApplicationActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND, savingsID), getCloseAccountJSON()); + return performSavingApplicationActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND, savingsID), getCloseAccountJSON(withdrawBalance)); } public Object deleteSavingsApplication(final Integer savingsId, final String jsonAttributeToGetBack) { @@ -266,11 +266,12 @@ public class SavingsAccountHelper { return josn; } - private String getCloseAccountJSON() { + private String getCloseAccountJSON(String withdrawBalance) { final HashMap map = new HashMap<>(); map.put("locale", CommonConstants.locale); map.put("dateFormat", CommonConstants.dateFormat); map.put("closedOnDate", LAST_TRANSACTION_DATE); + map.put("withdrawBalance", withdrawBalance); map.put("note", "Close Test"); String josn = new Gson().toJson(map); return josn; @@ -352,6 +353,13 @@ public class SavingsAccountHelper { jsonAttributeToGetBack); } + public Object closeSavingsAccountAndGetBackRequiredField(final Integer savingsID, String withdrawBalance, + final String jsonAttributeToGetBack) { + System.out.println("---------------------------------- CLOSE SAVINGS APPLICATION ----------------------------------"); + return performSavingActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND, savingsID), getCloseAccountJSON(withdrawBalance), + jsonAttributeToGetBack); + } + private String getPeriodChargeRequestJSON(Integer chargeId) { final HashMap map = new HashMap<>(); map.put("chargeId", chargeId); diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsProductHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsProductHelper.java index 787f3d6c6..be33f20ad 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsProductHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/SavingsProductHelper.java @@ -66,6 +66,8 @@ public class SavingsProductHelper { private String minBalanceForInterestCalculation = null; private String allowOverdraft = "false"; private String overdraftLimit = null; + private String minRequiredBalance = null; + private String enforceMinRequiredBalance = "false"; public String build() { final HashMap map = new HashMap<>(); @@ -99,6 +101,8 @@ public class SavingsProductHelper { map.put("minBalanceForInterestCalculation", minBalanceForInterestCalculation); map.put("allowOverdraft", this.allowOverdraft); map.put("overdraftLimit", this.overdraftLimit); + map.put("minRequiredBalance", this.minRequiredBalance); + map.put("enforceMinRequiredBalance", this.enforceMinRequiredBalance); if (this.accountingRule.equals(CASH_BASED)) { map.putAll(getAccountMappingForCashBased()); @@ -168,6 +172,16 @@ public class SavingsProductHelper { this.accountList = account_list; return this; } + + public SavingsProductHelper withMinRequiredBalance(String minBalance) { + this.minRequiredBalance = minBalance; + return this; + } + + public SavingsProductHelper withEnforceMinRequiredBalance(String enforceMinRequiredBalance) { + this.enforceMinRequiredBalance = enforceMinRequiredBalance; + return this; + } public SavingsProductHelper withOverDraft(final String overDraftLimit) { this.allowOverdraft = "true"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java index afaf276ae..17010488f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java @@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType; import org.mifosplatform.portfolio.loanaccount.service.LoanAssembler; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; +import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; import org.mifosplatform.portfolio.savings.domain.SavingsAccount; import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler; import org.mifosplatform.portfolio.savings.domain.SavingsAccountDomainService; @@ -102,14 +103,17 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer boolean isInterestTransfer = false; boolean isAccountTransfer = true; Long fromLoanAccountId = null; + boolean isWithdrawBalance = false; + if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) { fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName); final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId); + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), - isInterestTransfer, isAccountTransfer, isRegularTransaction); + transactionDate, transactionAmount, paymentDetail, transactionBooleanValues); final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName); final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId); @@ -127,9 +131,10 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName); final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(fromSavingsAccountId); + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), - isInterestTransfer, isAccountTransfer, isRegularTransaction); + transactionDate, transactionAmount, paymentDetail, transactionBooleanValues); final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName); final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId); @@ -235,6 +240,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer public Long transferFunds(final AccountTransferDTO accountTransferDTO) { Long transferTransactionId = null; final boolean isAccountTransfer = true; + final boolean isWithdrawBalance = false; final boolean isRegularTransaction = accountTransferDTO.isRegularTransaction(); AccountTransferDetails accountTransferDetails = accountTransferDTO.getAccountTransferDetails(); if (isSavingsToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) { @@ -251,10 +257,13 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer this.loanAccountAssembler.setHelpers(toLoanAccount); } + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType.fromInt( + accountTransferDTO.getTransferType()).isInterestTransfer(), isWithdrawBalance); + final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType - .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(), isAccountTransfer, isRegularTransaction); + accountTransferDTO.getPaymentDetail(), transactionBooleanValues); LoanTransaction loanTransaction = null; @@ -297,10 +306,13 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer this.savingsAccountAssembler.setHelpers(toSavingsAccount); } + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType.fromInt( + accountTransferDTO.getTransferType()).isInterestTransfer(), isWithdrawBalance); + final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType - .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(), isAccountTransfer, isRegularTransaction); + accountTransferDTO.getPaymentDetail(), transactionBooleanValues); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java index 2128826ac..fa4a72612 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java @@ -57,7 +57,9 @@ public class StandingInstructionHistoryReadPlatformServiceImpl implements Standi sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); sqlBuilder.append(this.standingInstructionHistoryMapper.schema()); if (standingInstructionDTO.transferType() != null || standingInstructionDTO.clientId() != null - || standingInstructionDTO.clientName() != null) { + || standingInstructionDTO.clientName() != null + || (standingInstructionDTO.fromAccountType() != null && standingInstructionDTO.fromAccount() != null) + || standingInstructionDTO.startDateRange() != null || standingInstructionDTO.endDateRange() != null) { sqlBuilder.append(" where "); } boolean addAndCaluse = false; @@ -108,11 +110,16 @@ public class StandingInstructionHistoryReadPlatformServiceImpl implements Standi final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); sqlBuilder.append(" atsih.execution_time >= ? "); paramObj.add(df.format(standingInstructionDTO.startDateRange())); - if (standingInstructionDTO.endDateRange() != null) { + addAndCaluse = true; + } + + if (standingInstructionDTO.endDateRange() != null) { + if (addAndCaluse) { sqlBuilder.append(" and "); - sqlBuilder.append(" atsih.execution_time < ? "); - paramObj.add(df.format(standingInstructionDTO.endDateRange())); } + final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + sqlBuilder.append(" atsih.execution_time < ? "); + paramObj.add(df.format(standingInstructionDTO.endDateRange())); addAndCaluse = true; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index 992914f0d..025b2fa61 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -248,7 +248,7 @@ public class LoanEnumerations { break; case DISBURSEMENT: optionData = new LoanTransactionEnumData(LoanTransactionType.DISBURSEMENT.getValue().longValue(), - LoanTransactionType.DISBURSEMENT.getCode(), "Dibursement"); + LoanTransactionType.DISBURSEMENT.getCode(), "Disbursement"); break; case REPAYMENT: optionData = new LoanTransactionEnumData(LoanTransactionType.REPAYMENT.getValue().longValue(), diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java index 54395a1d3..5d77d2bc1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java @@ -98,6 +98,7 @@ public class SavingsApiConstants { public static final String minRequiredBalanceParamName = "minRequiredBalance"; public static final String enforceMinRequiredBalanceParamName = "enforceMinRequiredBalance"; public static final String minBalanceForInterestCalculationParamName = "minBalanceForInterestCalculation"; + public static final String withdrawBalanceParamName = "withdrawBalance"; // transaction parameters public static final String transactionDateParamName = "transactionDate"; @@ -206,7 +207,8 @@ public class SavingsApiConstants { dateFormatParamName, activatedOnDateParamName)); public static final Set SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, - dateFormatParamName, closedOnDateParamName, noteParamName)); + dateFormatParamName, closedOnDateParamName, noteParamName, paymentTypeIdParamName, withdrawBalanceParamName, + transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName)); public static final Set SAVINGS_ACCOUNT_CHARGES_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(chargeIdParamName, savingsAccountChargeIdParamName, chargeNameParamName, penaltyParamName, chargeTimeTypeParamName, dueAsOfDateParamName, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsTransactionBooleanValues.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsTransactionBooleanValues.java new file mode 100644 index 000000000..b4a8789f8 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsTransactionBooleanValues.java @@ -0,0 +1,41 @@ +package org.mifosplatform.portfolio.savings; + +public class SavingsTransactionBooleanValues { + + private final boolean isAccountTransfer; + private final boolean isRegularTransaction; + private final boolean isApplyWithdrawFee; + private final boolean isInterestTransfer; + private final boolean isWithdrawBalance; + + public SavingsTransactionBooleanValues(final boolean isAccountTransfer, final boolean isRegularTransaction, + final boolean isApplyWithdrawFee, final boolean isInterestTransfer, final boolean isWithdrawBalance) { + + this.isAccountTransfer = isAccountTransfer; + this.isRegularTransaction = isRegularTransaction; + this.isApplyWithdrawFee = isApplyWithdrawFee; + this.isInterestTransfer = isInterestTransfer; + this.isWithdrawBalance = isWithdrawBalance; + } + + public boolean isAccountTransfer() { + return this.isAccountTransfer; + } + + public boolean isRegularTransaction() { + return this.isRegularTransaction; + } + + public boolean isApplyWithdrawFee() { + return this.isApplyWithdrawFee; + } + + public boolean isInterestTransfer() { + return this.isInterestTransfer; + } + + public boolean isWithdrawBalance() { + return this.isWithdrawBalance; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java index 7af82cd6d..a7e69825a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java @@ -15,6 +15,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.routingCod import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionAccountNumberParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionAmountParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionDateParamName; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName; import java.lang.reflect.Type; import java.math.BigDecimal; @@ -71,17 +72,8 @@ public class SavingsAccountTransactionDataValidator { final BigDecimal transactionAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element); baseDataValidator.reset().parameter(transactionAmountParamName).value(transactionAmount).notNull().positiveAmount(); - - // Validate all string payment detail fields for max length - final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paymentTypeIdParamName, element); - baseDataValidator.reset().parameter(paymentTypeIdParamName).value(paymentTypeId).ignoreIfNull().integerGreaterThanZero(); - final Set paymentDetailParameters = new HashSet<>(Arrays.asList(transactionAccountNumberParamName, - checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName)); - for (final String paymentDetailParameterName : paymentDetailParameters) { - final String paymentDetailParameterValue = this.fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element); - baseDataValidator.reset().parameter(paymentDetailParameterName).value(paymentDetailParameterValue).ignoreIfNull() - .notExceedingLengthOf(50); - } + + validatePaymentTypeDetails(baseDataValidator, element); throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -122,12 +114,33 @@ public class SavingsAccountTransactionDataValidator { final JsonElement element = command.parsedJson(); - final LocalDate activationDate = this.fromApiJsonHelper.extractLocalDateNamed(closedOnDateParamName, element); - baseDataValidator.reset().parameter(closedOnDateParamName).value(activationDate).notNull(); + final LocalDate closedonDate = this.fromApiJsonHelper.extractLocalDateNamed(closedOnDateParamName, element); + baseDataValidator.reset().parameter(closedOnDateParamName).value(closedonDate).notNull(); + + if (this.fromApiJsonHelper.parameterExists(withdrawBalanceParamName, element)) { + final Boolean withdrawBalance = this.fromApiJsonHelper.extractBooleanNamed(withdrawBalanceParamName, element); + baseDataValidator.reset().parameter(withdrawBalanceParamName).value(withdrawBalance).isOneOfTheseValues(true, false); + } + + validatePaymentTypeDetails(baseDataValidator, element); throwExceptionIfValidationWarningsExist(dataValidationErrors); } + private void validatePaymentTypeDetails(final DataValidatorBuilder baseDataValidator, JsonElement element) { + // Validate all string payment detail fields for max length + final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paymentTypeIdParamName, element); + baseDataValidator.reset().parameter(paymentTypeIdParamName).value(paymentTypeId).ignoreIfNull().integerGreaterThanZero(); + final Set paymentDetailParameters = new HashSet<>(Arrays.asList(transactionAccountNumberParamName, checkNumberParamName, + routingCodeParamName, receiptNumberParamName, bankNumberParamName)); + for (final String paymentDetailParameterName : paymentDetailParameters) { + final String paymentDetailParameterValue = this.fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element); + baseDataValidator.reset().parameter(paymentDetailParameterName).value(paymentDetailParameterValue).ignoreIfNull() + .notExceedingLengthOf(50); + } + + } + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { if (!dataValidationErrors.isEmpty()) { // diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java index 0c358834c..31beb81bc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java @@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.savings.DepositAccountOnClosureType; import org.mifosplatform.portfolio.savings.DepositAccountType; import org.mifosplatform.portfolio.savings.DepositsApiConstants; import org.mifosplatform.portfolio.savings.SavingsApiConstants; +import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -76,8 +77,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final boolean applyWithdrawFee, final boolean isRegularTransaction) { boolean isAccountTransfer = false; boolean isInterestTransfer = false; + boolean isWithdrawBalance = false; + + SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, applyWithdrawFee, isInterestTransfer, isWithdrawBalance); return this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, transactionAmount, paymentDetail, - applyWithdrawFee, isInterestTransfer, isAccountTransfer, isRegularTransaction); + transactionBooleanValues); } @Transactional @@ -164,6 +169,10 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi savingsTransactionId = withdrawal.getId(); } + /*** + * Update account transactionIds for post journal entries. + */ + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); account.close(user, command, tenantsTodayDate, changes); this.savingsAccountRepository.save(account); @@ -230,6 +239,10 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi savingsTransactionId = withdrawal.getId(); } + /*** + * Update account transactionIds for post journal entries. + */ + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); account.close(user, command, tenantsTodayDate, changes); this.savingsAccountRepository.save(account); @@ -286,6 +299,10 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi savingsTransactionId = withdrawal.getId(); } + /*** + * Update account transactionIds for post journal entries. + */ + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); account.prematureClosure(user, command, tenantsTodayDate, changes); this.savingsAccountRepository.save(account); @@ -331,6 +348,10 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi savingsTransactionId = withdrawal.getId(); } + /*** + * Update account transactionIds for post journal entries. + */ + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); account.prematureClosure(user, command, tenantsTodayDate, changes); this.savingsAccountRepository.save(account); postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 84b5d8b37..0959b2d9a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -790,7 +790,7 @@ public class SavingsAccount extends AbstractPersistable { return transactionBeforeLastInterestPosting; } - public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount) { + public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isWithdrawBalance) { final List transactionsSortedByDate = retreiveListOfTransactions(); Money runningBalance = Money.zero(this.currency); @@ -804,7 +804,7 @@ public class SavingsAccount extends AbstractPersistable { final BigDecimal withdrawalFee = null; // deal with potential minRequiredBalance and // enforceMinRequiredBalance - if (this.minRequiredBalance != null && this.enforceMinRequiredBalance) { + if (!isWithdrawBalance && this.minRequiredBalance != null && this.enforceMinRequiredBalance) { if (runningBalance.minus(this.minRequiredBalance).isLessThanZero()) { throw new InsufficientAccountBalanceException( "transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java index dd1a15704..b08760083 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java @@ -11,12 +11,12 @@ import java.util.Set; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; +import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; public interface SavingsAccountDomainService { SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isInterestTransfer, - boolean isAccountTransfer, boolean isRegularTransaction); + BigDecimal transactionAmount, PaymentDetail paymentDetail, SavingsTransactionBooleanValues transactionBooleanValues); SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index fe0c6472d..894deae32 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -20,6 +20,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; +import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO; import org.mifosplatform.portfolio.savings.exception.DepositAccountTransactionNotAllowedException; import org.springframework.beans.factory.annotation.Autowired; @@ -49,30 +50,30 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi @Override public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean applyWithdrawFee, boolean isInterestTransfer, final boolean isAccountTransfer, final boolean isRegularTransaction) { + final SavingsTransactionBooleanValues transactionBooleanValues) { - if (isRegularTransaction && !account.allowWithdrawal()) { throw new DepositAccountTransactionNotAllowedException(account.getId(), - "withdraw", account.depositAccountType()); } + if (transactionBooleanValues.isRegularTransaction() && !account.allowWithdrawal()) { throw new DepositAccountTransactionNotAllowedException( + account.getId(), "withdraw", account.depositAccountType()); } final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, paymentDetail, new Date()); - final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, applyWithdrawFee); + final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee()); final MathContext mc = MathContext.DECIMAL64; if (account.isBeforeLastPostingPeriod(transactionDate)) { final LocalDate today = DateUtils.getLocalDateOfTenant(); - account.postInterest(mc, today, isInterestTransfer); + account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer()); } else { final LocalDate today = DateUtils.getLocalDateOfTenant(); - account.calculateInterestUsing(mc, today, isInterestTransfer); + account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer()); } - account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount); + account.validateAccountBalanceDoesNotBecomeNegative(transactionAmount, transactionBooleanValues.isWithdrawBalance()); saveTransactionToGenerateTransactionId(withdrawal); this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer()); return withdrawal; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 52c3c7f79..753bcdb1f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -9,6 +9,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_AC import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName; import java.math.BigDecimal; import java.math.MathContext; @@ -60,6 +61,7 @@ import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType; import org.mifosplatform.portfolio.savings.SavingsApiConstants; +import org.mifosplatform.portfolio.savings.SavingsTransactionBooleanValues; import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeDataValidator; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDataValidator; @@ -242,11 +244,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(account); - boolean isInterestTransfer = false; - boolean isAccountTransfer = false; - boolean isRegularTransaction = true; + + final boolean isAccountTransfer = false; + final boolean isRegularTransaction = true; + final boolean isApplyWithdrawFee = true; + final boolean isInterestTransfer = false; + final boolean isWithdrawBalance = false; + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, - transactionAmount, paymentDetail, true, isInterestTransfer, isAccountTransfer, isRegularTransaction); + transactionAmount, paymentDetail, transactionBooleanValues); return new CommandProcessingResultBuilder() // .withEntityId(withdrawal.getId()) // @@ -525,7 +532,33 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId); } - final Map changes = account.close(user, command, DateUtils.getLocalDateOfTenant()); + final boolean isWithdrawBalance = command.booleanPrimitiveValueOfParameterNamed(withdrawBalanceParamName); + + final Locale locale = command.extractLocale(); + final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); + final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); + + final Map changes = new LinkedHashMap<>(); + + if (isWithdrawBalance && account.getSummary().getAccountBalance(account.getCurrency()).isGreaterThanZero()) { + + final BigDecimal transactionAmount = account.getSummary().getAccountBalance(); + final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + + final boolean isAccountTransfer = false; + final boolean isRegularTransaction = true; + final boolean isApplyWithdrawFee = false; + final boolean isInterestTransfer = false; + final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, + isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance); + + this.savingsAccountDomainService.handleWithdrawal(account, fmt, closedDate, transactionAmount, paymentDetail, + transactionBooleanValues); + + } + + final Map accountChanges = account.close(user, command, DateUtils.getLocalDateOfTenant()); + changes.putAll(accountChanges); if (!changes.isEmpty()) { this.savingAccountRepository.save(account); final String noteText = command.stringValueOfParameterNamed("note");