FINERACT-1960: GL account mappings to use Savings product with Accrual accounting
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/common/AccountingValidations.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/common/AccountingValidations.java
new file mode 100644
index 0000000..aac47c5
--- /dev/null
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/common/AccountingValidations.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.accounting.common;
+
+public final class AccountingValidations {
+
+    private AccountingValidations() {}
+
+    public static boolean isCashBasedAccounting(final Integer accountingRuleType) {
+        return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
+    }
+
+    public static boolean isAccrualPeriodicBasedAccounting(final Integer accountingRuleType) {
+        return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType);
+    }
+
+    public static boolean isUpfrontAccrualAccounting(final Integer accountingRuleType) {
+        return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
+    }
+
+    public static boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
+        return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType)
+                || AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
+    }
+
+    public static boolean isCashOrAccrualBasedAccounting(final Integer accountingRuleType) {
+        return isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType);
+    }
+
+}
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java
index 13e175d..511ce5e 100644
--- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java
@@ -31,7 +31,7 @@
 import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
 import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
 import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAccountingParams;
-import org.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.accounting.common.AccountingValidations;
 import org.apache.fineract.accounting.glaccount.domain.GLAccount;
 import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -83,7 +83,8 @@
         final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
         baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4);
 
-        if (isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
 
             final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.FUND_SOURCE.getValue(), element);
             baseDataValidator.reset().parameter(LoanProductAccountingParams.FUND_SOURCE.getValue()).value(fundAccountId).notNull()
@@ -131,7 +132,7 @@
 
         }
 
-        if (isAccrualBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
 
             final Long receivableInterestAccountId = this.fromApiJsonHelper
                     .extractLongNamed(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), element);
@@ -168,7 +169,7 @@
                 Locale.getDefault());
         baseDataValidator.reset().parameter(accountingRuleParamName).value(accountingRuleType).notNull().inMinMaxRange(1, 3);
 
-        if (isCashBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)) {
 
             final Long savingsControlAccountId = this.fromApiJsonHelper
                     .extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
@@ -227,6 +228,23 @@
 
         }
 
+        // Periodic Accrual Accounting aditional GL Accounts
+        if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
+            final Long feeReceivableAccountId = this.fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.FEES_RECEIVABLE.getValue()).value(feeReceivableAccountId)
+                    .notNull().integerGreaterThanZero();
+            final Long penaltyReceivableAccountId = this.fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue())
+                    .value(penaltyReceivableAccountId).notNull().integerGreaterThanZero();
+
+            final Long interestPayableAccountId = this.fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_PAYABLE.getValue()).value(interestPayableAccountId)
+                    .notNull().integerGreaterThanZero();
+        }
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
@@ -246,7 +264,7 @@
                 Locale.getDefault());
         baseDataValidator.reset().parameter(accountingRuleParamName).value(accountingRuleType).notNull().inMinMaxRange(1, 3);
 
-        if (isCashBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)) {
 
             final Long shareReferenceId = this.fromApiJsonHelper.extractLongNamed(SharesProductAccountingParams.SHARES_REFERENCE.getValue(),
                     element);
@@ -273,15 +291,6 @@
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
-    private boolean isCashBasedAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
-    }
-
-    private boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType)
-                || AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
-    }
-
     private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
         if (!dataValidationErrors.isEmpty()) {
             throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java
index fa9bb08..b9edf47 100644
--- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java
@@ -25,7 +25,9 @@
 import java.util.List;
 import java.util.Map;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
+import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
@@ -33,6 +35,7 @@
 import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingDataParams;
 import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAccountingParams;
 import org.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.accounting.common.AccountingValidations;
 import org.apache.fineract.accounting.glaccount.data.GLAccountData;
 import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
 import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
@@ -44,6 +47,7 @@
 import org.springframework.jdbc.core.RowMapper;
 import org.springframework.stereotype.Service;
 
+@Slf4j
 @Service
 @RequiredArgsConstructor
 public class ProductToGLAccountMappingReadPlatformServiceImpl implements ProductToGLAccountMappingReadPlatformService {
@@ -106,7 +110,7 @@
         final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, // NOSONAR
                 new Object[] { PortfolioProductType.LOAN.getValue(), loanProductId });
 
-        if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
+        if (AccountingValidations.isCashBasedAccounting(accountingType)) {
 
             for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
 
@@ -159,8 +163,8 @@
                 }
 
             }
-        } else if (AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingType)
-                || AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingType)) {
+        } else if (AccountingValidations.isAccrualBasedAccounting(accountingType)
+                || AccountingValidations.isUpfrontAccrualAccounting(accountingType)) {
 
             for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
                 final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
@@ -225,49 +229,21 @@
 
     @Override
     public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(final Long savingsProductId, final Integer accountingType) {
-        final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
-
         final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
         final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null and mapping.charge_id is null ";
 
         final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, // NOSONAR
                 new Object[] { PortfolioProductType.SAVING.getValue(), savingsProductId });
 
-        if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
+        Map<String, Object> accountMappingDetails = null;
+        if (AccountingValidations.isCashBasedAccounting(accountingType)) {
+            accountMappingDetails = setCashSavingsProductToGLAccountMaps(listOfProductToGLAccountMaps);
 
-            for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
+        } else if (AccountingValidations.isAccrualPeriodicBasedAccounting(accountingType)) {
+            accountMappingDetails = setAccrualPeriodicSavingsProductToGLAccountMaps(listOfProductToGLAccountMaps);
 
-                final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
-                final CashAccountsForSavings glAccountForSavings = CashAccountsForSavings.fromInt(financialAccountType);
-
-                final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
-                final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
-                final String glCode = (String) productToGLAccountMap.get("glCode");
-                final GLAccountData gLAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
-
-                if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_REFERENCE)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_CONTROL)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_FEES)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_PENALTIES)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.TRANSFERS_SUSPENSE)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.INTEREST_ON_SAVINGS)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.LOSSES_WRITTEN_OFF)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_INTEREST)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), gLAccountData);
-                } else if (glAccountForSavings.equals(CashAccountsForSavings.ESCHEAT_LIABILITY)) {
-                    accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), gLAccountData);
-                }
-            }
         }
+
         return accountMappingDetails;
     }
 
@@ -412,4 +388,105 @@
         return fetchChargeToIncomeAccountMappings(PortfolioProductType.SHARES, productId, false);
     }
 
+    private Map<String, Object> setAccrualPeriodicSavingsProductToGLAccountMaps(
+            final List<Map<String, Object>> listOfProductToGLAccountMaps) {
+        final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
+
+        for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
+
+            final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
+            AccrualAccountsForSavings glAccountForSavings = AccrualAccountsForSavings.fromInt(financialAccountType);
+
+            if (glAccountForSavings != null) {
+                final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
+                final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
+                final String glCode = (String) productToGLAccountMap.get("glCode");
+                final GLAccountData glAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
+
+                // Assets
+                if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_REFERENCE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.FEES_RECEIVABLE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.FEES_RECEIVABLE.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.PENALTIES_RECEIVABLE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.PENALTIES_RECEIVABLE.getValue(), glAccountData);
+                    // Liabilities
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_CONTROL)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.TRANSFERS_SUSPENSE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_PAYABLE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_PAYABLE.getValue(), glAccountData);
+                    // Income
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_FEES)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_PENALTIES)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.INCOME_FROM_INTEREST)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.ESCHEAT_LIABILITY)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), glAccountData);
+                    // Expense
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_ON_SAVINGS)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(AccrualAccountsForSavings.LOSSES_WRITTEN_OFF)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), glAccountData);
+                }
+            } else {
+                log.error("Accounting mapping null {}", financialAccountType);
+            }
+        }
+
+        return accountMappingDetails;
+    }
+
+    private Map<String, Object> setCashSavingsProductToGLAccountMaps(final List<Map<String, Object>> listOfProductToGLAccountMaps) {
+        final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
+
+        for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
+
+            final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
+            CashAccountsForSavings glAccountForSavings = CashAccountsForSavings.fromInt(financialAccountType);
+
+            if (glAccountForSavings != null) {
+                final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
+                final String glAccountName = (String) productToGLAccountMap.get("glAccountName");
+                final String glCode = (String) productToGLAccountMap.get("glCode");
+                final GLAccountData glAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
+
+                // Assets
+                if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_REFERENCE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
+                    // Liabilities
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.SAVINGS_CONTROL)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_CONTROL.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.TRANSFERS_SUSPENSE)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.TRANSFERS_SUSPENSE.getValue(), glAccountData);
+                    // Income
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_FEES)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_FEES.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_PENALTIES)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_PENALTIES.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.INCOME_FROM_INTEREST)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INCOME_FROM_INTEREST.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.ESCHEAT_LIABILITY)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.ESCHEAT_LIABILITY.getValue(), glAccountData);
+                    // Expense
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.INTEREST_ON_SAVINGS)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_ON_SAVINGS.getValue(), glAccountData);
+                } else if (glAccountForSavings.equals(CashAccountsForSavings.LOSSES_WRITTEN_OFF)) {
+                    accountMappingDetails.put(SavingProductAccountingDataParams.LOSSES_WRITTEN_OFF.getValue(), glAccountData);
+                }
+            } else {
+                log.error("Accounting mapping null {}", financialAccountType);
+            }
+        }
+
+        return accountMappingDetails;
+    }
+
 }
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java
index 6cccdfe..4b3e75b 100644
--- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java
@@ -21,6 +21,7 @@
 import com.google.gson.JsonElement;
 import java.util.HashMap;
 import java.util.Map;
+import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
 import org.apache.fineract.accounting.common.AccountingRuleType;
@@ -167,6 +168,25 @@
                 changes.put(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
             break;
             case ACCRUAL_PERIODIC:
+                final Long feeReceivableId = this.fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), element);
+                final Long penaltyReceivableId = this.fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
+                final Long interestPayableId = this.fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
+
+                changes.put(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingsControlId);
+                changes.put(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
+                changes.put(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
+                changes.put(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
+                changes.put(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltiesId);
+                changes.put(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
+                changes.put(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), overdraftControlId);
+                changes.put(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), incomeFromInterest);
+                changes.put(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
+                changes.put(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), feeReceivableId);
+                changes.put(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), penaltyReceivableId);
+                changes.put(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), interestPayableId);
             break;
             case ACCRUAL_UPFRONT:
             break;
