FINERACT-1960: GL account mappings to use Savings product with Accrual accounting
This commit is contained in:
committed by
Adam Saghy
parent
051b37c4b3
commit
6ee881b89a
+116
-3
@@ -46,6 +46,8 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.GetRecurringDepositProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetSavingsProductsProductIdResponse;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
@@ -141,6 +143,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
this.journalEntryHelper = new JournalEntryHelper(requestSpec, responseSpec);
|
||||
this.schedulerJobHelper = new SchedulerJobHelper(requestSpec);
|
||||
this.periodicAccrualAccountingHelper = new PeriodicAccrualAccountingHelper(requestSpec, responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
this.tenantTimeZone = TimeZone.getTimeZone(Utils.TENANT_TIME_ZONE);
|
||||
}
|
||||
@@ -281,7 +284,6 @@ public class AccountingScenarioIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSavingsFlow() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
@@ -373,10 +375,107 @@ public class AccountingScenarioIntegrationTest {
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSavingsFlowUsingAccrualAccounting() {
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account liabilityAccount = this.accountHelper.createLiabilityAccount();
|
||||
|
||||
final Integer savingsProductID = createSavingsProductWithAccrualAccounting(MINIMUM_OPENING_BALANCE, assetAccount, incomeAccount,
|
||||
expenseAccount, liabilityAccount);
|
||||
final GetSavingsProductsProductIdResponse savingsProductsResponse = SavingsProductHelper.getSavingsProductById(requestSpec,
|
||||
responseSpec, savingsProductID);
|
||||
Assertions.assertNotNull(savingsProductsResponse);
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings());
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings().getSavingsControlAccount());
|
||||
Assertions.assertNotNull(savingsProductsResponse.getAccountingMappings().getInterestPayableAccount());
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, DATE_OF_JOINING);
|
||||
final Integer savingsID = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
|
||||
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(requestSpec, responseSpec, savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.approveSavings(savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||
|
||||
savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsID);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
// Checking initial Account entries.
|
||||
final JournalEntry[] assetAccountInitialEntry = { new JournalEntry(SP_BALANCE, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] liablilityAccountInitialEntry = { new JournalEntry(SP_BALANCE, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountInitialEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE, liablilityAccountInitialEntry);
|
||||
|
||||
// First Transaction-Deposit
|
||||
this.savingsAccountHelper.depositToSavingsAccount(savingsID, DEPOSIT_AMOUNT, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
Float balance = SP_BALANCE + SP_DEPOSIT_AMOUNT;
|
||||
HashMap summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance after Deposit");
|
||||
|
||||
LOG.info("----------------------Verifying Journal Entry after the Transaction Deposit----------------------------");
|
||||
final JournalEntry[] assetAccountFirstTransactionEntry = {
|
||||
new JournalEntry(SP_DEPOSIT_AMOUNT, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] liabililityAccountFirstTransactionEntry = {
|
||||
new JournalEntry(SP_DEPOSIT_AMOUNT, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountFirstTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountFirstTransactionEntry);
|
||||
|
||||
// Second Transaction-Withdrawal
|
||||
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsID, WITHDRAWAL_AMOUNT, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
balance -= SP_WITHDRAWAL_AMOUNT;
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance after Withdrawal");
|
||||
|
||||
LOG.info("-------------------Verifying Journal Entry after the Transaction Withdrawal----------------------");
|
||||
final JournalEntry[] assetAccountSecondTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT, JournalEntry.TransactionType.CREDIT) };
|
||||
final JournalEntry[] liabililityAccountSecondTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT, JournalEntry.TransactionType.DEBIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountSecondTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountSecondTransactionEntry);
|
||||
|
||||
// Third Transaction-Add Charges for Withdrawal Fee
|
||||
final Integer withdrawalChargeId = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getSavingsWithdrawalFeeJSON());
|
||||
Assertions.assertNotNull(withdrawalChargeId);
|
||||
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsID, withdrawalChargeId, false);
|
||||
ArrayList<HashMap> chargesPendingState = this.savingsAccountHelper.getSavingsCharges(savingsID);
|
||||
Assertions.assertEquals(1, chargesPendingState.size());
|
||||
HashMap savingsChargeForPay = chargesPendingState.get(0);
|
||||
HashMap paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsID, (Integer) savingsChargeForPay.get("id"));
|
||||
Float chargeAmount = (Float) paidCharge.get("amount");
|
||||
|
||||
// Withdrawal after adding Charge of type Withdrawal Fee
|
||||
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsID, WITHDRAWAL_AMOUNT_ADJUSTED, SavingsAccountHelper.TRANSACTION_DATE,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
summary = this.savingsAccountHelper.getSavingsSummary(savingsID);
|
||||
balance = balance - SP_WITHDRAWAL_AMOUNT_ADJUSTED - chargeAmount;
|
||||
|
||||
final JournalEntry[] liabililityAccountThirdTransactionEntry = { new JournalEntry(chargeAmount, JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT_ADJUSTED, JournalEntry.TransactionType.DEBIT) };
|
||||
final JournalEntry[] assetAccountThirdTransactionEntry = {
|
||||
new JournalEntry(SP_WITHDRAWAL_AMOUNT_ADJUSTED, JournalEntry.TransactionType.CREDIT) };
|
||||
final JournalEntry[] incomeAccountThirdTransactionEntry = { new JournalEntry(chargeAmount, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, TRANSACTION_DATE, assetAccountThirdTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(liabilityAccount, TRANSACTION_DATE,
|
||||
liabililityAccountThirdTransactionEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, TRANSACTION_DATE, incomeAccountThirdTransactionEntry);
|
||||
|
||||
// Verifying Balance after applying Charge for Withdrawal Fee
|
||||
assertEquals(balance, summary.get("accountBalance"), "Verifying Balance");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixedDepositAccountingFlow() {
|
||||
this.accountHelper = new AccountHelper(requestSpec, responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.US);
|
||||
@@ -481,6 +580,12 @@ public class AccountingScenarioIntegrationTest {
|
||||
Integer recurringDepositProductId = createRecurringDepositProduct(VALID_FROM, VALID_TO, assetAccount, liabilityAccount,
|
||||
incomeAccount, expenseAccount);
|
||||
Assertions.assertNotNull(recurringDepositProductId);
|
||||
final GetRecurringDepositProductsProductIdResponse recurringDepositProductsProduct = RecurringDepositProductHelper
|
||||
.getRecurringDepositProductById(requestSpec, responseSpec, recurringDepositProductId);
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct);
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct.getAccountingMappings());
|
||||
Assertions.assertNotNull(recurringDepositProductsProduct.getAccountingMappings().getSavingsControlAccount());
|
||||
Assertions.assertNull(recurringDepositProductsProduct.getAccountingMappings().getInterestPayableAccount());
|
||||
|
||||
Integer recurringDepositAccountId = applyForRecurringDepositApplication(clientId.toString(), recurringDepositProductId.toString(),
|
||||
VALID_FROM, VALID_TO, SUBMITTED_ON_DATE, RecurringDepositTest.WHOLE_TERM, EXPECTED_FIRST_DEPOSIT_ON_DATE);
|
||||
@@ -573,6 +678,15 @@ public class AccountingScenarioIntegrationTest {
|
||||
return RecurringDepositAccountHelper.applyRecurringDepositApplication(recurringDepositApplicationJSON, requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
public static Integer createSavingsProductWithAccrualAccounting(final String minOpenningBalance, final Account... accounts) {
|
||||
LOG.info("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------");
|
||||
final String savingsProductJSON = new SavingsProductHelper().withInterestCompoundingPeriodTypeAsDaily() //
|
||||
.withInterestPostingPeriodTypeAsQuarterly() //
|
||||
.withInterestCalculationPeriodTypeAsDailyBalance() //
|
||||
.withMinimumOpenningBalance(minOpenningBalance).withAccountingRuleAsAccrualBased(accounts).build();
|
||||
return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPeriodicAccrualAccountingFlow() throws InterruptedException, ParseException {
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
@@ -1124,7 +1238,6 @@ public class AccountingScenarioIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void checkAccountingWithSharingFlow() {
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
|
||||
|
||||
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||
|
||||
+11
@@ -25,6 +25,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.models.GetRecurringDepositProductsProductIdResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
import org.slf4j.Logger;
|
||||
@@ -36,6 +38,7 @@ public class RecurringDepositProductHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RecurringDepositProductHelper.class);
|
||||
private final RequestSpecification requestSpec;
|
||||
private final ResponseSpecification responseSpec;
|
||||
private static final Gson GSON = new JSON().getGson();
|
||||
|
||||
public RecurringDepositProductHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
|
||||
this.requestSpec = requestSpec;
|
||||
@@ -241,6 +244,14 @@ public class RecurringDepositProductHelper {
|
||||
return response;
|
||||
}
|
||||
|
||||
public static GetRecurringDepositProductsProductIdResponse getRecurringDepositProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer productId) {
|
||||
LOG.info("-------------------- RETRIEVING RECURRING DEPOSIT PRODUCT BY ID --------------------------");
|
||||
final String GET_RD_PRODUCT_BY_ID_URL = RECURRING_DEPOSIT_PRODUCT_URL + "/" + productId + "?" + Utils.TENANT_IDENTIFIER;
|
||||
final String response = Utils.performServerGet(requestSpec, responseSpec, GET_RD_PRODUCT_BY_ID_URL);
|
||||
return GSON.fromJson(response, GetRecurringDepositProductsProductIdResponse.class);
|
||||
}
|
||||
|
||||
public static HashMap retrieveRecurringDepositProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final String productId) {
|
||||
LOG.info("-------------------- RETRIEVING RECURRING DEPOSIT PRODUCT BY ID --------------------------");
|
||||
|
||||
+55
@@ -26,6 +26,8 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.models.GetSavingsProductsProductIdResponse;
|
||||
import org.apache.fineract.client.util.JSON;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,6 +39,7 @@ public class SavingsProductHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SavingsProductHelper.class);
|
||||
private static final String SAVINGS_PRODUCT_URL = "/fineract-provider/api/v1/savingsproducts";
|
||||
private static final String CREATE_SAVINGS_PRODUCT_URL = SAVINGS_PRODUCT_URL + "?" + Utils.TENANT_IDENTIFIER;
|
||||
private static final Gson GSON = new JSON().getGson();
|
||||
|
||||
private static final String LOCALE = "en_GB";
|
||||
private static final String DIGITS_AFTER_DECIMAL = "4";
|
||||
@@ -56,6 +59,7 @@ public class SavingsProductHelper {
|
||||
private static final String DAYS_365 = "365";
|
||||
private static final String NONE = "1";
|
||||
private static final String CASH_BASED = "2";
|
||||
private static final String ACCRUAL_PERIODIC = "3";
|
||||
|
||||
private String nameOfSavingsProduct = Utils.uniqueRandomStringGenerator("SAVINGS_PRODUCT_", 6);
|
||||
private String shortName = Utils.uniqueRandomStringGenerator("", 4);
|
||||
@@ -143,6 +147,9 @@ public class SavingsProductHelper {
|
||||
if (this.accountingRule.equals(CASH_BASED)) {
|
||||
map.putAll(getAccountMappingForCashBased());
|
||||
}
|
||||
if (this.accountingRule.equals(ACCRUAL_PERIODIC)) {
|
||||
map.putAll(getAccountMappingForAccrualBased());
|
||||
}
|
||||
if (this.isDormancyTrackingActive) {
|
||||
map.put("isDormancyTrackingActive", Boolean.toString(this.isDormancyTrackingActive));
|
||||
map.put("daysToInactive", this.daysToInactive);
|
||||
@@ -216,6 +223,12 @@ public class SavingsProductHelper {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SavingsProductHelper withAccountingRuleAsAccrualBased(final Account[] account_list) {
|
||||
this.accountingRule = ACCRUAL_PERIODIC;
|
||||
this.accountList = account_list;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SavingsProductHelper withAccountingRuleAsCashBased(final Account[] account_list) {
|
||||
this.accountingRule = CASH_BASED;
|
||||
this.accountList = account_list;
|
||||
@@ -306,6 +319,39 @@ public class SavingsProductHelper {
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String, String> getAccountMappingForAccrualBased() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
if (accountList != null) {
|
||||
for (int i = 0; i < this.accountList.length; i++) {
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.ASSET)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("savingsReferenceAccountId", ID);
|
||||
map.put("overdraftPortfolioControlId", ID);
|
||||
map.put("feesReceivableAccountId", ID);
|
||||
map.put("penaltiesReceivableAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.LIABILITY)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("savingsControlAccountId", ID);
|
||||
map.put("transfersInSuspenseAccountId", ID);
|
||||
map.put("interestPayableAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.EXPENSE)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("interestOnSavingsAccountId", ID);
|
||||
map.put("writeOffAccountId", ID);
|
||||
}
|
||||
if (this.accountList[i].getAccountType().equals(Account.AccountType.INCOME)) {
|
||||
final String ID = this.accountList[i].getAccountID().toString();
|
||||
map.put("incomeFromFeeAccountId", ID);
|
||||
map.put("incomeFromPenaltyAccountId", ID);
|
||||
map.put("incomeFromInterestId", ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Integer createSavingsProduct(final String savingsProductJSON, final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec) {
|
||||
return Utils.performServerPost(requestSpec, responseSpec, CREATE_SAVINGS_PRODUCT_URL, savingsProductJSON, "resourceId");
|
||||
@@ -326,4 +372,13 @@ public class SavingsProductHelper {
|
||||
this.daysToEscheat = "90";
|
||||
return this;
|
||||
}
|
||||
|
||||
public static GetSavingsProductsProductIdResponse getSavingsProductById(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec, final Integer productId) {
|
||||
LOG.info("-------------------- RETRIEVING SAVINGS DEPOSIT PRODUCT BY ID --------------------------");
|
||||
final String GET_PRODUCT_BY_ID_URL = SAVINGS_PRODUCT_URL + "/" + productId + "?" + Utils.TENANT_IDENTIFIER;
|
||||
final String response = Utils.performServerGet(requestSpec, responseSpec, GET_PRODUCT_BY_ID_URL);
|
||||
return GSON.fromJson(response, GetSavingsProductsProductIdResponse.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user