You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by av...@apache.org on 2021/10/21 11:05:46 UTC

[fineract] branch develop updated: Fineract-1410 Allow Payment types to map to all types of Ledgers (#1917)

This is an automated email from the ASF dual-hosted git repository.

avikg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new c6b7546  Fineract-1410 Allow Payment types to map to all types of Ledgers (#1917)
c6b7546 is described below

commit c6b754621839db74a3f427a5d95e1e478bb73493
Author: ankita10r <92...@users.noreply.github.com>
AuthorDate: Thu Oct 21 16:35:37 2021 +0530

    Fineract-1410 Allow Payment types to map to all types of Ledgers (#1917)
---
 .../service/ProductToGLAccountMappingHelper.java   |  8 ++++--
 .../api/GlobalConfigurationApiConstant.java        |  1 +
 .../data/GlobalConfigurationDataValidator.java     | 12 ++++++---
 .../data/GlobalConfigurationPropertyData.java      | 13 +++++++---
 .../domain/ConfigurationDomainService.java         |  4 +++
 .../domain/ConfigurationDomainServiceJpa.java      | 30 ++++++++++++++++++++++
 .../domain/GlobalConfigurationProperty.java        | 24 ++++++++++++++---
 .../ConfigurationReadPlatformServiceImpl.java      | 11 ++++----
 .../portfolio/savings/SavingsApiConstants.java     |  2 ++
 .../savings/api/SavingsApiSetConstants.java        |  5 ++--
 .../savings/api/SavingsProductsApiResource.java    | 17 ++++++++----
 .../api/SavingsProductsApiResourceSwagger.java     |  4 +++
 .../portfolio/savings/data/SavingsProductData.java | 25 +++++++++++-------
 ..._adding_expenseliablity_to_paymentorfeetype.sql | 25 ++++++++++++++++++
 .../common/GlobalConfigurationHelper.java          | 24 ++++++++++++++---
 15 files changed, 168 insertions(+), 37 deletions(-)

diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java
index 2db50c5..2e44ad9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java
@@ -362,8 +362,7 @@ public class ProductToGLAccountMappingHelper {
     private void savePaymentChannelToFundSourceMapping(final Long productId, final Long paymentTypeId,
             final Long paymentTypeSpecificFundAccountId, final PortfolioProductType portfolioProductType) {
         final PaymentType paymentType = this.paymentTypeRepositoryWrapper.findOneWithNotFoundDetection(paymentTypeId);
-        final GLAccount glAccount = getAccountByIdAndType(LoanProductAccountingParams.FUND_SOURCE.getValue(), GLAccountType.ASSET,
-                paymentTypeSpecificFundAccountId);
+        final GLAccount glAccount = getAccountById(LoanProductAccountingParams.FUND_SOURCE.getValue(), paymentTypeSpecificFundAccountId);
         final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
                 portfolioProductType.getValue(), CashAccountsForLoan.FUND_SOURCE.getValue(), paymentType);
         this.accountMappingRepository.save(accountMapping);
@@ -427,6 +426,11 @@ public class ProductToGLAccountMappingHelper {
         return glAccount;
     }
 
+    public GLAccount getAccountById(final String paramName, final Long accountId) {
+        final GLAccount glAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountId);
+        return glAccount;
+    }
+
     public GLAccount getAccountByIdAndType(final String paramName, final List<GLAccountType> expectedAccountTypes, final Long accountId) {
         final GLAccount glAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountId);
         // validate account is of the expected Type
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiConstant.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiConstant.java
index 3174b45..b8e86d5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiConstant.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationApiConstant.java
@@ -31,5 +31,6 @@ public final class GlobalConfigurationApiConstant {
     public static final String CONFIGURATION_RESOURCE_NAME = "globalConfiguration";
     public static final String localeParamName = "locale";
     public static final String dateFormatParamName = "dateFormat";
+    public static final String STRING_VALUE = "stringValue";
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationDataValidator.java
index 40676ed..668d619 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationDataValidator.java
@@ -43,9 +43,10 @@ import org.springframework.stereotype.Component;
 public class GlobalConfigurationDataValidator {
 
     private final FromJsonHelper fromApiJsonHelper;
-    private static final Set<String> UPDATE_CONFIGURATION_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
-            GlobalConfigurationApiConstant.localeParamName, GlobalConfigurationApiConstant.dateFormatParamName,
-            GlobalConfigurationApiConstant.ENABLED, GlobalConfigurationApiConstant.VALUE, GlobalConfigurationApiConstant.DATE_VALUE));
+    private static final Set<String> UPDATE_CONFIGURATION_DATA_PARAMETERS = new HashSet<>(
+            Arrays.asList(GlobalConfigurationApiConstant.localeParamName, GlobalConfigurationApiConstant.dateFormatParamName,
+                    GlobalConfigurationApiConstant.ENABLED, GlobalConfigurationApiConstant.VALUE, GlobalConfigurationApiConstant.DATE_VALUE,
+                    GlobalConfigurationApiConstant.STRING_VALUE));
 
     @Autowired
     public GlobalConfigurationDataValidator(final FromJsonHelper fromApiJsonHelper) {
@@ -81,6 +82,11 @@ public class GlobalConfigurationDataValidator {
             baseDataValidator.reset().parameter(GlobalConfigurationApiConstant.DATE_VALUE).value(dateValue).notNull();
         }
 
+        if (this.fromApiJsonHelper.parameterExists(GlobalConfigurationApiConstant.STRING_VALUE, element)) {
+            final String stringValue = this.fromApiJsonHelper.extractStringNamed(GlobalConfigurationApiConstant.STRING_VALUE, element);
+            baseDataValidator.reset().parameter(GlobalConfigurationApiConstant.STRING_VALUE).value(stringValue).notNull();
+        }
+
         if (!dataValidationErrors.isEmpty()) {
             throw new PlatformApiDataValidationException(dataValidationErrors);
         }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationPropertyData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
index a893b93..7e54b01 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/data/GlobalConfigurationPropertyData.java
@@ -33,6 +33,7 @@ public class GlobalConfigurationPropertyData {
     private final Long value;
     @SuppressWarnings("unused")
     private final Date dateValue;
+    private String stringValue;
     @SuppressWarnings("unused")
     private final Long id;
     @SuppressWarnings("unused")
@@ -41,22 +42,24 @@ public class GlobalConfigurationPropertyData {
     private final boolean trapDoor;
 
     public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, final Date dateValue,
-            final String description, final boolean trapDoor) {
+            final String stringValue, final String description, final boolean trapDoor) {
         this.name = name;
         this.enabled = enabled;
         this.value = value;
         this.dateValue = dateValue;
+        this.stringValue = stringValue;
         this.id = null;
         this.description = description;
         this.trapDoor = trapDoor;
     }
 
-    public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, Date dateValue, final Long id,
-            final String description, final boolean isTrapDoor) {
+    public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, Date dateValue,
+            final String stringValue, final Long id, final String description, final boolean isTrapDoor) {
         this.name = name;
         this.enabled = enabled;
         this.value = value;
         this.dateValue = dateValue;
+        this.stringValue = stringValue;
         this.id = id;
         this.description = description;
         this.trapDoor = isTrapDoor;
@@ -74,6 +77,10 @@ public class GlobalConfigurationPropertyData {
         return this.value;
     }
 
+    public String getStringValue() {
+        return this.stringValue;
+    }
+
     public Date getDateValue() {
         return this.dateValue;
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index 4b791c9..b35611c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -98,4 +98,8 @@ public interface ConfigurationDomainService {
     boolean isFirstRepaymentDateAfterRescheduleAllowedOnHoliday();
 
     boolean isInterestToBeAppropriatedEquallyWhenGreaterThanEMI();
+
+    String getAccountMappingForPaymentType();
+
+    String getAccountMappingForCharge();
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 321d640..b03c2a9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -363,4 +363,34 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
         }
     }
 
+    @Override
+    public String getAccountMappingForPaymentType() {
+        final String propertyName = "account-mapping-for-payment-type";
+        String defaultValue = "Asset"; // 1 Stands for Account mapped from asset only
+        final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
+        if (property.isEnabled()) {
+            String value = property.getStringValue();
+            if (value == null) {
+                return defaultValue;
+            }
+            return value;
+        }
+        return defaultValue;
+    }
+
+    @Override
+    public String getAccountMappingForCharge() {
+        final String propertyName = "account-mapping-for-charge";
+        String defaultValue = "Income"; // 1 Stands for Account mapped from income only
+        final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(propertyName);
+        if (property.isEnabled()) {
+            String value = property.getValue().toString();
+            if (value == null) {
+                return defaultValue;
+            }
+            return value;
+        }
+        return defaultValue;
+    }
+
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/GlobalConfigurationProperty.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/GlobalConfigurationProperty.java
index e6a3a2e..84e0283 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/GlobalConfigurationProperty.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/GlobalConfigurationProperty.java
@@ -46,6 +46,9 @@ public class GlobalConfigurationProperty extends AbstractPersistableCustom {
     @Column(name = "date_value", nullable = true)
     private Date dateValue;
 
+    @Column(name = "string_value", nullable = true)
+    private String stringValue;
+
     @Column(name = "description", nullable = true)
     private String description;
 
@@ -57,16 +60,18 @@ public class GlobalConfigurationProperty extends AbstractPersistableCustom {
         this.enabled = false;
         this.value = null;
         this.dateValue = null;
+        this.stringValue = null;
         this.description = null;
         this.isTrapDoor = false;
     }
 
     public GlobalConfigurationProperty(final String name, final boolean enabled, final Long value, final Date dateValue,
-            final String description, final boolean isTrapDoor) {
+            final String stringValue, final String description, final boolean isTrapDoor) {
         this.name = name;
         this.enabled = enabled;
         this.value = value;
         this.dateValue = dateValue;
+        this.stringValue = stringValue;
         this.description = description;
         this.isTrapDoor = isTrapDoor;
     }
@@ -83,6 +88,10 @@ public class GlobalConfigurationProperty extends AbstractPersistableCustom {
         return this.dateValue;
     }
 
+    public String getStringValue() {
+        return this.stringValue;
+    }
+
     public Map<String, Object> update(final JsonCommand command) {
 
         final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
@@ -113,6 +122,13 @@ public class GlobalConfigurationProperty extends AbstractPersistableCustom {
             this.dateValue = newDateValue;
         }
 
+        final String stringValueParamName = "stringValue";
+        if (command.isChangeInStringParameterNamed(stringValueParamName, this.stringValue)) {
+            final String newStringValue = command.stringValueOfParameterNamed(stringValueParamName);
+            actualChanges.put(stringValueParamName, newStringValue);
+            this.stringValue = newStringValue;
+        }
+
         final String passwordPropertyName = "force-password-reset-days";
         if (this.name.equalsIgnoreCase(passwordPropertyName)) {
             if ((this.enabled == true && command.hasParameter(valueParamName) && (this.value == 0))
@@ -126,12 +142,12 @@ public class GlobalConfigurationProperty extends AbstractPersistableCustom {
     }
 
     public static GlobalConfigurationProperty newSurveyConfiguration(final String name) {
-        return new GlobalConfigurationProperty(name, false, null, null, null, false);
+        return new GlobalConfigurationProperty(name, false, null, null, null, null, false);
     }
 
     public GlobalConfigurationPropertyData toData() {
-        return new GlobalConfigurationPropertyData(getName(), isEnabled(), getValue(), getDateValue(), this.getId(), this.description,
-                this.isTrapDoor);
+        return new GlobalConfigurationPropertyData(getName(), isEnabled(), getValue(), getDateValue(), getStringValue(), this.getId(),
+                this.description, this.isTrapDoor);
     }
 
     public String getName() {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
index 65eaec1..dd7326a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/service/ConfigurationReadPlatformServiceImpl.java
@@ -52,7 +52,7 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
 
         this.context.authenticatedUser();
 
-        String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.description, c.is_trap_door FROM c_configuration c ";
+        String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.description,c.string_value, c.is_trap_door FROM c_configuration c ";
 
         if (survey) {
             sql += " JOIN x_registered_table on x_registered_table.registered_table_name = c.name ";
@@ -68,11 +68,11 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
     }
 
     @Override
-    public GlobalConfigurationPropertyData retrieveGlobalConfiguration(String name) {
+    public GlobalConfigurationPropertyData retrieveGlobalConfiguration(final String name) {
 
         this.context.authenticatedUser();
 
-        final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.description, c.is_trap_door FROM "
+        final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.string_value, c.description, c.is_trap_door FROM "
                 + "c_configuration c where c.name=? order by c.id";
         final GlobalConfigurationPropertyData globalConfiguration = this.jdbcTemplate.queryForObject(sql, this.rm, new Object[] { name });
 
@@ -84,7 +84,7 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
 
         this.context.authenticatedUser();
 
-        final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.description, c.is_trap_door FROM "
+        final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.date_value, c.string_value ,c.description, c.is_trap_door FROM "
                 + "c_configuration c where c.id=? order by c.id";
         final GlobalConfigurationPropertyData globalConfiguration = this.jdbcTemplate.queryForObject(sql, this.rm,
                 new Object[] { configId });
@@ -102,10 +102,11 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
             final boolean enabled = rs.getBoolean("enabled");
             final Long value = rs.getLong("value");
             final Date dateValue = rs.getDate("date_value");
+            final String stringValue = rs.getString("string_value");
             final String description = rs.getString("description");
             final Long id = rs.getLong("id");
             final boolean isTrapDoor = rs.getBoolean("is_trap_door");
-            return new GlobalConfigurationPropertyData(name, enabled, value, dateValue, id, description, isTrapDoor);
+            return new GlobalConfigurationPropertyData(name, enabled, value, dateValue, stringValue, id, description, isTrapDoor);
         }
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
index 8f2e884..1113571 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
@@ -191,4 +191,6 @@ public class SavingsApiConstants {
     public static final String gsimApplicationId = "applicationId";
     public static final String gsimLastApplication = "lastApplication";
     public static final String ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE = "not.in.active.state";
+
+    public static final String accountMappingForPaymentParamName = "accountMappingForPayment";
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java
index 3ec70e7..d278167 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsApiSetConstants.java
@@ -41,13 +41,12 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
                     "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions",
                     "withdrawalFeeTypeOptions", nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
                     withHoldTaxParamName, taxGroupIdParamName, isDormancyTrackingActiveParamName, daysToInactiveParamName,
-                    daysToDormancyParamName, daysToInactiveParamName));
+                    daysToDormancyParamName, daysToInactiveParamName, accountMappingForPaymentParamName));
 
     /**
      * These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
      * get response parameters to match those of request parameters.
      */
-
     protected static final Set<String> SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
             accountNoParamName, externalIdParamName, statusParamName, activatedOnDateParamName, staffIdParamName, clientIdParamName,
             "clientName", groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency",
@@ -58,7 +57,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
             "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
             "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee",
             "annualFee", onHoldFundsParamName, nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
-            datatables, savingsAmountOnHold));
+            datatables, savingsAmountOnHold, accountMappingForPaymentParamName));
 
     protected static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
             Arrays.asList(idParamName, "accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName,
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
index ab8d4c2..d01f4dc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
@@ -52,6 +52,7 @@ import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToG
 import org.apache.fineract.commands.domain.CommandWrapper;
 import org.apache.fineract.commands.service.CommandWrapperBuilder;
 import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
 import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -100,6 +101,7 @@ public class SavingsProductsApiResource {
     private final ChargeReadPlatformService chargeReadPlatformService;
     private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
     private final TaxReadPlatformService taxReadPlatformService;
+    private final ConfigurationDomainService configurationDomainService;
 
     @Autowired
     public SavingsProductsApiResource(final SavingsProductReadPlatformService savingProductReadPlatformService,
@@ -111,7 +113,7 @@ public class SavingsProductsApiResource {
             final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
             final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
             final ChargeReadPlatformService chargeReadPlatformService, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
-            final TaxReadPlatformService taxReadPlatformService) {
+            final TaxReadPlatformService taxReadPlatformService, final ConfigurationDomainService configurationDomainService) {
         this.savingProductReadPlatformService = savingProductReadPlatformService;
         this.dropdownReadPlatformService = dropdownReadPlatformService;
         this.currencyReadPlatformService = currencyReadPlatformService;
@@ -124,6 +126,7 @@ public class SavingsProductsApiResource {
         this.chargeReadPlatformService = chargeReadPlatformService;
         this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
         this.taxReadPlatformService = taxReadPlatformService;
+        this.configurationDomainService = configurationDomainService;
     }
 
     @POST
@@ -132,7 +135,7 @@ public class SavingsProductsApiResource {
     @Operation(summary = "Create a Savings Product", description = "Creates a Savings Product\n\n"
             + "Mandatory Fields: name, shortName, description, currencyCode, digitsAfterDecimal,inMultiplesOf, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType,accountingRule\n\n"
             + "Mandatory Fields for Cash based accounting (accountingRule = 2): savingsReferenceAccountId, savingsControlAccountId, interestOnSavingsAccountId, incomeFromFeeAccountId, transfersInSuspenseAccountId, incomeFromPenaltyAccountId\n\n"
-            + "Optional Fields: minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, charges, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation,withHoldTax,taxGroupId")
+            + "Optional Fields: minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, paymentChannelToFundSourceMappings, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, charges, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation,withHoldTax,taxGroupId,accountMapping")
     @RequestBody(required = true, content = @Content(schema = @Schema(implementation = SavingsProductsApiResourceSwagger.PostSavingsProductsRequest.class)))
     @ApiResponses({
             @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SavingsProductsApiResourceSwagger.PostSavingsProductsResponse.class))) })
@@ -229,7 +232,8 @@ public class SavingsProductsApiResource {
     @Consumes({ MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_JSON })
     @Operation(summary = "Retrieve Savings Product Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n"
-            + "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "\n" + "savingsproducts/template")
+            + "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "Account Mapping:\n" + "\n"
+            + "savingsproducts/template")
     @ApiResponses({
             @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SavingsProductsApiResourceSwagger.GetSavingsProductsTemplateResponse.class))) })
     public String retrieveTemplate(@Context final UriInfo uriInfo) {
@@ -288,6 +292,8 @@ public class SavingsProductsApiResource {
         final Map<String, List<GLAccountData>> accountingMappingOptions = this.accountingDropdownReadPlatformService
                 .retrieveAccountMappingOptionsForSavingsProducts();
 
+        final String accountMappingForPayment = configurationDomainService.getAccountMappingForPaymentType();
+
         // charges
         final boolean feeChargesOnly = false;
         Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSavingsProductApplicableCharges(feeChargesOnly);
@@ -301,13 +307,14 @@ public class SavingsProductsApiResource {
             savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
                     interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
                     lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
-                    accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions);
+                    accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions, accountMappingForPayment);
         } else {
             savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
                     interestCalculationType, interestCalculationDaysInYearType, accountingRule, currencyOptions,
                     interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
                     interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
-                    paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions);
+                    paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, taxGroupOptions,
+                    accountMappingForPayment);
         }
 
         return savingsProductToReturn;
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 20fdd3e..5aaeabb 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
@@ -70,6 +70,8 @@ final class SavingsProductsApiResourceSwagger {
         @Schema(example = "1")
         public Integer accountingRule;
         public Set<PostSavingsCharges> charges;
+        @Schema(example = "accountMappingForPayment")
+        public String accountMappingForPayment;
     }
 
     @Schema(description = "PostSavingsProductsResponse")
@@ -725,6 +727,8 @@ final class SavingsProductsApiResourceSwagger {
         public Set<GetSavingsProductsTemplateAccountingRule> accountingRuleOptions;
         public GetSavingsProductsAccountingMappingOptions accountingMappingOptions;
         public Set<GetSavingsProductsChargeOptions> chargeOptions;
+        public GetSavingsProductsResponse.GetSavingsCurrency accountMapping;
+
     }
 
     @Schema(description = "DeleteSavingsProductsProductIdResponse")
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java
index 856adf4..95505c8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java
@@ -62,6 +62,7 @@ public final class SavingsProductData implements Serializable {
     private final boolean withHoldTax;
     private final TaxGroupData taxGroup;
     private String depositAccountType = null;
+    private final String accountMappingForPayment;
 
     // accounting
     private final EnumOptionData accountingRule;
@@ -102,7 +103,8 @@ public final class SavingsProductData implements Serializable {
             final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
             final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
             final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
-            final Collection<ChargeData> penaltyOptions, final Collection<TaxGroupData> taxGroupOptions) {
+            final Collection<ChargeData> penaltyOptions, final Collection<TaxGroupData> taxGroupOptions,
+            final String accountMappingForPayment) {
 
         final Long id = null;
         final String name = null;
@@ -141,7 +143,7 @@ public final class SavingsProductData implements Serializable {
                 penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
                 minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft,
                 minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions, isDormancyTrackingActive, daysToInactive,
-                daysToDormancy, daysToEscheat);
+                daysToDormancy, daysToEscheat, accountMappingForPayment);
     }
 
     public static SavingsProductData withCharges(final SavingsProductData product, final Collection<ChargeData> charges) {
@@ -158,7 +160,7 @@ public final class SavingsProductData implements Serializable {
                 product.minRequiredBalance, product.enforceMinRequiredBalance, product.minBalanceForInterestCalculation,
                 product.nominalAnnualInterestRateOverdraft, product.minOverdraftForInterestCalculation, product.withHoldTax,
                 product.taxGroup, product.taxGroupOptions, product.isDormancyTrackingActive, product.daysToInactive, product.daysToDormancy,
-                product.daysToEscheat);
+                product.daysToEscheat, product.accountMappingForPayment);
     }
 
     /**
@@ -167,6 +169,7 @@ public final class SavingsProductData implements Serializable {
      *
      * @param taxGroupOptions
      *            TODO
+     * @param accountMapping
      */
     public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection<CurrencyData> currencyOptions,
             final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