@@ -229,6 +249,61 @@
                         savingsProductId, CashAccountsForSavings.ESCHEAT_LIABILITY.getValue(), changes);
             break;
             case ACCRUAL_PERIODIC:
+                // asset
+                mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
+                        AccrualAccountsForSavings.SAVINGS_REFERENCE.toString(), changes);
+
+                mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
+                        AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.toString(), changes);
+
+                mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.FEES_RECEIVABLE.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.FEES_RECEIVABLE.getValue(),
+                        AccrualAccountsForSavings.FEES_RECEIVABLE.toString(), changes);
+
+                mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue(),
+                        AccrualAccountsForSavings.PENALTIES_RECEIVABLE.toString(), changes);
+
+                // income
+                mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.INCOME_FROM_FEES.getValue(),
+                        AccrualAccountsForSavings.INCOME_FROM_FEES.toString(), changes);
+
+                mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.INCOME_FROM_PENALTIES.getValue(),
+                        AccrualAccountsForSavings.INCOME_FROM_PENALTIES.toString(), changes);
+
+                mergeSavingsToIncomeAccountMappingChanges(element, SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
+                        AccrualAccountsForSavings.INCOME_FROM_INTEREST.toString(), changes);
+
+                // expenses
+                mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
+                        AccrualAccountsForSavings.INTEREST_ON_SAVINGS.toString(), changes);
+
+                mergeSavingsToExpenseAccountMappingChanges(element, SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
+                        AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.toString(), changes);
+
+                // liability
+                mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.SAVINGS_CONTROL.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                        AccrualAccountsForSavings.SAVINGS_CONTROL.toString(), changes);
+
+                mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
+                        AccrualAccountsForSavings.TRANSFERS_SUSPENSE.toString(), changes);
+
+                mergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_PAYABLE.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(),
+                        AccrualAccountsForSavings.INTEREST_PAYABLE.toString(), changes);
+
+                createOrmergeSavingsToLiabilityAccountMappingChanges(element, SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(),
+                        savingsProductId, AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(), changes);
+
             break;
             case ACCRUAL_UPFRONT:
             break;
diff --git a/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java b/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
index 257dc1f..669ad59 100644
--- a/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
+++ b/fineract-core/src/main/java/org/apache/fineract/accounting/common/AccountingConstants.java
@@ -278,6 +278,54 @@
     }
 
     /***
+     * Accounting placeholders for periodic accrual based accounting for savings products
+     ***/
+    public enum AccrualAccountsForSavings {
+
+        SAVINGS_REFERENCE(1), //
+        SAVINGS_CONTROL(2), //
+        INTEREST_ON_SAVINGS(3), //
+        INCOME_FROM_FEES(4), //
+        INCOME_FROM_PENALTIES(5), //
+        TRANSFERS_SUSPENSE(10), //
+        OVERDRAFT_PORTFOLIO_CONTROL(11), //
+        INCOME_FROM_INTEREST(12), //
+        LOSSES_WRITTEN_OFF(13), //
+        ESCHEAT_LIABILITY(14), //
+        FEES_RECEIVABLE(15), //
+        PENALTIES_RECEIVABLE(16), //
+        INTEREST_PAYABLE(17);
+
+        private final Integer value;
+
+        AccrualAccountsForSavings(final Integer value) {
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return name().toString().replaceAll("_", " ");
+        }
+
+        public Integer getValue() {
+            return this.value;
+        }
+
+        private static final Map<Integer, AccrualAccountsForSavings> intToEnumMap = new HashMap<>();
+
+        static {
+            for (final AccrualAccountsForSavings type : AccrualAccountsForSavings.values()) {
+                intToEnumMap.put(type.value, type);
+            }
+        }
+
+        public static AccrualAccountsForSavings fromInt(final int i) {
+            final AccrualAccountsForSavings type = intToEnumMap.get(Integer.valueOf(i));
+            return type;
+        }
+    }
+
+    /***
      * Enum of all accounting related input parameter names used while creating/updating a savings product
      ***/
     public enum SavingProductAccountingParams {
@@ -298,7 +346,10 @@
         OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControlId"), //
         INCOME_FROM_INTEREST("incomeFromInterestId"), //
         LOSSES_WRITTEN_OFF("writeOffAccountId"), //
-        ESCHEAT_LIABILITY("escheatLiabilityId"); //
+        ESCHEAT_LIABILITY("escheatLiabilityId"), //
+        PENALTIES_RECEIVABLE("penaltiesReceivableAccountId"), //
+        FEES_RECEIVABLE("feesReceivableAccountId"), //
+        INTEREST_PAYABLE("interestPayableAccountId");
 
         private final String value;
 
@@ -332,7 +383,10 @@
         OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControl"), //
         INCOME_FROM_INTEREST("incomeFromInterest"), //
         LOSSES_WRITTEN_OFF("writeOffAccount"), //
-        ESCHEAT_LIABILITY("escheatLiabilityAccount"); //
+        ESCHEAT_LIABILITY("escheatLiabilityAccount"), //
+        FEES_RECEIVABLE("feeReceivableAccount"), //
+        PENALTIES_RECEIVABLE("penaltyReceivableAccount"), //
+        INTEREST_PAYABLE("interestPayableAccount"); //
 
         private final String value;
 
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
index 517003b..1665603 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositsApiConstants.java
@@ -218,8 +218,10 @@
             SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
             SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
             SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
-            SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), chartsParamName,
-            SavingsApiConstants.withHoldTaxParamName, SavingsApiConstants.taxGroupIdParamName));
+            SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
+            SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
+            SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), chartsParamName, SavingsApiConstants.withHoldTaxParamName,
+            SavingsApiConstants.taxGroupIdParamName));
 
     private static final Set<String> PRECLOSURE_REQUEST_DATA_PARAMETERS = new HashSet<>(
             Arrays.asList(preClosurePenalApplicableParamName, preClosurePenalInterestParamName, preClosurePenalInterestOnTypeIdParamName));
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
index 639806c..af1034a 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
@@ -40,6 +40,7 @@
     WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharge"), //
     PAY_CHARGE(7, "savingsAccountTransactionType.payCharge", TransactionEntryType.DEBIT), //
     DIVIDEND_PAYOUT(8, "savingsAccountTransactionType.dividendPayout", TransactionEntryType.CREDIT), //
+    ACCRUAL(10, "savingsAccountTransactionType.accrual"), //
     INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
     APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
     WITHDRAW_TRANSFER(14, "savingsAccountTransactionType.withdrawTransfer"), //
@@ -181,6 +182,10 @@
         return this == AMOUNT_RELEASE;
     }
 
+    public boolean isAccrual() {
+        return this == ACCRUAL;
+    }
+
     public boolean isCredit() {
         // AMOUNT_RELEASE is not credit, because the account balance is not changed
         return isCreditEntryType() && !isAmountRelease();
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
index 60401d5..6d69469 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
@@ -49,6 +49,7 @@
     private final boolean escheat;
     private final boolean amountHold;
     private final boolean amountRelease;
+    private final boolean accrual;
 
     public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
         this.id = id;
@@ -57,6 +58,7 @@
         SavingsAccountTransactionType transactionType = id == null ? null : SavingsAccountTransactionType.fromInt(id.intValue());
         this.deposit = transactionType == SavingsAccountTransactionType.DEPOSIT;
         this.dividendPayout = transactionType == SavingsAccountTransactionType.DIVIDEND_PAYOUT;
+        this.accrual = transactionType == SavingsAccountTransactionType.ACCRUAL;
         this.withdrawal = transactionType == SavingsAccountTransactionType.WITHDRAWAL;
         this.interestPosting = transactionType == SavingsAccountTransactionType.INTEREST_POSTING;
         this.feeDeduction = transactionType == SavingsAccountTransactionType.ANNUAL_FEE
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
index 9d14a87..21c5943 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsEnumerations.java
@@ -141,6 +141,10 @@
                 optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WITHDRAWAL.getValue().longValue(),
                         SavingsAccountTransactionType.WITHDRAWAL.getCode(), "Withdrawal");
             break;
+            case ACCRUAL:
+                optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.ACCRUAL.getValue().longValue(),
+                        SavingsAccountTransactionType.ACCRUAL.getCode(), "Accrual");
+            break;
             case INTEREST_POSTING:
                 optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INTEREST_POSTING.getValue().longValue(),
                         SavingsAccountTransactionType.INTEREST_POSTING.getCode(), "Interest posting");
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorForSavingsFactory.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorForSavingsFactory.java
index e5c9fb4..5bccce4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorForSavingsFactory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorForSavingsFactory.java
@@ -40,6 +40,9 @@
         if (savingsDTO.isCashBasedAccountingEnabled()) {
             accountingProcessorForSavings = this.applicationContext.getBean("cashBasedAccountingProcessorForSavings",
                     AccountingProcessorForSavings.class);
+        } else if (savingsDTO.isAccrualBasedAccountingEnabled()) {
+            accountingProcessorForSavings = this.applicationContext.getBean("accrualBasedAccountingProcessorForSavings",
+                    AccountingProcessorForSavings.class);
         }
 
         return accountingProcessorForSavings;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
index 6c637e9..804184c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccountingProcessorHelper.java
@@ -30,6 +30,7 @@
 import org.apache.fineract.accounting.closure.domain.GLClosure;
 import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
 import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
+import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
@@ -573,6 +574,28 @@
                 paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
     }
 
