From fbc55d5dd18fe93d971b1af8756f0452add2363f Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Fri, 11 Apr 2014 14:25:29 -0700 Subject: [PATCH] MIFOSX-865: initial work around adding support for accrual accounting --- .../accounting/common/AccountingRuleType.java | 3 +- ...AccountMappingFromApiJsonDeserializer.java | 11 ++-- .../LoanProductToGLAccountMappingHelper.java | 56 ++++++++++++++----- ...AccountMappingReadPlatformServiceImpl.java | 55 +++++++++--------- ...ccountMappingWritePlatformServiceImpl.java | 13 ++--- ...avingsProductToGLAccountMappingHelper.java | 22 +++++--- .../portfolio/loanaccount/domain/Loan.java | 3 +- .../loanproduct/domain/LoanProduct.java | 18 ++++-- .../LoanProductDataValidator.java | 13 ++++- .../savings/domain/SavingsProduct.java | 12 +++- 10 files changed, 135 insertions(+), 71 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingRuleType.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingRuleType.java index 351dd39bc..47c5d7803 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingRuleType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingRuleType.java @@ -12,7 +12,8 @@ public enum AccountingRuleType { NONE(1, "accountingRuleType.none"), // CASH_BASED(2, "accountingRuleType.cash"), // - ACCRUAL_BASED(3, "accountingRuleType.accrual"); + ACCRUAL_PERIODIC(3, "accountingRuleType.accrual.periodic"), // + ACCRUAL_UPFRONT(4, "accountingRuleType.accrual.upfront"); // private final Integer value; private final String code; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java index f99265379..4c120aaf6 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java @@ -190,16 +190,16 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer { SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element); baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue()) .value(overdraftAccount).notNull().integerGreaterThanZero(); - + final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed( SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), element); baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue()) .value(incomeFromInterest).notNull().integerGreaterThanZero(); - + final Long writtenOff = this.fromApiJsonHelper.extractLongNamed( SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element); - baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()) - .value(writtenOff).notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writtenOff) + .notNull().integerGreaterThanZero(); } @@ -211,7 +211,8 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer { } private boolean isAccrualBasedAccounting(final Integer accountingRuleType) { - return AccountingRuleType.ACCRUAL_BASED.getValue().equals(accountingRuleType); + return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingRuleType) + || AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingRuleType); } private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/LoanProductToGLAccountMappingHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/LoanProductToGLAccountMappingHelper.java index 9f72f2fbd..294b8770d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/LoanProductToGLAccountMappingHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/LoanProductToGLAccountMappingHelper.java @@ -139,25 +139,51 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi case NONE: break; case CASH_BASED: - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), overPaymentAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId); - //$FALL-THROUGH$ - case ACCRUAL_BASED: - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId); - changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId); + populateChangesForCashBasedAccounting(changes, fundAccountId, loanPortfolioAccountId, incomeFromInterestId, + incomeFromFeeId, incomeFromPenaltyId, writeOffAccountId, overPaymentAccountId, transfersInSuspenseAccountId); + break; + case ACCRUAL_PERIODIC: + populateChangesForAccrualBasedAccounting(changes, fundAccountId, loanPortfolioAccountId, incomeFromInterestId, + incomeFromFeeId, incomeFromPenaltyId, writeOffAccountId, overPaymentAccountId, transfersInSuspenseAccountId, + receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId); + break; + case ACCRUAL_UPFRONT: + populateChangesForAccrualBasedAccounting(changes, fundAccountId, loanPortfolioAccountId, incomeFromInterestId, + incomeFromFeeId, incomeFromPenaltyId, writeOffAccountId, overPaymentAccountId, transfersInSuspenseAccountId, + receivableInterestAccountId, receivableFeeAccountId, receivablePenaltyAccountId); break; } return changes; } + private void populateChangesForAccrualBasedAccounting(final Map changes, final Long fundAccountId, + final Long loanPortfolioAccountId, final Long incomeFromInterestId, final Long incomeFromFeeId, final Long incomeFromPenaltyId, + final Long writeOffAccountId, final Long overPaymentAccountId, final Long transfersInSuspenseAccountId, + final Long receivableInterestAccountId, final Long receivableFeeAccountId, final Long receivablePenaltyAccountId) { + + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId); + + populateChangesForCashBasedAccounting(changes, fundAccountId, loanPortfolioAccountId, incomeFromInterestId, incomeFromFeeId, + incomeFromPenaltyId, writeOffAccountId, overPaymentAccountId, transfersInSuspenseAccountId); + + } + + private void populateChangesForCashBasedAccounting(final Map changes, final Long fundAccountId, + final Long loanPortfolioAccountId, final Long incomeFromInterestId, final Long incomeFromFeeId, final Long incomeFromPenaltyId, + final Long writeOffAccountId, final Long overPaymentAccountId, final Long transfersInSuspenseAccountId) { + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), overPaymentAccountId); + changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId); + } + /** * Examines and updates each account mapping for given loan product with * changes passed in from the Json element @@ -199,7 +225,9 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi mergeLoanToLiabilityAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString(), changes); break; - case ACCRUAL_BASED: + case ACCRUAL_UPFRONT: + // fall through to periodic accrual + case ACCRUAL_PERIODIC: // assets (including receivables) mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), changes); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index 4e7736e72..185031aea 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -44,14 +44,13 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product private static final class ProductToGLAccountMappingMapper implements RowMapper> { public String schema() { - return " mapping.id as id, mapping.gl_account_id as glAccountId,glaccount.name as name,glaccount.gl_code as code," + return " mapping.id as id, mapping.gl_account_id as glAccountId,glaccount.name as name,glaccount.gl_code as code," + " mapping.product_id as productId, mapping.product_type as productType,mapping.financial_account_type as financialAccountType, " + " mapping.payment_type as paymentTypeId,cv.code_value codeValue, mapping.charge_id as chargeId, charge.is_penalty as penalty, " + " charge.name as chargeName " + " from acc_product_mapping mapping left join m_charge charge on mapping.charge_id=charge.id " + " left join acc_gl_account as glaccount on mapping.gl_account_id = glaccount.id" - + " left join m_code_value cv on mapping.payment_type=cv.id" - + " where mapping.product_type= ? "; + + " left join m_code_value cv on mapping.payment_type=cv.id" + " where mapping.product_type= ? "; } @Override @@ -69,7 +68,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product final String glCode = rs.getString("code"); final String chargeName = rs.getString("chargeName"); final Boolean penalty = rs.getBoolean("penalty"); - + final Map loanProductToGLAccountMap = new LinkedHashMap(5); loanProductToGLAccountMap.put("id", id); loanProductToGLAccountMap.put("glAccountId", glAccountId); @@ -77,7 +76,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product loanProductToGLAccountMap.put("productType", productType); loanProductToGLAccountMap.put("financialAccountType", financialAccountType); loanProductToGLAccountMap.put("paymentTypeId", paymentTypeId); - loanProductToGLAccountMap.put("paymentTypeValue",paymentTypeValue); + loanProductToGLAccountMap.put("paymentTypeValue", paymentTypeValue); loanProductToGLAccountMap.put("chargeId", chargeId); loanProductToGLAccountMap.put("chargeName", chargeName); loanProductToGLAccountMap.put("penalty", penalty); @@ -106,9 +105,9 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product final CASH_ACCOUNTS_FOR_LOAN glAccountForLoan = CASH_ACCOUNTS_FOR_LOAN.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(glAccountId, glAccountName, glCode); + final String glAccountName = (String) productToGLAccountMap.get("glAccountName"); + final String glCode = (String) productToGLAccountMap.get("glCode"); + final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE)) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.FUND_SOURCE.getValue(), gLAccountData); @@ -128,16 +127,17 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.OVERPAYMENT.getValue(), gLAccountData); } } - } else if (AccountingRuleType.ACCRUAL_BASED.getValue().equals(accountingType)) { + } else if (AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingType) + || AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingType)) { for (final Map productToGLAccountMap : listOfProductToGLAccountMaps) { final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType"); final ACCRUAL_ACCOUNTS_FOR_LOAN glAccountForLoan = ACCRUAL_ACCOUNTS_FOR_LOAN.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(glAccountId, glAccountName, glCode); + final String glAccountName = (String) productToGLAccountMap.get("glAccountName"); + final String glCode = (String) productToGLAccountMap.get("glCode"); + final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE)) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.FUND_SOURCE.getValue(), gLAccountData); @@ -187,10 +187,9 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product final CASH_ACCOUNTS_FOR_SAVINGS glAccountForSavings = CASH_ACCOUNTS_FOR_SAVINGS.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(glAccountId, glAccountName, glCode); - + final String glAccountName = (String) productToGLAccountMap.get("glAccountName"); + final String glCode = (String) productToGLAccountMap.get("glCode"); + final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE)) { accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.SAVINGS_REFERENCE.getValue(), gLAccountData); @@ -206,9 +205,9 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.INTEREST_ON_SAVINGS.getValue(), gLAccountData); } else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL)) { accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), gLAccountData); - }else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF)) { + } else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF)) { accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.LOSSES_WRITTEN_OFF.getValue(), gLAccountData); - }else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST)) { + } else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST)) { accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.INCOME_FROM_INTEREST.getValue(), gLAccountData); } } @@ -245,14 +244,14 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product paymentTypeToGLAccountMappers = new ArrayList(); } final Long paymentTypeId = (Long) productToGLAccountMap.get("paymentTypeId"); - final String paymentTypeValue = (String)productToGLAccountMap.get("paymentTypeValue"); + final String paymentTypeValue = (String) productToGLAccountMap.get("paymentTypeValue"); final CodeValueData codeValueData = CodeValueData.instance(paymentTypeId, paymentTypeValue); 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(glAccountId, glAccountName, glCode); - - final PaymentTypeToGLAccountMapper paymentTypeToGLAccountMapper = new PaymentTypeToGLAccountMapper(codeValueData,gLAccountData); + final String glAccountName = (String) productToGLAccountMap.get("glAccountName"); + final String glCode = (String) productToGLAccountMap.get("glCode"); + final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); + + final PaymentTypeToGLAccountMapper paymentTypeToGLAccountMapper = new PaymentTypeToGLAccountMapper(codeValueData, gLAccountData); paymentTypeToGLAccountMappers.add(paymentTypeToGLAccountMapper); } return paymentTypeToGLAccountMappers; @@ -296,12 +295,12 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product chargeToGLAccountMappers = new ArrayList(); } final Long glAccountId = (Long) chargeToIncomeAccountMap.get("glAccountId"); - final String glAccountName = (String)chargeToIncomeAccountMap.get("glAccountName"); - final String glCode = (String)chargeToIncomeAccountMap.get("glCode"); + final String glAccountName = (String) chargeToIncomeAccountMap.get("glAccountName"); + final String glCode = (String) chargeToIncomeAccountMap.get("glCode"); final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); final Long chargeId = (Long) chargeToIncomeAccountMap.get("chargeId"); - final String chargeName = (String)chargeToIncomeAccountMap.get("chargeName"); - final Boolean penalty1 = (Boolean)chargeToIncomeAccountMap.get("penalty"); + final String chargeName = (String) chargeToIncomeAccountMap.get("chargeName"); + final Boolean penalty1 = (Boolean) chargeToIncomeAccountMap.get("penalty"); final ChargeData chargeData = ChargeData.lookup(chargeId, chargeName, penalty1); final ChargeToGLAccountMapper chargeToGLAccountMapper = new ChargeToGLAccountMapper(chargeData, gLAccountData); chargeToGLAccountMappers.add(chargeToGLAccountMapper); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java index 5f78d16bd..d75a28dad 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java @@ -92,8 +92,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null); this.loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null); break; - case ACCRUAL_BASED: - + case ACCRUAL_UPFRONT: + // Fall Through + case ACCRUAL_PERIODIC: // assets (including receivables) this.loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId, @@ -170,17 +171,16 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), savingProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.getValue()); - + this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), savingProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST.getValue()); - // expenses this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), savingProductId, CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue()); - + this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), savingProductId, CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF.getValue()); @@ -197,8 +197,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null); this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null); break; - /*** Do not have accrual based accounting for now ***/ - case ACCRUAL_BASED: + default: break; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java index 33f86a60e..d97f2e3df 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java @@ -124,10 +124,10 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa element); final Long transfersInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed( SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element); - final Long overdraftControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), - element); - final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), - element); + final Long overdraftControlId = this.fromApiJsonHelper.extractLongNamed( + SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element); + final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed( + SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), element); final Long writeOffId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element); switch (accountingRuleType) { @@ -144,7 +144,11 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), incomeFromInterest); changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffId); break; - case ACCRUAL_BASED: + case ACCRUAL_PERIODIC: + break; + case ACCRUAL_UPFRONT: + break; + default: break; } return changes; @@ -169,7 +173,7 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa mergeSavingsToAssetAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.toString(), changes); - + mergeSavingsToAssetAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.toString(), changes); @@ -203,7 +207,11 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.toString(), changes); break; - case ACCRUAL_BASED: + case ACCRUAL_PERIODIC: + break; + case ACCRUAL_UPFRONT: + break; + default: break; } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index c248b7247..094ffb7d2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -3238,7 +3238,8 @@ public class Loan extends AbstractPersistable { accountingBridgeData.put("currency", currencyData); accountingBridgeData.put("calculatedInterest", this.summary.getTotalInterestCharged()); accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnLoanProduct()); - accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnLoanProduct()); + accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnLoanProduct()); + accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnLoanProduct()); final List> newLoanTransactions = new ArrayList>(); for (final LoanTransaction transaction : this.loanTransactions) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index d79fb3ed0..b77804018 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -177,7 +177,7 @@ public class LoanProduct extends AbstractPersistable { outstandingLoanBalance = command.bigDecimalValueOfParameterNamed(LoanProductConstants.outstandingLoanBalanceParameterName); maxTrancheCount = command.integerValueOfParameterNamed(LoanProductConstants.maxTrancheCountParameterName); } - + final Integer graceOnArrearsAgeing = command.integerValueOfParameterNamed(LoanProductConstants.graceOnArrearsAgeingParameterName); return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal, @@ -186,7 +186,7 @@ public class LoanProduct extends AbstractPersistable { numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle, startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount, - outstandingLoanBalance,graceOnArrearsAgeing); + outstandingLoanBalance, graceOnArrearsAgeing); } /** @@ -396,7 +396,7 @@ public class LoanProduct extends AbstractPersistable { final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle, final LocalDate startDate, final LocalDate closeDate, final String externalId, final boolean useBorrowerCycle, final Set loanProductBorrowerCycleVariations, final boolean multiDisburseLoan, - final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance,final Integer graceOnArrearsAgeing) { + final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing) { this.fund = fund; this.transactionProcessingStrategy = transactionProcessingStrategy; this.name = name.trim(); @@ -414,7 +414,7 @@ public class LoanProduct extends AbstractPersistable { this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, graceOnInterestPayment, - graceOnInterestCharged, amortizationMethod, inArrearsTolerance,graceOnArrearsAgeing); + graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing); this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings(); @@ -614,7 +614,15 @@ public class LoanProduct extends AbstractPersistable { } public boolean isAccrualBasedAccountingEnabled() { - return AccountingRuleType.ACCRUAL_BASED.getValue().equals(this.accountingRule); + return isUpfrontAccrualAccounting() || isPeriodicAccrualAccounting(); + } + + public boolean isUpfrontAccrualAccounting() { + return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(this.accountingRule); + } + + public boolean isPeriodicAccrualAccounting() { + return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(this.accountingRule); } public Money getPrincipalAmount() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java index db82b588c..00f8fed6b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -254,7 +254,8 @@ public final class LoanProductDataValidator { final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( LoanProductConstants.graceOnArrearsAgeingParameterName, element); - baseDataValidator.reset().parameter(LoanProductConstants.graceOnArrearsAgeingParameterName).value(graceOnArrearsAgeing).zeroOrPositiveAmount(); + baseDataValidator.reset().parameter(LoanProductConstants.graceOnArrearsAgeingParameterName).value(graceOnArrearsAgeing) + .zeroOrPositiveAmount(); // accounting related data validation final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault()); @@ -973,7 +974,15 @@ public final class LoanProductDataValidator { } private boolean isAccrualBasedAccounting(final Integer accountingRuleType) { - return AccountingRuleType.ACCRUAL_BASED.getValue().equals(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 dataValidationErrors) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java index d748f4c8c..a704401cc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java @@ -538,8 +538,18 @@ public class SavingsProduct extends AbstractPersistable { return AccountingRuleType.CASH_BASED.getValue().equals(this.accountingRule); } + // TODO this entire block is currently unnecessary as Savings does not have + // accrual accounting public boolean isAccrualBasedAccountingEnabled() { - return AccountingRuleType.ACCRUAL_BASED.getValue().equals(this.accountingRule); + return isUpfrontAccrualAccounting() || isPeriodicAccrualAccounting(); + } + + public boolean isPeriodicAccrualAccounting() { + return AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(this.accountingRule); + } + + public boolean isUpfrontAccrualAccounting() { + return AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(this.accountingRule); } public Integer getAccountingType() {