@@ -176,7 +179,7 @@ public final class SavingsProductData implements Serializable {
             final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
             final Collection<PaymentTypeData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
             final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> chargeOptions,
-            final Collection<ChargeData> penaltyOptions, Collection<TaxGroupData> taxGroupOptions) {
+            final Collection<ChargeData> penaltyOptions, Collection<TaxGroupData> taxGroupOptions, final String accountMappingForPayment) {
 
         return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
                 existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
@@ -192,7 +195,7 @@ public final class SavingsProductData implements Serializable {
                 existingProduct.minBalanceForInterestCalculation, existingProduct.nominalAnnualInterestRateOverdraft,
                 existingProduct.minOverdraftForInterestCalculation, existingProduct.withHoldTax, existingProduct.taxGroup, taxGroupOptions,
                 existingProduct.isDormancyTrackingActive, existingProduct.daysToInactive, existingProduct.daysToDormancy,
-                existingProduct.daysToEscheat);
+                existingProduct.daysToEscheat, existingProduct.accountMappingForPayment);
     }
 
     public static SavingsProductData withAccountingDetails(final SavingsProductData existingProduct,
@@ -212,6 +215,7 @@ public final class SavingsProductData implements Serializable {
         final Map<String, List<GLAccountData>> accountingMappingOptions = null;
         final Collection<ChargeData> chargeOptions = null;
         final Collection<ChargeData> penaltyOptions = null;
+        final String accountMappingForPayment = null;
 
         return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
                 existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
@@ -227,7 +231,7 @@ public final class SavingsProductData implements Serializable {
                 existingProduct.minBalanceForInterestCalculation, existingProduct.nominalAnnualInterestRateOverdraft,
                 existingProduct.minOverdraftForInterestCalculation, existingProduct.withHoldTax, existingProduct.taxGroup,
                 existingProduct.taxGroupOptions, existingProduct.isDormancyTrackingActive, existingProduct.daysToInactive,
-                existingProduct.daysToDormancy, existingProduct.daysToEscheat);
+                existingProduct.daysToDormancy, existingProduct.daysToEscheat, existingProduct.accountMappingForPayment);
     }
 
     public static SavingsProductData instance(final Long id, final String name, final String shortName, final String description,
@@ -260,6 +264,7 @@ public final class SavingsProductData implements Serializable {
         final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
         final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
         final Collection<TaxGroupData> taxGroupOptions = null;
+        final String accountMappingForPayment = null;
 
         return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
                 interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
@@ -270,7 +275,7 @@ public final class SavingsProductData implements Serializable {
                 penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
                 minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft,
                 minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions, isDormancyTrackingActive, daysToInactive,
-                daysToDormancy, daysToEscheat);
+                daysToDormancy, daysToEscheat, accountMappingForPayment);
     }
 
     public static SavingsProductData lookup(final Long id, final String name) {
@@ -320,6 +325,7 @@ public final class SavingsProductData implements Serializable {
         final Long daysToInactive = null;
         final Long daysToDormancy = null;
         final Long daysToEscheat = null;
+        final String accountMappingForPayment = null;
 
         return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
                 interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
@@ -330,7 +336,7 @@ public final class SavingsProductData implements Serializable {
                 penaltyOptions, feeToIncomeAccountMappings, penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit,
                 minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft,
                 minOverdraftForInterestCalculation, withHoldTax, taxGroup, taxGroupOptions, isDormancyTrackingActive, daysToInactive,
-                daysToDormancy, daysToEscheat);
+                daysToDormancy, daysToEscheat, accountMappingForPayment);
     }
 
     private SavingsProductData(final Long id, final String name, final String shortName, final String description,
@@ -354,7 +360,7 @@ public final class SavingsProductData implements Serializable {
             final BigDecimal minBalanceForInterestCalculation, final BigDecimal nominalAnnualInterestRateOverdraft,
             final BigDecimal minOverdraftForInterestCalculation, final boolean withHoldTax, final TaxGroupData taxGroup,
             final Collection<TaxGroupData> taxGroupOptions, final Boolean isDormancyTrackingActive, final Long daysToInactive,
-            final Long daysToDormancy, final Long daysToEscheat) {
+            final Long daysToDormancy, final Long daysToEscheat, final String accountMappingForPayment) {
         this.id = id;
         this.name = name;
         this.shortName = shortName;
@@ -411,6 +417,7 @@ public final class SavingsProductData implements Serializable {
         this.daysToInactive = daysToInactive;
         this.daysToDormancy = daysToDormancy;
         this.daysToEscheat = daysToEscheat;
+        this.accountMappingForPayment = accountMappingForPayment;
     }
 
     public boolean hasAccountingEnabled() {
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V374__adding_expenseliablity_to_paymentorfeetype.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V374__adding_expenseliablity_to_paymentorfeetype.sql
new file mode 100644
index 0000000..fa090be
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V374__adding_expenseliablity_to_paymentorfeetype.sql
@@ -0,0 +1,25 @@
+--
+-- 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.
+--
+
+ALTER TABLE `c_configuration`
+    ADD COLUMN `string_value` VARCHAR(100) NULL DEFAULT NULL AFTER `date_value`;
+
+insert into c_configuration(name, string_value, enabled, description) values('account-mapping-for-payment-type', 'Asset', '1', 'Asset: default for asset, Use comma seperated values for Liability, Asset and Expense accounts');
+
+insert into c_configuration(name, string_value, enabled, description) values('account-mapping-for-charge', 'Income', '1', 'Income: default for Income, Use comma seperated values for Income, Liability and Expense accounts');
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
index 39657e2..6721857 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
@@ -88,9 +88,9 @@ public class GlobalConfigurationHelper {
         ArrayList<HashMap> expectedGlobalConfigurations = getAllDefaultGlobalConfigurations();
         ArrayList<HashMap> actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec);
 
-        // There are currently 30 global configurations.
-        Assertions.assertEquals(30, expectedGlobalConfigurations.size());
-        Assertions.assertEquals(30, actualGlobalConfigurations.size());
+        // There are currently 32 global configurations.
+        Assertions.assertEquals(32, expectedGlobalConfigurations.size());
+        Assertions.assertEquals(32, actualGlobalConfigurations.size());
 
         for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
 
@@ -362,6 +362,24 @@ public class GlobalConfigurationHelper {
         isInterestAppropriationEnabled.put("trapDoor", false);
         defaults.add(isInterestAppropriationEnabled);
 
+        HashMap<String, Object> isAccountMappedForPayment = new HashMap<>();
+        isAccountMappedForPayment.put("id", 35);
+        isAccountMappedForPayment.put("name", "account-mapping-for-payment-type");
+        isAccountMappedForPayment.put("value", 0);
+        isAccountMappedForPayment.put("enabled", false);
+        isAccountMappedForPayment.put("trapDoor", false);
+        isAccountMappedForPayment.put("string_value", "Asset");
+        defaults.add(isAccountMappedForPayment);
+
+        HashMap<String, Object> isAccountMappedForCharge = new HashMap<>();
+        isAccountMappedForCharge.put("id", 36);
+        isAccountMappedForCharge.put("name", "account-mapping-for-charge");
+        isAccountMappedForCharge.put("value", 0);
+        isAccountMappedForCharge.put("enabled", false);
+        isAccountMappedForCharge.put("trapDoor", false);
+        isAccountMappedForCharge.put("string_value", "Income");
+        defaults.add(isAccountMappedForCharge);
+
         return defaults;
     }