+    public void createAccrualBasedJournalEntriesAndReversalsForSavingsTax(final Office office, final String currencyCode,
+            final AccrualAccountsForSavings accountTypeToBeDebited, final AccrualAccountsForSavings accountTypeToBeCredited,
+            final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
+            final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal, final List<TaxPaymentDTO> taxDetails) {
+
+        for (TaxPaymentDTO taxPaymentDTO : taxDetails) {
+            if (taxPaymentDTO.getAmount() != null) {
+                if (taxPaymentDTO.getCreditAccountId() == null) {
+                    createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode, accountTypeToBeCredited.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, taxPaymentDTO.getAmount(),
+                            isReversal);
+                } else {
+                    createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            taxPaymentDTO.getCreditAccountId(), savingsId, transactionId, transactionDate, taxPaymentDTO.getAmount(),
+                            isReversal);
+                }
+            }
+        }
+        createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode, accountTypeToBeDebited.getValue(),
+                savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+    }
+
     public void createCashBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
             final Integer accountTypeToBeDebited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
             final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
@@ -623,6 +646,56 @@
         }
     }
 
+    public void createAccrualBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
+            final Integer accountTypeToBeDebited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
+            final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
+        // reverse debits and credits for reversals
+        if (isReversal) {
+            createCreditJournalEntriesForSavings(office, currencyCode, accountTypeToBeDebited, savingsProductId, paymentTypeId, savingsId,
+                    transactionId, transactionDate, amount);
+        } else {
+            createDebitJournalEntriesForSavings(office, currencyCode, accountTypeToBeDebited, savingsProductId, paymentTypeId, savingsId,
+                    transactionId, transactionDate, amount);
+        }
+    }
+
+    public void createAccrualBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
+            final Integer accountTypeToBeCredited, final Long savingsProductId, final Long paymentTypeId, final Long savingsId,
+            final String transactionId, final LocalDate transactionDate, final BigDecimal amount, final Boolean isReversal) {
+        // reverse debits and credits for reversals
+        if (isReversal) {
+            createDebitJournalEntriesForSavings(office, currencyCode, accountTypeToBeCredited, savingsProductId, paymentTypeId, savingsId,
+                    transactionId, transactionDate, amount);
+        } else {
+            createCreditJournalEntriesForSavings(office, currencyCode, accountTypeToBeCredited, savingsProductId, paymentTypeId, savingsId,
+                    transactionId, transactionDate, amount);
+        }
+    }
+
+    public void createAccrualBasedDebitJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
+            final Long debitAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
+            final BigDecimal amount, final Boolean isReversal) {
+        // reverse debits and credits for reversals
+        final GLAccount debitAccount = getGLAccountById(debitAccountId);
+        if (isReversal) {
+            createCreditJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
+        } else {
+            createDebitJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount);
+        }
+    }
+
+    public void createAccrualBasedBasedCreditJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode,
+            final Long creditAccountId, final Long savingsId, final String transactionId, final LocalDate transactionDate,
+            final BigDecimal amount, final Boolean isReversal) {
+        // reverse debits and credits for reversals
+        final GLAccount creditAccount = getGLAccountById(creditAccountId);
+        if (isReversal) {
+            createDebitJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
+        } else {
+            createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
+        }
+    }
+
     private void createDebitJournalEntriesForSavings(final Office office, final String currencyCode, final int accountTypeToDebitId,
             final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
             final LocalDate transactionDate, final BigDecimal amount) {
@@ -768,6 +841,41 @@
         }
     }
 
+    public void createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
+            final AccrualAccountsForSavings accountTypeToBeDebited, AccrualAccountsForSavings accountTypeToBeCredited,
+            final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
+            final LocalDate transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
+            final List<ChargePaymentDTO> chargePaymentDTOs) {
+        // TODO Vishwas: Remove this validation, as and when appropriate Junit
+        // tests are written for accounting
+        /**
+         * Accounting module currently supports a single charge per transaction, throw an error if this is not the case
+         * here so any developers changing the expected portfolio behavior would also take care of modifying the
+         * accounting code appropriately
+         **/
+        if (chargePaymentDTOs.size() != 1) {
+            throw new PlatformDataIntegrityException("Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code",
+                    "Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code");
+        }
+        ChargePaymentDTO chargePaymentDTO = chargePaymentDTOs.get(0);
+        GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(),
+                chargePaymentDTO.getChargeId());
+
+        final GLAccount savingsControlAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToBeDebited.getValue(),
+                paymentTypeId);
+        if (isReversal) {
+            createDebitJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
+                    totalAmount);
+            createCreditJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
+                    totalAmount);
+        } else {
+            createDebitJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
+                    totalAmount);
+            createCreditJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
+                    totalAmount);
+        }
+    }
+
     public LoanTransaction getLoanTransactionById(final Long loanTransactionId) {
         return this.loanTransactionRepository.getReferenceById(loanTransactionId);
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForSavings.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForSavings.java
new file mode 100644
index 0000000..4aa1b93
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/AccrualBasedAccountingProcessorForSavings.java
@@ -0,0 +1,272 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.accounting.journalentry.service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.accounting.closure.domain.GLClosure;
+import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
+import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
+import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
+import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
+import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
+import org.apache.fineract.organisation.office.domain.Office;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class AccrualBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
+
+    private final AccountingProcessorHelper helper;
+
+    @Override
+    public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
+        final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
+        final Long savingsProductId = savingsDTO.getSavingsProductId();
+        final Long savingsId = savingsDTO.getSavingsId();
+        final String currencyCode = savingsDTO.getCurrencyCode();
+        for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
+            final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
+            final String transactionId = savingsTransactionDTO.getTransactionId();
+            final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
+            final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
+            final boolean isReversal = savingsTransactionDTO.isReversed();
+            final BigDecimal amount = savingsTransactionDTO.getAmount();
+            final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
+            final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
+            final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
+
+            this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
+
+            if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
+                boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
+                if (savingsTransactionDTO.isAccountTransfer()) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
+                            FinancialActivity.LIABILITY_TRANSFER.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
+                            transactionDate, overdraftAmount, isReversal);
+                    if (isPositive) {
+                        this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                                AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
+                                savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
+                                amount.subtract(overdraftAmount), isReversal);
+                    }
+                } else {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
+                            AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
+                            transactionId, transactionDate, overdraftAmount, isReversal);
+                    if (isPositive) {
+                        this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                                AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                                AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
+                                transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
+                    }
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
+                boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
+                if (savingsTransactionDTO.isAccountTransfer()) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            FinancialActivity.LIABILITY_TRANSFER.getValue(),
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                            transactionId, transactionDate, overdraftAmount, isReversal);
+                    if (isPositive) {
+                        this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                                FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                                savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
+                                amount.subtract(overdraftAmount), isReversal);
+                    }
+                } else {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                            transactionId, transactionDate, overdraftAmount, isReversal);
+                    if (isPositive) {
+                        this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                                AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
+                                AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                                transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
+                    }
+                }
+            }
+
+            /** Handle Deposits and reversals of deposits **/
+            else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
+                if (savingsTransactionDTO.isAccountTransfer()) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                } else {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                }
+            }
+
+            /** Handle Deposits and reversals of Dividend pay outs **/
+            else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        FinancialActivity.PAYABLE_DIVIDENDS.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                        savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+            }
+
+            /** Handle withdrawals and reversals of withdrawals **/
+            else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
+                if (savingsTransactionDTO.isAccountTransfer()) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                } else {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
+                        savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+            }
+            /**
+             * Handle Interest Applications and reversals of Interest Applications
+             **/
+            else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
+                boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
+                // Post journal entry if earned interest amount is greater than
+                // zero
+                if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                            transactionId, transactionDate, overdraftAmount, isReversal);
+                    if (isPositive) {
+                        this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                                AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
+                                AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                                transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
+                    }
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
+                // Post journal entry if earned interest amount is greater than
+                // zero
+                if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isAccrual()) {
+                // Post journal entry for Accrual Recognition
+                if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
+                    this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                            AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(),
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
+                this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
+                        AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.SAVINGS_REFERENCE, savingsProductId,
+                        paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal,
+                        savingsTransactionDTO.getTaxPayments());
+            }
+
+            /** Handle Fees Deductions and reversals of Fees Deductions **/
+            else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
+                boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
+                // Is the Charge a penalty?
+                if (penaltyPayments.size() > 0) {
+                    this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
+                            penaltyPayments);
+                    if (isPositive) {
+                        this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                                AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
+                                savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
+                                amount.subtract(overdraftAmount), isReversal, penaltyPayments);
+                    }
+                } else {
+                    this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                            AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES,
+                            savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
+                            feePayments);
+                    if (isPositive) {
+                        this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                                AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
+                                paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
+                                feePayments);
+                    }
+                }
+            }
+
+            else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
+                // Is the Charge a penalty?
+                if (penaltyPayments.size() > 0) {
+                    this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
+                            paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
+                } else {
+                    this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                            AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
+                            paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
+                }
+            }
+
+            /** Handle Transfers proposal **/
+            else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
+                        savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+            }
+
+            /** Handle Transfer Withdrawal or Acceptance **/
+            else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
+                    || savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
+                        savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+            }
+
+            /** overdraft **/
+            else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
+                        savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
+            } else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
+                this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
+                        AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
+                        AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
+                        transactionId, transactionDate, amount, isReversal);
+            } else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
+                this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
+                        AccrualAccountsForSavings.SAVINGS_REFERENCE, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
+                        paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
+            }
+        }
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java
index 751bc65..5349600 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/productaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java
@@ -27,6 +27,7 @@
 import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForLoan;
+import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
 import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
@@ -211,6 +212,65 @@
         }
     }
 
