Merge pull request #854 from vishwasbabu/develop

MIFOSX-865: initial work around adding support for accrual accounting
This commit is contained in:
Vishwas Babu A J
2014-04-11 14:28:40 -07:00
10 changed files with 135 additions and 71 deletions
@@ -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;
@@ -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<ApiParameterError> dataValidationErrors) {
@@ -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<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);
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);
@@ -44,14 +44,13 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
private static final class ProductToGLAccountMappingMapper implements RowMapper<Map<String, Object>> {
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<String, Object> loanProductToGLAccountMap = new LinkedHashMap<String, Object>(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<String, Object> 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<PaymentTypeToGLAccountMapper>();
}
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<ChargeToGLAccountMapper>();
}
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);
@@ -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;
}
@@ -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;
}
}
@@ -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) {
@@ -177,7 +177,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
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<Long> {
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<Long> {
final AccountingRuleType accountingRuleType, final boolean includeInBorrowerCycle, final LocalDate startDate,
final LocalDate closeDate, final String externalId, final boolean useBorrowerCycle,
final Set<LoanProductBorrowerCycleVariations> 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<Long> {
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<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() {
@@ -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) {
@@ -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() {