Merge pull request #854 from vishwasbabu/develop
MIFOSX-865: initial work around adding support for accrual accounting
This commit is contained in:
+2
-1
@@ -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;
|
||||
|
||||
+4
-3
@@ -198,8 +198,8 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
|
||||
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<ApiParameterError> dataValidationErrors) {
|
||||
|
||||
+38
-10
@@ -139,6 +139,41 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
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<String, Object> 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<String, Object> 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);
|
||||
@@ -147,15 +182,6 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
|
||||
+3
-4
@@ -50,8 +50,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
+ " 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
|
||||
@@ -128,7 +127,8 @@ 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<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
@@ -191,7 +191,6 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
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);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL)) {
|
||||
|
||||
+4
-5
@@ -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,
|
||||
@@ -175,7 +176,6 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
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,
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+14
-6
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -3238,7 +3238,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
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<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
|
||||
+9
-1
@@ -614,7 +614,15 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
+11
-2
@@ -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<ApiParameterError> dataValidationErrors) {
|
||||
|
||||
+11
-1
@@ -538,8 +538,18 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user