+    private void saveSavingsBaseAccountMapping(final Long savingProductId, final DepositAccountType accountType, final JsonCommand command,
+            final JsonElement element) {
+        // asset
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
+                SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingProductId,
+                CashAccountsForSavings.SAVINGS_REFERENCE.getValue());
+
+        if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
+            this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
+                    SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingProductId,
+                    CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue());
+        }
+
+        // income
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
+                SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), savingProductId,
+                CashAccountsForSavings.INCOME_FROM_FEES.getValue());
+
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
+                SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), savingProductId,
+                CashAccountsForSavings.INCOME_FROM_PENALTIES.getValue());
+
+        if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
+            this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
+                    SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), savingProductId,
+                    CashAccountsForSavings.INCOME_FROM_INTEREST.getValue());
+        }
+
+        // expenses
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
+                SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), savingProductId,
+                CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue());
+
+        if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
+            this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
+                    SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), savingProductId,
+                    CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue());
+        }
+
+        // liability
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
+                SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingProductId,
+                CashAccountsForSavings.SAVINGS_CONTROL.getValue());
+        this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
+                SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), savingProductId,
+                CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue());
+
+        final Boolean isDormancyTrackingActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
+        if (null != isDormancyTrackingActive && isDormancyTrackingActive) {
+            this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
+                    SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), savingProductId,
+                    CashAccountsForSavings.ESCHEAT_LIABILITY.getValue());
+        }
+
+        // advanced accounting mappings
+        this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
+        this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null);
+    }
+
     @Override
     @Transactional
     public void createSavingProductToGLAccountMapping(final Long savingProductId, final JsonCommand command,
@@ -219,67 +279,28 @@
         final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed(accountingRuleParamName, element,
                 Locale.getDefault());
         final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
-
         switch (accountingRuleType) {
             case NONE:
             break;
             case CASH_BASED:
-                // asset
+                saveSavingsBaseAccountMapping(savingProductId, accountType, command, element);
+            break;
+
+            case ACCRUAL_PERIODIC:
+                saveSavingsBaseAccountMapping(savingProductId, accountType, command, element);
+                // assets
                 this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
-                        SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), savingProductId,
-                        CashAccountsForSavings.SAVINGS_REFERENCE.getValue());
+                        SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), savingProductId,
+                        AccrualAccountsForSavings.FEES_RECEIVABLE.getValue());
 
-                if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
-                    this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
-                            SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingProductId,
-                            CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue());
-                }
-
-                // income
-                this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
-                        SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), savingProductId,
-                        CashAccountsForSavings.INCOME_FROM_FEES.getValue());
-
-                this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
-                        SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), savingProductId,
-                        CashAccountsForSavings.INCOME_FROM_PENALTIES.getValue());
-
-                if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
-                    this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
-                            SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), savingProductId,
-                            CashAccountsForSavings.INCOME_FROM_INTEREST.getValue());
-                }
-
-                // expenses
-                this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
-                        SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), savingProductId,
-                        CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue());
-
-                if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
-                    this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
-                            SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), savingProductId,
-                            CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue());
-                }
+                this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
+                        SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), savingProductId,
+                        AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue());
 
                 // liability
                 this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
-                        SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), savingProductId,
-                        CashAccountsForSavings.SAVINGS_CONTROL.getValue());
-                this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
-                        SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), savingProductId,
-                        CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue());
-
-                final Boolean isDormancyTrackingActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName,
-                        element);
-                if (null != isDormancyTrackingActive && isDormancyTrackingActive) {
-                    this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
-                            SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), savingProductId,
-                            CashAccountsForSavings.ESCHEAT_LIABILITY.getValue());
-                }
-
-                // advanced accounting mappings
-                this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
-                this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null);
+                        SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), savingProductId,
+                        AccrualAccountsForSavings.INTEREST_PAYABLE.getValue());
             break;
             default:
             break;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index b99e1bd..946d1e5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -359,6 +359,8 @@
         CalendarInstance compoundingCalendarInstance = null;
         InterestRecalculationCompoundingMethod compoundingMethod = null;
         boolean allowCompoundingOnEod = false;
+        final Boolean isFloatingInterestRate = this.fromApiJsonHelper
+                .extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
         if (isInterestRecalculationEnabled) {
             LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
                     .getProductInterestRecalculationDetails();
@@ -409,8 +411,7 @@
         if (loanProduct.isLinkedToFloatingInterestRate()) {
             final BigDecimal interestRateDiff = this.fromApiJsonHelper
                     .extractBigDecimalWithLocaleNamed(LoanApiConstants.interestRateDifferentialParameterName, element);
-            final Boolean isFloatingInterestRate = this.fromApiJsonHelper
-                    .extractBooleanNamed(LoanApiConstants.isFloatingInterestRateParameterName, element);
+
             List<FloatingRatePeriodData> baseLendingRatePeriods = null;
             try {
                 baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate().getRatePeriods();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index 6a6abe9..c5ee18f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -33,10 +33,9 @@
 import java.util.Map;
 import java.util.Set;
 import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
-import org.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.accounting.common.AccountingValidations;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
@@ -65,7 +64,6 @@
 import org.apache.fineract.portfolio.loanproduct.exception.EqualAmortizationUnsupportedFeatureException;
 import org.springframework.stereotype.Component;
 
-@Slf4j
 @RequiredArgsConstructor
 @Component
 public final class LoanProductDataValidator {
@@ -613,7 +611,8 @@
         final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed(ACCOUNTING_RULE, element, Locale.getDefault());
         baseDataValidator.reset().parameter(ACCOUNTING_RULE).value(accountingRuleType).notNull().inMinMaxRange(1, 4);
 
-        if (isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
 
             final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.FUND_SOURCE.getValue(), element);
             baseDataValidator.reset().parameter(LoanProductAccountingParams.FUND_SOURCE.getValue()).value(fundAccountId).notNull()
@@ -709,7 +708,7 @@
 
         }
 
-        if (isAccrualBasedAccounting(accountingRuleType)) {
+        if (AccountingValidations.isAccrualBasedAccounting(accountingRuleType)) {
 
             final Long receivableInterestAccountId = this.fromApiJsonHelper
                     .extractLongNamed(LoanProductAccountingParams.INTEREST_RECEIVABLE.getValue(), element);
@@ -2144,22 +2143,6 @@
         }
     }
 
-    private boolean isCashBasedAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
-    }
-
-    private boolean isAccrualBasedAccounting(final Integer accountingRuleType) {
-        return isUpfrontAccrualAccounting(accountingRuleType) || isPeriodicAccounting(accountingRuleType);
-    }
-
-    private boolean isUpfrontAccrualAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType);
-    }
-
-    private boolean isPeriodicAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType);
-    }
-
     private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
         if (!dataValidationErrors.isEmpty()) {
             throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResourceSwagger.java
index 96de367..75981cf 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositProductsApiResourceSwagger.java
@@ -318,88 +318,31 @@
             public String description;
         }
 
+        static final class GetFixedDepositProductsGlAccount {
+
+            private GetFixedDepositProductsGlAccount() {}
+
+            @Schema(example = "12")
+            public Long id;
+            @Schema(example = "savings ref")
+            public String name;
+            @Schema(example = "20")
+            public Integer glCode;
+        }
+
         static final class GetFixedDepositProductsProductIdAccountingMappings {
 
             private GetFixedDepositProductsProductIdAccountingMappings() {}
 
-            static final class GetFixedDepositProductsProductIdSavingsReferenceAccount {
-
-                private GetFixedDepositProductsProductIdSavingsReferenceAccount() {}
-
-                @Schema(example = "12")
-                public Long id;
-                @Schema(example = "savings ref")
-                public String name;
-                @Schema(example = "20")
-                public String glCode;
-            }
-
-            static final class GetFixedDepositProductsProductIdIncomeFromFeeAccount {
-
-                private GetFixedDepositProductsProductIdIncomeFromFeeAccount() {}
-
-                @Schema(example = "16")
-                public Long id;
-                @Schema(example = "income from savings fee")
-                public String name;
-                @Schema(example = "24")
-                public String glCode;
-            }
-
-            static final class GetFixedDepositProductsProductIdIncomeFromPenaltyAccount {
-
-                private GetFixedDepositProductsProductIdIncomeFromPenaltyAccount() {}
-
-                @Schema(example = "17")
-                public Long id;
-                @Schema(example = "income from sav penalties")
-                public String name;
-                @Schema(example = "25")
-                public String glCode;
-            }
-
-            static final class GetFixedDepositProductsProductIdInterestOnSavingsAccount {
-
-                private GetFixedDepositProductsProductIdInterestOnSavingsAccount() {}
-
-                @Schema(example = "15")
-                public Long id;
-                @Schema(example = "interest on savings")
-                public String name;
-                @Schema(example = "23")
-                public String glCode;
-            }
-
-            static final class GetFixedDepositProductsProductIdSavingsControlAccount {
-
-                private GetFixedDepositProductsProductIdSavingsControlAccount() {}
-
-                @Schema(example = "13")
-                public Long id;
-                @Schema(example = "savings ref tool kit")
-                public String name;
-                @Schema(example = "21")
-                public String glCode;
-            }
-
-            static final class GetFixedDepositProductsProductIdTransfersInSuspenseAccount {
-
-                private GetFixedDepositProductsProductIdTransfersInSuspenseAccount() {}
-
-                @Schema(example = "14")
-                public Long id;
-                @Schema(example = "saving transfers")
-                public String name;
-                @Schema(example = "22")
-                public String glCode;
-            }
-
-            public GetFixedDepositProductsProductIdSavingsReferenceAccount savingsReferenceAccount;
-            public GetFixedDepositProductsProductIdIncomeFromFeeAccount incomeFromFeeAccount;
-            public GetFixedDepositProductsProductIdIncomeFromPenaltyAccount incomeFromPenaltyAccount;
-            public GetFixedDepositProductsProductIdInterestOnSavingsAccount interestOnSavingsAccount;
-            public GetFixedDepositProductsProductIdSavingsControlAccount savingsControlAccount;
-            public GetFixedDepositProductsProductIdTransfersInSuspenseAccount transfersInSuspenseAccount;
+            public GetFixedDepositProductsGlAccount savingsReferenceAccount;
+            public GetFixedDepositProductsGlAccount feeReceivableAccount;
+            public GetFixedDepositProductsGlAccount penaltyReceivableAccount;
+            public GetFixedDepositProductsGlAccount incomeFromFeeAccount;
+            public GetFixedDepositProductsGlAccount incomeFromPenaltyAccount;
+            public GetFixedDepositProductsGlAccount interestOnSavingsAccount;
+            public GetFixedDepositProductsGlAccount savingsControlAccount;
+            public GetFixedDepositProductsGlAccount transfersInSuspenseAccount;
+            public GetFixedDepositProductsGlAccount interestPayableAccount;
         }
 
         static final class GetFixedDepositProductsProductIdFeeToIncomeAccountMappings {
@@ -455,7 +398,7 @@
             }
 
             public GetFixedDepositProductsProductIdPenaltyToIncomeAccountMappingsCharge charge;
-            public GetFixedDepositProductsProductIdAccountingMappings.GetFixedDepositProductsProductIdIncomeFromPenaltyAccount incomeAccount;
+            public GetFixedDepositProductsGlAccount incomeAccount;
         }
 
         static final class GetFixedDepositProductsProductIdPreClosurePenalInterestOnType {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResourceSwagger.java
index e07b32c..57f5dd0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositProductsApiResourceSwagger.java
@@ -343,88 +343,30 @@
             public String description;
         }
 
+        static final class GetRecurringDepositProductsGlAccount {
+
+            private GetRecurringDepositProductsGlAccount() {}
+
+            @Schema(example = "12")
+            public Long id;
+            @Schema(example = "savings control")
+            public String name;
+            @Schema(example = "2000001")
+            public String glCode;
+        }
+
         static final class GetRecurringDepositProductsProductIdAccountingMappings {
 
             private GetRecurringDepositProductsProductIdAccountingMappings() {}
 
-            static final class GetRecurringDepositProductsProductIdSavingsReferenceAccount {
-
-                private GetRecurringDepositProductsProductIdSavingsReferenceAccount() {}
-
-                @Schema(example = "12")
-                public Long id;
-                @Schema(example = "savings ref")
-                public String name;
-                @Schema(example = "20")
-                public String glCode;
-            }
-
-            static final class GetRecurringDepositProductsProductIdIncomeFromFeeAccount {
-
-                private GetRecurringDepositProductsProductIdIncomeFromFeeAccount() {}
-
-                @Schema(example = "16")
-                public Long id;
-                @Schema(example = "income from savings fee")
-                public String name;
-                @Schema(example = "24")
-                public String glCode;
-            }
-
-            static final class GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount {
-
-                private GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount() {}
-
-                @Schema(example = "17")
-                public Long id;
-                @Schema(example = "income from sav penalties")
-                public String name;
-                @Schema(example = "25")
-                public String glCode;
-            }
-
-            static final class GetRecurringDepositProductsProductIdInterestOnSavingsAccount {
-
-                private GetRecurringDepositProductsProductIdInterestOnSavingsAccount() {}
-
-                @Schema(example = "15")
-                public Long id;
-                @Schema(example = "interest on savings")
-                public String name;
-                @Schema(example = "23")
-                public String glCode;
-            }
-
-            static final class GetRecurringDepositProductsProductIdSavingsControlAccount {
-
-                private GetRecurringDepositProductsProductIdSavingsControlAccount() {}
-
-                @Schema(example = "13")
-                public Long id;
-                @Schema(example = "savings ref tool kit")
-                public String name;
-                @Schema(example = "21")
-                public String glCode;
-            }
-
-            static final class GetRecurringDepositProductsProductIdTransfersInSuspenseAccount {
-
-                private GetRecurringDepositProductsProductIdTransfersInSuspenseAccount() {}
-
-                @Schema(example = "14")
-                public Long id;
-                @Schema(example = "saving transfers")
-                public String name;
-                @Schema(example = "22")
-                public String glCode;
-            }
-
-            public GetRecurringDepositProductsProductIdSavingsReferenceAccount savingsReferenceAccount;
-            public GetRecurringDepositProductsProductIdIncomeFromFeeAccount incomeFromFeeAccount;
-            public GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount incomeFromPenaltyAccount;
-            public GetRecurringDepositProductsProductIdInterestOnSavingsAccount interestOnSavingsAccount;
-            public GetRecurringDepositProductsProductIdSavingsControlAccount savingsControlAccount;
-            public GetRecurringDepositProductsProductIdTransfersInSuspenseAccount transfersInSuspenseAccount;
+            public GetRecurringDepositProductsGlAccount incomeFromFeeAccount;
+            public GetRecurringDepositProductsGlAccount incomeFromPenaltyAccount;
+            public GetRecurringDepositProductsGlAccount interestOnSavingsAccount;
+            public GetRecurringDepositProductsGlAccount savingsControlAccount;
+            public GetRecurringDepositProductsGlAccount transfersInSuspenseAccount;
+            public GetRecurringDepositProductsGlAccount feeReceivableAccount;
+            public GetRecurringDepositProductsGlAccount penaltyReceivableAccount;
+            public GetRecurringDepositProductsGlAccount interestPayableAccount;
         }
 
         static final class GetRecurringDepositProductsProductIdFeeToIncomeAccountMappings {
@@ -480,7 +422,7 @@
             }
 
             public GetRecurringDepositProductsProductIdPenaltyToIncomeAccountMappingsCharge charge;
-            public GetRecurringDepositProductsProductIdAccountingMappings.GetRecurringDepositProductsProductIdIncomeFromPenaltyAccount incomeAccount;
+            public GetRecurringDepositProductsGlAccount incomeAccount;
         }
 
         static final class GetRecurringDepositProductsProductIdPreClosurePenalInterestOnType {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResourceSwagger.java
index b44afc2..f2fe2ef 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResourceSwagger.java
@@ -226,88 +226,34 @@
 
         private GetSavingsProductsProductIdResponse() {}
 
+        static final class GetSavingsProductsGlAccount {
+
+            private GetSavingsProductsGlAccount() {}
+
+            @Schema(example = "12")
+            public Integer id;
+            @Schema(example = "savings control")
+            public String name;
+            @Schema(example = "2000001")
+            public String glCode;
+        }
+
         static final class GetSavingsProductsAccountingMappings {
 
             private GetSavingsProductsAccountingMappings() {}
 
-            static final class GetSavingsProductsSavingsReferenceAccount {
-
-                private GetSavingsProductsSavingsReferenceAccount() {}
-
-                @Schema(example = "12")
-                public Integer id;
-                @Schema(example = "savings ref")
-                public String name;
-                @Schema(example = "20")
-                public String glCode;
-            }
-
-            static final class GetSavingsProductsIncomeFromFeeAccount {
-
-                private GetSavingsProductsIncomeFromFeeAccount() {}
-
-                @Schema(example = "16")
-                public Integer id;
-                @Schema(example = "income from savings fee")
-                public String name;
-                @Schema(example = "24")
-                public String glCode;
-            }
-
-            static final class GetSavingsProductsIncomeFromPenaltyAccount {
-
-                private GetSavingsProductsIncomeFromPenaltyAccount() {}
-
-                @Schema(example = "17")
-                public Integer id;
-                @Schema(example = "income from sav penalties")
-                public String name;
-                @Schema(example = "25")
-                public String glCode;
-            }
-
-            static final class GetSavingsProductsInterestOnSavingsAccount {
-
-                private GetSavingsProductsInterestOnSavingsAccount() {}
-
-                @Schema(example = "15")
-                public Integer id;
-                @Schema(example = "interest on savings")
-                public String name;
-                @Schema(example = "23")
-                public String glCode;
-            }
-
-            static final class GetSavingsProductsSavingsControlAccount {
-
-                private GetSavingsProductsSavingsControlAccount() {}
-
-                @Schema(example = "13")
-                public Integer id;
-                @Schema(example = "savings ref tool kit")
-                public String name;
-                @Schema(example = "21")
-                public String glCode;
-            }
-
-            static final class GetSavingsProductsTransfersInSuspenseAccount {
-
-                private GetSavingsProductsTransfersInSuspenseAccount() {}
-
-                @Schema(example = "14")
-                public Integer id;
-                @Schema(example = "saving transfers")
-                public String name;
-                @Schema(example = "22")
-                public String glCode;
-            }
-
-            public GetSavingsProductsSavingsReferenceAccount savingsReferenceAccount;
-            public GetSavingsProductsIncomeFromFeeAccount incomeFromFeeAccount;
-            public GetSavingsProductsIncomeFromPenaltyAccount incomeFromPenaltyAccount;
-            public GetSavingsProductsInterestOnSavingsAccount interestOnSavingsAccount;
-            public GetSavingsProductsSavingsControlAccount savingsControlAccount;
-            public GetSavingsProductsTransfersInSuspenseAccount transfersInSuspenseAccount;
+            public GetSavingsProductsGlAccount savingsReferenceAccount;
+            public GetSavingsProductsGlAccount overdraftPortfolioControl;
+            public GetSavingsProductsGlAccount feeReceivableAccount;
+            public GetSavingsProductsGlAccount penaltyReceivableAccount;
+            public GetSavingsProductsGlAccount incomeFromFeeAccount;
+            public GetSavingsProductsGlAccount incomeFromPenaltyAccount;
+            public GetSavingsProductsGlAccount incomeFromInterest;
+            public GetSavingsProductsGlAccount interestOnSavingsAccount;
+            public GetSavingsProductsGlAccount writeOffAccount;
+            public GetSavingsProductsGlAccount savingsControlAccount;
+            public GetSavingsProductsGlAccount transfersInSuspenseAccount;
+            public GetSavingsProductsGlAccount interestPayableAccount;
         }
 
         static final class GetSavingsProductsPaymentChannelToFundSourceMappings {
@@ -393,7 +339,7 @@
             }
 
             public GetSavingsProductsPenaltyToIncomeAccountMappingsCharge charge;
-            public GetSavingsProductsAccountingMappings.GetSavingsProductsIncomeFromPenaltyAccount incomeAccount;
+            public GetSavingsProductsGlAccount incomeAccount;
         }
 
         @Schema(example = "1")
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositProductDataValidator.java
index 96380a8..a30f97b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositProductDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositProductDataValidator.java
@@ -71,35 +71,33 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
-import org.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.accounting.common.AccountingValidations;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartDataValidator;
+import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.PreClosurePenalInterestOnType;
+import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
 import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
 import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
 import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
 import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
+@RequiredArgsConstructor
 public class DepositProductDataValidator {
 
     private final FromJsonHelper fromApiJsonHelper;
     private final InterestRateChartDataValidator chartDataValidator;
-
-    @Autowired
-    public DepositProductDataValidator(FromJsonHelper fromApiJsonHelper, InterestRateChartDataValidator chartDataValidator) {
-        this.fromApiJsonHelper = fromApiJsonHelper;
-        this.chartDataValidator = chartDataValidator;
-    }
+    private final SavingsProductAccountingDataValidator savingsProductAccountingDataValidator;
 
     public void validateForFixedDepositCreate(final String json) {
         if (StringUtils.isBlank(json)) {
@@ -115,7 +113,7 @@
 
         final JsonElement element = this.fromApiJsonHelper.parse(json);
 
-        validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator);
+        validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator, DepositAccountType.FIXED_DEPOSIT);
 
         validatePreClosureDetailForCreate(element, baseDataValidator);
 
@@ -168,7 +166,7 @@
 
         final JsonElement element = this.fromApiJsonHelper.parse(json);
 
-        validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator);
+        validateDepositDetailForCreate(element, this.fromApiJsonHelper, baseDataValidator, DepositAccountType.RECURRING_DEPOSIT);
 
         validatePreClosureDetailForCreate(element, baseDataValidator);
 
@@ -212,7 +210,7 @@
     }
 
     private void validateDepositDetailForCreate(final JsonElement element, final FromJsonHelper fromApiJsonHelper,
-            final DataValidatorBuilder baseDataValidator) {
+            final DataValidatorBuilder baseDataValidator, final DepositAccountType accountType) {
         final String name = fromApiJsonHelper.extractStringNamed(nameParamName, element);
         baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
 
@@ -258,13 +256,6 @@
         baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType).notNull()
                 .isOneOfTheseValues(SavingsInterestCalculationDaysInYearType.integerValues());
 
-        /*
-         * if (fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName , element)) { final BigDecimal
-         * minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed (minRequiredOpeningBalanceParamName,
-         * element); baseDataValidator.reset ().parameter(minRequiredOpeningBalanceParamName
-         * ).value(minOpeningBalance).zeroOrPositiveAmount(); }
-         */
-
         if (fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
 
             final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
@@ -302,40 +293,16 @@
         final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
         baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
 
-        if (isCashBasedAccounting(accountingRuleType)) {
+        Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(SavingsApiConstants.isDormancyTrackingActiveParamName,
+                element);
+        if (isDormancyActive == null) {
+            isDormancyActive = false;
+        }
 
-            final Long savingsControlAccountId = fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
-                    .notNull().integerGreaterThanZero();
-
-            final Long savingsReferenceAccountId = fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
-                    .notNull().integerGreaterThanZero();
-
-            final Long transfersInSuspenseAccountId = fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
-                    .value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
-
-            final Long interestOnSavingsAccountId = fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
-                    .value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
-
-            final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
-                    element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
-                    .integerGreaterThanZero();
-
-            final Long incomeFromPenaltyId = fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
-                    .notNull().integerGreaterThanZero();
-
-            validatePaymentChannelFundSourceMappings(fromApiJsonHelper, baseDataValidator, element);
-            validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element);
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
+            savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
+                    baseDataValidator, accountType);
         }
 
         validateTaxWithHoldingParams(baseDataValidator, element, true);
@@ -542,8 +509,8 @@
         baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
                 .ignoreIfNull().integerGreaterThanZero();
 
-        validatePaymentChannelFundSourceMappings(fromApiJsonHelper, baseDataValidator, element);
-        validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element);
+        savingsProductAccountingDataValidator.validatePaymentChannelFundSourceMappings(baseDataValidator, element);
+        savingsProductAccountingDataValidator.validateChargeToIncomeAccountMappings(baseDataValidator, element);
         validateTaxWithHoldingParams(baseDataValidator, element, false);
     }
 
@@ -611,76 +578,6 @@
         }
     }
 
-    private boolean isCashBasedAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
-    }
-
-    /**
-     * Validation for advanced accounting options
-     */
-    private void validatePaymentChannelFundSourceMappings(final FromJsonHelper fromApiJsonHelper,
-            final DataValidatorBuilder baseDataValidator, final JsonElement element) {
-        if (fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
-            final JsonArray paymentChannelMappingArray = fromApiJsonHelper
-                    .extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
-            if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
-                int i = 0;
-                do {
-                    final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
-                    final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
-                    final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
-                            .getAsLong();
-                    baseDataValidator.reset()
-                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
-                                    + SavingProductAccountingParams.PAYMENT_TYPE.toString())
-                            .value(paymentTypeId).notNull().integerGreaterThanZero();
-                    baseDataValidator.reset()
-                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
-                                    + SavingProductAccountingParams.FUND_SOURCE.getValue())
-                            .value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
-                    i++;
-                } while (i < paymentChannelMappingArray.size());
-            }
-        }
-    }
-
-    private void validateChargeToIncomeAccountMappings(final FromJsonHelper fromApiJsonHelper, final DataValidatorBuilder baseDataValidator,
-            final JsonElement element) {
-        // validate for both fee and penalty charges
-        validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element, true);
-        validateChargeToIncomeAccountMappings(fromApiJsonHelper, baseDataValidator, element, true);
-    }
-
-    private void validateChargeToIncomeAccountMappings(final FromJsonHelper fromApiJsonHelper, final DataValidatorBuilder baseDataValidator,
-            final JsonElement element, final boolean isPenalty) {
-        String parameterName;
-        if (isPenalty) {
-            parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
-        } else {
-            parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
-        }
-
-        if (fromApiJsonHelper.parameterExists(parameterName, element)) {
-            final JsonArray chargeToIncomeAccountMappingArray = fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
-            if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
-                int i = 0;
-                do {
-                    final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
-                    final Long chargeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
-                            jsonObject);
-                    final Long incomeAccountId = fromApiJsonHelper
-                            .extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
-                    baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
-                            .value(chargeId).notNull().integerGreaterThanZero();
-                    baseDataValidator.reset()
-                            .parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
-                            .value(incomeAccountId).notNull().integerGreaterThanZero();
-                    i++;
-                } while (i < chargeToIncomeAccountMappingArray.size());
-            }
-        }
-    }
-
     public void validateRecurringDetailForCreate(JsonElement element, DataValidatorBuilder baseDataValidator) {
 
         final Boolean isMandatoryDeposit = this.fromApiJsonHelper.extractBooleanNamed(isMandatoryDepositParamName, element);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
index fd95092..a53e5ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
@@ -43,6 +43,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -55,15 +56,14 @@
 import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountSubStatusEnum;
 import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
 import org.apache.fineract.portfolio.savings.exception.TransactionBeforePivotDateNotAllowed;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
+@RequiredArgsConstructor
 public class SavingsAccountTransactionDataValidator {
 
     private final FromJsonHelper fromApiJsonHelper;
@@ -71,15 +71,6 @@
             Arrays.asList(transactionDateParamName, SavingsApiConstants.dateFormatParamName, SavingsApiConstants.localeParamName,
                     transactionAmountParamName, lienAllowedParamName, SavingsApiConstants.reasonForBlockParamName));
     private final ConfigurationDomainService configurationDomainService;
-    private final SavingsAccountAssembler savingAccountAssembler;
-
-    @Autowired
-    public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper,
-            final ConfigurationDomainService configurationDomainService, final SavingsAccountAssembler savingAccountAssembler) {
-        this.fromApiJsonHelper = fromApiJsonHelper;
-        this.configurationDomainService = configurationDomainService;
-        this.savingAccountAssembler = savingAccountAssembler;
-    }
 
     public void validateTransactionWithPivotDate(final LocalDate transactionDate, final SavingsAccount savingsAccount) {
         final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
index 3389a01..822a08c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java
@@ -99,7 +99,6 @@
 import org.springframework.util.CollectionUtils;
 
 @RequiredArgsConstructor
-
 public class DepositAccountReadPlatformServiceImpl implements DepositAccountReadPlatformService {
 
     private static final FixedDepositAccountMapper FIXED_DEPOSIT_ACCOUNT_MAPPER = new FixedDepositAccountMapper();
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index d094213..4a983e3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -611,7 +611,6 @@
                     final BigDecimal outstandingChargeAmount = null;
                     final BigDecimal runningBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "runningBalance");
                     final boolean reversed = rs.getBoolean("reversed");
-                    final boolean isManualTransaction = rs.getBoolean("manualTransaction");
                     final Long officeId = rs.getLong("officeId");
                     final BigDecimal cumulativeBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "cumulativeBalance");
 
@@ -684,59 +683,6 @@
             }
             return savingsAccountDataList;
 
-            // final String productName = rs.getString("productName");
-
-            // final String fieldOfficerName = rs.getString("fieldOfficerName");
-
-            // final String submittedByUsername = rs.getString("submittedByUsername");
-            // final String submittedByFirstname = rs.getString("submittedByFirstname");
-            // final String submittedByLastname = rs.getString("submittedByLastname");
-            //
-
-            // final String rejectedByUsername = rs.getString("rejectedByUsername");
-            // final String rejectedByFirstname = rs.getString("rejectedByFirstname");
-            // final String rejectedByLastname = rs.getString("rejectedByLastname");
-            //
-
-            // final String withdrawnByUsername = rs.getString("withdrawnByUsername");
-            // final String withdrawnByFirstname = rs.getString("withdrawnByFirstname");
-            // final String withdrawnByLastname = rs.getString("withdrawnByLastname");
-
-            // final String approvedByUsername = rs.getString("approvedByUsername");
-            // final String approvedByFirstname = rs.getString("approvedByFirstname");
-            // final String approvedByLastname = rs.getString("approvedByLastname");
-
-            // final String activatedByUsername = rs.getString("activatedByUsername");
-            // final String activatedByFirstname = rs.getString("activatedByFirstname");
-            // final String activatedByLastname = rs.getString("activatedByLastname");
-
-            // final String closedByUsername = rs.getString("closedByUsername");
-            // final String closedByFirstname = rs.getString("closedByFirstname");
-            // final String closedByLastname = rs.getString("closedByLastname");
-
-            // final String currencyName = rs.getString("currencyName");
-            // final String currencyNameCode = rs.getString("currencyNameCode");
-            // final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
-
-            /*
-             * final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
-             *
-             * EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue =
-             * JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) {
-             * withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); }
-             */
-
-            /*
-             * final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
-             *
-             * MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs,
-             * "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if
-             * (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new
-             * MonthDay(annualFeeOnMonth, annualFeeOnDay); }
-             *
-             * final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
-             */
-
         }
     }
 
@@ -792,20 +738,12 @@
             sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, ");
             sqlBuilder.append("sa.lockin_period_frequency as lockinPeriodFrequency,");
             sqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
-            // sqlBuilder.append("sa.withdrawal_fee_amount as
-            // withdrawalFeeAmount,");
-            // sqlBuilder.append("sa.withdrawal_fee_type_enum as
-            // withdrawalFeeTypeEnum, ");
+
             sqlBuilder.append("sa.allow_overdraft as allowOverdraft, ");
             sqlBuilder.append("sa.overdraft_limit as overdraftLimit, ");
             sqlBuilder.append("sa.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
             sqlBuilder.append("sa.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
-            // sqlBuilder.append("sa.annual_fee_amount as annualFeeAmount,");
-            // sqlBuilder.append("sa.annual_fee_on_month as annualFeeOnMonth,
-            // ");
-            // sqlBuilder.append("sa.annual_fee_on_day as annualFeeOnDay, ");
-            // sqlBuilder.append("sa.annual_fee_next_due_date as
-            // annualFeeNextDueDate, ");
+
             sqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
             sqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
             sqlBuilder.append("sa.total_withdrawal_fees_derived as totalWithdrawalFees, ");
@@ -981,14 +919,6 @@
                 lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
             }
 
-            /*
-             * final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
-             *
-             * EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue =
-             * JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) {
-             * withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); }
-             */
-
             final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
 
             final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
@@ -1004,16 +934,6 @@
             final BigDecimal maxAllowedLienLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxAllowedLienLimit");
             final boolean lienAllowed = rs.getBoolean("lienAllowed");
 
-            /*
-             * final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
-             *
-             * MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs,
-             * "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if
-             * (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new
-             * MonthDay(annualFeeOnMonth, annualFeeOnDay); }
-             *
-             * final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
-             */
             final BigDecimal totalDeposits = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalDeposits");
             final BigDecimal totalWithdrawals = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawals");
             final BigDecimal totalWithdrawalFees = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawalFees");
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java
index aa201de..f4fb623 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java
@@ -59,11 +59,7 @@
                 SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY),
                 SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY),
                 SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL),
-                SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL)
-        // //
-        // SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST)
-        // //
-        );
+                SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL));
 
         return allowedOptions;
     }
diff --git a/fineract-savings/dependencies.gradle b/fineract-savings/dependencies.gradle
index bd2a158..467fc30 100644
--- a/fineract-savings/dependencies.gradle
+++ b/fineract-savings/dependencies.gradle
@@ -25,6 +25,7 @@
     // implementation dependencies are directly used (compiled against) in src/main (and src/test)
     //
     implementation(project(path: ':fineract-core'))
+    implementation(project(path: ':fineract-accounting'))
 
     implementation(
             'org.springframework.boot:spring-boot-starter-web',
diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductAccountingDataValidator.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductAccountingDataValidator.java
new file mode 100644
index 0000000..1e527e7
--- /dev/null
+++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductAccountingDataValidator.java
@@ -0,0 +1,185 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.savings.data;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
+import org.apache.fineract.accounting.common.AccountingValidations;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.savings.DepositAccountType;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class SavingsProductAccountingDataValidator {
+
+    private final FromJsonHelper fromApiJsonHelper;
+
+    public void evaluateProductAccountingData(final Integer accountingRuleType, final boolean isDormancyActive, final JsonElement element,
+            DataValidatorBuilder baseDataValidator, final DepositAccountType accountType) {
+        // GL Accounts for Cash or Accrual Periodic
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
+
+            final Long savingsControlAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
+                    .notNull().integerGreaterThanZero();
+
+            final Long savingsReferenceAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
+                    .notNull().integerGreaterThanZero();
+
+            final Long transfersInSuspenseAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
+                    .value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
+
+            final Long interestOnSavingsAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
+                    .value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
+
+            final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
+                    element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
+                    .integerGreaterThanZero();
+
+            final Long incomeFromPenaltyId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
+                    .notNull().integerGreaterThanZero();
+
+            if (!accountType.equals(DepositAccountType.RECURRING_DEPOSIT) && !accountType.equals(DepositAccountType.FIXED_DEPOSIT)) {
+                final Long overdraftControlAccountId = fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
+                baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
+                        .value(overdraftControlAccountId).notNull().integerGreaterThanZero();
+
+                final Long incomeFromInterest = fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
+                baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
+                        .notNull().integerGreaterThanZero();
+
+                final Long writtenoff = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
+                        element);
+                baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).notNull()
+                        .integerGreaterThanZero();
+            }
+
+            if (isDormancyActive) {
+                final Long escheatLiabilityAccountId = fromApiJsonHelper
+                        .extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
+                baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
+                        .value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
+            }
+        }
+
+        // GL Accounts for Accrual Period only
+        if (AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
+            final Long feeReceivableAccountId = fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.FEES_RECEIVABLE.getValue(),
+                    element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.FEES_RECEIVABLE.getValue()).value(feeReceivableAccountId)
+                    .notNull().integerGreaterThanZero();
+
+            final Long penaltyReceivableAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue())
+                    .value(penaltyReceivableAccountId).notNull().integerGreaterThanZero();
+
+            final Long interestPayableAccountId = fromApiJsonHelper
+                    .extractLongNamed(SavingProductAccountingParams.INTEREST_PAYABLE.getValue(), element);
+            baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_PAYABLE.getValue()).value(interestPayableAccountId)
+                    .notNull().integerGreaterThanZero();
+        }
+
+        validatePaymentChannelFundSourceMappings(baseDataValidator, element);
+        validateChargeToIncomeAccountMappings(baseDataValidator, element);
+    }
+
+    /**
+     * Validation for advanced accounting options
+     */
+    public void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
+        if (fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
+            final JsonArray paymentChannelMappingArray = fromApiJsonHelper
+                    .extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
+            if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
+                int i = 0;
+                do {
+                    final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
+                    final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
+                    final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
+                            .getAsLong();
+                    baseDataValidator.reset()
+                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
+                                    + SavingProductAccountingParams.PAYMENT_TYPE.toString())
+                            .value(paymentTypeId).notNull().integerGreaterThanZero();
+                    baseDataValidator.reset()
+                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
+                                    + SavingProductAccountingParams.FUND_SOURCE.getValue())
+                            .value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
+                    i++;
+                } while (i < paymentChannelMappingArray.size());
+            }
+        }
+    }
+
+    public void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
+        // validate for both fee and penalty charges
+        validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
+        validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
+    }
+
+    private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
+            final boolean isPenalty) {
+        String parameterName;
+        if (isPenalty) {
+            parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
+        } else {
+            parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
+            final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
+            if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
+                int i = 0;
+                do {
+                    final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
+                    final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
+                            jsonObject);
+                    final Long incomeAccountId = this.fromApiJsonHelper
+                            .extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
+                    baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
+                            .value(chargeId).notNull().integerGreaterThanZero();
+                    baseDataValidator.reset()
+                            .parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
+                            .value(incomeAccountId).notNull().integerGreaterThanZero();
+                    i++;
+                } while (i < chargeToIncomeAccountMappingArray.size());
+            }
+        }
+    }
+
+}
diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java
index 368c1a8..bac9114 100644
--- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java
+++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java
@@ -50,9 +50,7 @@
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
 
-import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
 import com.google.gson.reflect.TypeToken;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
@@ -64,28 +62,31 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingParams;
-import org.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.accounting.common.AccountingValidations;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
 import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
 import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
 import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
 import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 @Component
+@RequiredArgsConstructor
 public class SavingsProductDataValidator {
 
     private final FromJsonHelper fromApiJsonHelper;
+    private final SavingsProductAccountingDataValidator savingsProductAccountingDataValidator;
     private static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
             SavingsApiConstants.localeParamName, SavingsApiConstants.monthDayFormatParamName, nameParamName, shortNameParamName,
             descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, inMultiplesOfParamName,
@@ -95,11 +96,12 @@
             SavingsApiConstants.withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName,
             SavingsApiConstants.accountingRuleParamName, SavingsApiConstants.chargesParamName,
             SavingProductAccountingParams.INCOME_FROM_FEES.getValue(), SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(),
-            SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(),
+            SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
             SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
             SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(),
             SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
             SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
+            SavingProductAccountingParams.FEES_RECEIVABLE.getValue(), SavingProductAccountingParams.INTEREST_PAYABLE.getValue(),
             SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
             SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(), SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(),
             SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), isDormancyTrackingActiveParamName, daysToDormancyParamName,
@@ -109,11 +111,6 @@
             SavingsApiConstants.maxAllowedLienLimitParamName, SavingsApiConstants.lienAllowedParamName,
             minBalanceForInterestCalculationParamName, withHoldTaxParamName, taxGroupIdParamName));
 
-    @Autowired
-    public SavingsProductDataValidator(final FromJsonHelper fromApiJsonHelper) {
-        this.fromApiJsonHelper = fromApiJsonHelper;
-    }
-
     public void validateForCreate(final String json) {
 
         if (StringUtils.isBlank(json)) {
@@ -207,28 +204,6 @@
             }
         }
 
-        /*
-         * if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
-         *
-         * final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed
-         * (withdrawalFeeAmountParamName, element); baseDataValidator.reset().parameter
-         * (withdrawalFeeAmountParamName).value (withdrawalFeeAmount).zeroOrPositiveAmount();
-         *
-         * if (withdrawalFeeAmount != null) { final Integer withdrawalFeeType =
-         * this.fromApiJsonHelper.extractIntegerSansLocaleNamed( withdrawalFeeTypeParamName, element);
-         * baseDataValidator.reset().parameter (withdrawalFeeTypeParamName).value(withdrawalFeeType)
-         * .isOneOfTheseValues(SavingsWithdrawalFeesType.integerValues()); } }
-         *
-         * if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) { final Integer
-         * withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed (withdrawalFeeTypeParamName,
-         * element); baseDataValidator.reset().parameter
-         * (withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull() .isOneOfTheseValues(1, 2);
-         *
-         * if (withdrawalFeeType != null) { final BigDecimal withdrawalFeeAmount =
-         * this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( withdrawalFeeAmountParamName, element);
-         * baseDataValidator.reset().parameter (withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
-         * .zeroOrPositiveAmount(); } }
-         */
         if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
             final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper
                     .extractBooleanNamed(withdrawalFeeForTransfersParamName, element);
@@ -256,9 +231,12 @@
         }
 
         // dormancy
-        final Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
+        Boolean isDormancyActive = this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element);
+        if (isDormancyActive == null) {
+            isDormancyActive = false;
+        }
 
-        if (null != isDormancyActive && isDormancyActive) {
+        if (isDormancyActive) {
             final Long daysToInact = this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element);
             baseDataValidator.reset().parameter(daysToInactiveParamName).value(daysToInact).notNull().longGreaterThanZero();
 
@@ -278,62 +256,10 @@
         final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
         baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
 
-        if (isCashBasedAccounting(accountingRuleType)) {
-
-            final Long savingsControlAccountId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
-                    .notNull().integerGreaterThanZero();
-
-            final Long savingsReferenceAccountId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
-                    .notNull().integerGreaterThanZero();
-
-            final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue())
-                    .value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
-
-            final Long interestOnSavingsAccountId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue())
-                    .value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
-
-            final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
-                    element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).notNull()
-                    .integerGreaterThanZero();
-
-            final Long incomeFromPenaltyId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
-                    .notNull().integerGreaterThanZero();
-
-            final Long overdraftControlAccountId = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
-                    .value(overdraftControlAccountId).notNull().integerGreaterThanZero();
-
-            final Long incomeFromInterest = this.fromApiJsonHelper
-                    .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
-                    .notNull().integerGreaterThanZero();
-
-            final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
-                    element);
-            baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).notNull()
-                    .integerGreaterThanZero();
-
-            if (null != isDormancyActive && isDormancyActive) {
-                final Long escheatLiabilityAccountId = this.fromApiJsonHelper
-                        .extractLongNamed(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue(), element);
-                baseDataValidator.reset().parameter(SavingProductAccountingParams.ESCHEAT_LIABILITY.getValue())
-                        .value(escheatLiabilityAccountId).notNull().integerGreaterThanZero();
-            }
-
-            validatePaymentChannelFundSourceMappings(baseDataValidator, element);
-            validateChargeToIncomeAccountMappings(baseDataValidator, element);
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
+            savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
+                    baseDataValidator, DepositAccountType.SAVINGS_DEPOSIT);
         }
 
         validateOverdraftParams(baseDataValidator, element);
@@ -457,56 +383,21 @@
             baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
         }
 
-        final Long savingsControlAccountId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.SAVINGS_CONTROL.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long savingsReferenceAccountId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.SAVINGS_REFERENCE.getValue()).value(savingsReferenceAccountId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long transfersInSuspenseAccountId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.TRANSFERS_SUSPENSE.getValue()).value(transfersInSuspenseAccountId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long interestOnSavingsAccountId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.INTEREST_ON_SAVINGS.getValue()).value(interestOnSavingsAccountId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.INCOME_FROM_FEES.getValue(),
-                element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId).ignoreIfNull()
-                .integerGreaterThanZero();
-
-        final Long incomeFromPenaltyId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long overdraftAccountId = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue()).value(overdraftAccountId)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long incomeFromInterest = this.fromApiJsonHelper
-                .extractLongNamed(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue(), element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.INCOME_FROM_INTEREST.getValue()).value(incomeFromInterest)
-                .ignoreIfNull().integerGreaterThanZero();
-
-        final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue(),
-                element);
-        baseDataValidator.reset().parameter(SavingProductAccountingParams.LOSSES_WRITTEN_OFF.getValue()).value(writtenoff).ignoreIfNull()
-                .integerGreaterThanZero();
+        // accounting related data validation
+        final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
+        baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
 
         // dormancy
         final Boolean isDormancyActive = this.fromApiJsonHelper.parameterExists(isDormancyTrackingActiveParamName, element)
                 ? this.fromApiJsonHelper.extractBooleanNamed(isDormancyTrackingActiveParamName, element)
                 : product.isDormancyTrackingActive();
 
+        if (AccountingValidations.isCashBasedAccounting(accountingRuleType)
+                || AccountingValidations.isAccrualPeriodicBasedAccounting(accountingRuleType)) {
+            savingsProductAccountingDataValidator.evaluateProductAccountingData(accountingRuleType, isDormancyActive, element,
+                    baseDataValidator, DepositAccountType.SAVINGS_DEPOSIT);
+        }
+
         if (null != isDormancyActive && isDormancyActive) {
             final Long daysToInact = this.fromApiJsonHelper.parameterExists(daysToInactiveParamName, element)
                     ? this.fromApiJsonHelper.extractLongNamed(daysToInactiveParamName, element)
@@ -536,8 +427,6 @@
             }
         }
 
-        validatePaymentChannelFundSourceMappings(baseDataValidator, element);
-        validateChargeToIncomeAccountMappings(baseDataValidator, element);
         validateOverdraftParams(baseDataValidator, element);
 
         if (this.fromApiJsonHelper.parameterExists(minBalanceForInterestCalculationParamName, element)) {
@@ -558,74 +447,6 @@
         }
     }
 
-    private boolean isCashBasedAccounting(final Integer accountingRuleType) {
-        return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
-    }
-
-    /**
-     * Validation for advanced accounting options
-     */
-    private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
-        if (this.fromApiJsonHelper.parameterExists(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
-            final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper
-                    .extractJsonArrayNamed(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
-            if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
-                int i = 0;
-                do {
-                    final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
-                    final Long paymentTypeId = jsonObject.get(SavingProductAccountingParams.PAYMENT_TYPE.getValue()).getAsLong();
-                    final Long paymentSpecificFundAccountId = jsonObject.get(SavingProductAccountingParams.FUND_SOURCE.getValue())
-                            .getAsLong();
-                    baseDataValidator.reset()
-                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
-                                    + SavingProductAccountingParams.PAYMENT_TYPE.toString())
-                            .value(paymentTypeId).notNull().integerGreaterThanZero();
-                    baseDataValidator.reset()
-                            .parameter(SavingProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
-                                    + SavingProductAccountingParams.FUND_SOURCE.getValue())
-                            .value(paymentSpecificFundAccountId).notNull().integerGreaterThanZero();
-                    i++;
-                } while (i < paymentChannelMappingArray.size());
-            }
-        }
-    }
-
-    private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
-        // validate for both fee and penalty charges
-        validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
-        validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
-    }
-
-    private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
-            final boolean isPenalty) {
-        String parameterName;
-        if (isPenalty) {
-            parameterName = SavingProductAccountingParams.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
-        } else {
-            parameterName = SavingProductAccountingParams.FEE_INCOME_ACCOUNT_MAPPING.getValue();
-        }
-
-        if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
-            final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
-            if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
-                int i = 0;
-                do {
-                    final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
-                    final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SavingProductAccountingParams.CHARGE_ID.getValue(),
-                            jsonObject);
-                    final Long incomeAccountId = this.fromApiJsonHelper
-                            .extractLongNamed(SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), jsonObject);
-                    baseDataValidator.reset().parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.CHARGE_ID.getValue())
-                            .value(chargeId).notNull().integerGreaterThanZero();
-                    baseDataValidator.reset()
-                            .parameter(parameterName + "[" + i + "]." + SavingProductAccountingParams.INCOME_ACCOUNT_ID.getValue())
-                            .value(incomeAccountId).notNull().integerGreaterThanZero();
-                    i++;
-                } while (i < chargeToIncomeAccountMappingArray.size());
-            }
-        }
-    }
-
     private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
         if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
             final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(allowOverdraftParamName, element);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
index aca2e09..47a8085 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java
@@ -46,6 +46,8 @@
 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 @@
         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 @@
 
     @Test
     public void checkAccountingWithSavingsFlow() {
-        this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
 
         final Account assetAccount = this.accountHelper.createAssetAccount();
         final Account incomeAccount = this.accountHelper.createIncomeAccount();
@@ -374,9 +376,106 @@
     }
 
     @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 @@
         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 @@
         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 @@
 
     @Test
     public void checkAccountingWithSharingFlow() {
-        this.savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
 
         final Account assetAccount = this.accountHelper.createAssetAccount();
         final Account incomeAccount = this.accountHelper.createIncomeAccount();
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
index ca2650a..73fab66 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
@@ -25,6 +25,8 @@
 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 @@
     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 @@
         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 --------------------------");
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsProductHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsProductHelper.java
index 64234b5..a22ba29 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsProductHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/savings/SavingsProductHelper.java
@@ -26,6 +26,8 @@
 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 @@
     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 @@
     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 @@
         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 @@
         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 @@
         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 @@
         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);
+    }
+
 }