optionally account different fees and penalties under different heads

This commit is contained in:
Vishwas Babu AJ
2013-06-07 09:26:12 +05:30
parent 97daba62cb
commit 4d419c3e45
20 changed files with 493 additions and 55 deletions
@@ -0,0 +1,3 @@
ALTER TABLE `acc_product_mapping`
ADD COLUMN `charge_id` BIGINT(20) NULL DEFAULT NULL AFTER `payment_type`,
ADD CONSTRAINT `FK_acc_product_mapping_m_charge` FOREIGN KEY (`charge_id`) REFERENCES `m_charge` (`id`);
@@ -85,7 +85,8 @@ public class AccountingConstants {
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE(
"receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE(
"receivablePenaltyAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelToFundSourceMappings"), PAYMENT_TYPE(
"paymentTypeId");
"paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING("feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING(
"penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID("incomeAccountId");
private final String value;
@@ -0,0 +1,29 @@
package org.mifosplatform.accounting.journalentry.data;
import java.math.BigDecimal;
public class ChargePaymentDTO {
private final Long chargeId;
private final BigDecimal amount;
private final Long loanChargeId;
public ChargePaymentDTO(Long chargeId, Long loanChargeId, BigDecimal amount) {
this.chargeId = chargeId;
this.amount = amount;
this.loanChargeId = loanChargeId;
}
public Long getChargeId() {
return this.chargeId;
}
public BigDecimal getAmount() {
return this.amount;
}
public Long getLoanChargeId() {
return this.loanChargeId;
}
}
@@ -7,6 +7,7 @@ package org.mifosplatform.accounting.journalentry.data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
@@ -28,9 +29,14 @@ public class LoanTransactionDTO {
/*** Boolean values determines if the transaction is reversed ***/
private final boolean reversed;
/** Breakdowns of fees and penalties this Transaction pays **/
private final List<ChargePaymentDTO> penaltyPayments;
private final List<ChargePaymentDTO> feePayments;
public LoanTransactionDTO(final Long paymentTypeId, final String transactionId, final Date transactionDate,
final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest,
final BigDecimal fees, final BigDecimal penalties, final boolean reversed) {
final BigDecimal fees, final BigDecimal penalties, final boolean reversed, final List<ChargePaymentDTO> feePayments,
final List<ChargePaymentDTO> penaltyPayments) {
this.paymentTypeId = paymentTypeId;
this.transactionId = transactionId;
this.transactionDate = transactionDate;
@@ -41,6 +47,8 @@ public class LoanTransactionDTO {
this.penalties = penalties;
this.reversed = reversed;
this.transactionType = transactionType;
this.feePayments = feePayments;
this.penaltyPayments = penaltyPayments;
}
public String getTransactionId() {
@@ -83,4 +91,12 @@ public class LoanTransactionDTO {
return this.paymentTypeId;
}
public List<ChargePaymentDTO> getPenaltyPayments() {
return this.penaltyPayments;
}
public List<ChargePaymentDTO> getFeePayments() {
return this.feePayments;
}
}
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.journalentry.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -18,6 +19,7 @@ import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO;
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
@@ -30,6 +32,7 @@ import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidEx
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.office.domain.OfficeRepository;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
@@ -77,8 +80,28 @@ public class AccountingProcessorHelper {
final boolean reversed = (Boolean) map.get("reversed");
final Long paymentTypeId = (Long) map.get("paymentTypeId");
List<ChargePaymentDTO> feePayments = new ArrayList<ChargePaymentDTO>();
List<ChargePaymentDTO> penaltyPayments = new ArrayList<ChargePaymentDTO>();
// extract charge payment details (if exists)
if (map.containsKey("loanChargesPaid")) {
@SuppressWarnings("unchecked")
final List<Map<String, Object>> loanChargesPaidData = (List<Map<String, Object>>) map.get("loanChargesPaid");
for (final Map<String, Object> loanChargePaid : loanChargesPaidData) {
final Long chargeId = (Long) loanChargePaid.get("chargeId");
final Long loanChargeId = (Long) loanChargePaid.get("chargeId");
final boolean isPenalty = (Boolean) loanChargePaid.get("isPenalty");
final BigDecimal chargeAmountPaid = (BigDecimal) loanChargePaid.get("amount");
ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, loanChargeId, chargeAmountPaid);
if (isPenalty) {
penaltyPayments.add(chargePaymentDTO);
} else {
feePayments.add(chargePaymentDTO);
}
}
}
final LoanTransactionDTO transaction = new LoanTransactionDTO(paymentTypeId, transactionId, transactionDate, transactionType,
amount, principal, interest, fees, penalties, reversed);
amount, principal, interest, fees, penalties, reversed, feePayments, penaltyPayments);
newLoanTransactions.add(transaction);
@@ -304,6 +327,48 @@ public class AccountingProcessorHelper {
}
}
public void createCreditJournalEntryOrReversalForLoanCharges(final Office office, final int accountMappingTypeId,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate,
final BigDecimal totalAmount, final Boolean isReversal, final List<ChargePaymentDTO> chargePaymentDTOs) {
/***
* Map to track each account and the net credit to be made for a
* particular account
***/
Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<GLAccount, BigDecimal>();
for (ChargePaymentDTO chargePaymentDTO : chargePaymentDTOs) {
Long chargeId = chargePaymentDTO.getChargeId();
GLAccount chargeSpecificAccount = getLinkedGLAccountForLoanCharges(loanProductId, accountMappingTypeId, chargeId);
BigDecimal chargeSpecificAmount = chargePaymentDTO.getAmount();
// adjust net credit amount if the account is already present in the
// map
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
}
creditDetailsMap.put(chargeSpecificAccount, chargeSpecificAmount);
}
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
for (Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
GLAccount account = entry.getKey();
BigDecimal amount = entry.getValue();
totalCreditedAmount = totalCreditedAmount.add(amount);
if (isReversal) {
createDebitJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount);
} else {
createCreditJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount);
}
}
// TODO: Vishwas Temporary validation to be removed before moving to
// release branch
if (totalAmount.compareTo(totalCreditedAmount) != 0) { throw new PlatformDataIntegrityException(
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
"Meltdown in advanced accounting...sum of all charges is not equal to the fee charge for a transaction",
totalCreditedAmount, totalAmount); }
}
private void createCreditJournalEntryOrReversalForLoan(final Office office, final int accountMappingTypeId, final Long loanProductId,
final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount,
final Boolean isReversal) {
@@ -363,6 +428,30 @@ public class AccountingProcessorHelper {
accountMapping = paymentChannelSpecificAccountMapping;
}
}
return accountMapping.getGlAccount();
}
private GLAccount getLinkedGLAccountForLoanCharges(final Long loanProductId, final int accountMappingTypeId, final Long chargeId) {
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
PortfolioProductType.LOAN.getValue(), accountMappingTypeId);
/*****
* Get more specific mappings for Charges and penalties (based on the
* actual charge /penalty coupled with the loan product). Note the
* income from fees and income from penalties placeholder ID would be
* the same for both cash and accrual based accounts
*****/
// Vishwas TODO: remove this condition as it should always be true
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()
|| accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()) {
ProductToGLAccountMapping chargeSpecificIncomeAccountMapping = this.accountMappingRepository
.findByProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(loanProductId, PortfolioProductType.LOAN.getValue(),
accountMappingTypeId, chargeId);
if (chargeSpecificIncomeAccountMapping != null) {
accountMapping = chargeSpecificIncomeAccountMapping;
}
}
return accountMapping.getGlAccount();
}
@@ -134,14 +134,15 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(feesAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId,
loanId, transactionId, transactionDate, feesAmount, isReversal);
helper.createCreditJournalEntryOrReversalForLoanCharges(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(),
loanProductId, loanId, transactionId, transactionDate, feesAmount, isReversal, loanTransactionDTO.getFeePayments());
}
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId,
paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal);
helper.createCreditJournalEntryOrReversalForLoanCharges(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
loanProductId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal,
loanTransactionDTO.getPenaltyPayments());
}
/*** create a single debit entry (or reversal) for the entire amount **/
@@ -0,0 +1,20 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.producttoaccountmapping.data;
public class ChargeToGLAccountMapper {
@SuppressWarnings("unused")
private final long chargeId;
@SuppressWarnings("unused")
private final long incomeAccountId;
public ChargeToGLAccountMapper(long chargeId, long incomeAccountId) {
this.chargeId = chargeId;
this.incomeAccountId = incomeAccountId;
}
}
@@ -15,6 +15,7 @@ import javax.persistence.UniqueConstraint;
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@@ -33,6 +34,10 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
@JoinColumn(name = "payment_type", nullable = true)
private CodeValue paymentType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "charge_id", nullable = true)
private Charge charge;
@Column(name = "product_type", nullable = false)
private int productType;
@@ -49,16 +54,27 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
}
public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType, final int financialAccountType) {
this(glAccount, productId, productType, financialAccountType, null);
this(glAccount, productId, productType, financialAccountType, null, null);
}
public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType,
final int financialAccountType, final Charge charge) {
this(glAccount, productId, productType, financialAccountType, null, charge);
}
public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType,
final int financialAccountType, final CodeValue paymentType) {
this(glAccount, productId, productType, financialAccountType, paymentType, null);
}
private ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType,
final int financialAccountType, final CodeValue paymentType, final Charge charge) {
this.glAccount = glAccount;
this.productId = productId;
this.productType = productType;
this.financialAccountType = financialAccountType;
this.paymentType = paymentType;
this.charge = charge;
}
public GLAccount getGlAccount() {
@@ -101,4 +117,12 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
this.paymentType = paymentType;
}
public Charge getCharge() {
return this.charge;
}
public void setCharge(Charge charge) {
this.charge = charge;
}
}
@@ -18,7 +18,10 @@ public interface ProductToGLAccountMappingRepository extends JpaRepository<Produ
ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(Long productId, int productType,
int financialAccountType, Long paymentType);
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL")
ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(Long productId, int productType,
int financialAccountType, Long chargeId);
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL")
ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType,
@Param("financialAccountType") int financialAccountType);
@@ -27,5 +30,15 @@ public interface ProductToGLAccountMappingRepository extends JpaRepository<Produ
List<ProductToGLAccountMapping> findAllPaymentTypeToFundSourceMappings(@Param("productId") Long productId,
@Param("productType") int productType);
/*** The financial Account Type for income from interest will always be 4 ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=4 and mapping.charge is not NULL")
List<ProductToGLAccountMapping> findAllFeeToIncomeAccountMappings(@Param("productId") Long productId,
@Param("productType") int productType);
/*** The financial Account Type for income from interest will always be 5 ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=5 and mapping.charge is not NULL")
List<ProductToGLAccountMapping> findAllPenaltyToIncomeAccountMappings(@Param("productId") Long productId,
@Param("productType") int productType);
List<ProductToGLAccountMapping> findByProductIdAndProductType(Long productId, int productType);
}
@@ -19,6 +19,7 @@ import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAc
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -30,8 +31,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
@Autowired
public LoanProductToGLAccountMappingHelper(final GLAccountRepository glAccountRepository,
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper);
final CodeValueRepositoryWrapper codeValueRepositoryWrapper, final ChargeRepositoryWrapper chargeRepositoryWrapper) {
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper, chargeRepositoryWrapper);
}
/*** Set of abstractions for saving Loan Products to GL Account Mappings ***/
@@ -82,6 +83,20 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
updatePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.LOAN);
}
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
final Map<String, Object> changes) {
// save both fee and penalty charges
saveChargesToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, true);
saveChargesToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, false);
}
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
final Map<String, Object> changes) {
// update both fee and penalty charges
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, true);
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, false);
}
public Map<String, Object> populateChangesForNewLoanProductToGLAccountMappingCreation(final JsonElement element,
final AccountingRuleType accountingRuleType) {
final Map<String, Object> changes = new HashMap<String, Object>();
@@ -26,6 +26,8 @@ import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -41,15 +43,17 @@ public class ProductToGLAccountMappingHelper {
protected final ProductToGLAccountMappingRepository accountMappingRepository;
protected final FromJsonHelper fromApiJsonHelper;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
private final ChargeRepositoryWrapper chargeRepositoryWrapper;
@Autowired
public ProductToGLAccountMappingHelper(final GLAccountRepository glAccountRepository,
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
final CodeValueRepositoryWrapper codeValueRepositoryWrapper, final ChargeRepositoryWrapper chargeRepositoryWrapper) {
this.accountRepository = glAccountRepository;
this.accountMappingRepository = glAccountMappingRepository;
this.fromApiJsonHelper = fromApiJsonHelper;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
this.chargeRepositoryWrapper = chargeRepositoryWrapper;
}
@@ -110,6 +114,128 @@ public class ProductToGLAccountMappingHelper {
}
}
/**
* Saves the Charge to Income account mappings for a particular
* product/product type (also populates the changes array if passed in)
*
* @param command
* @param element
* @param productId
* @param changes
*/
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
Map<String, Object> changes, final PortfolioProductType portfolioProductType, final boolean isPenalty) {
String arrayName;
if (isPenalty) {
arrayName = LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
} else {
arrayName = LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue();
}
JsonArray chargeToIncomeAccountMappingArray = fromApiJsonHelper.extractJsonArrayNamed(arrayName, element);
if (chargeToIncomeAccountMappingArray != null) {
if (changes != null) {
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue()));
}
for (int i = 0; i < chargeToIncomeAccountMappingArray.size(); i++) {
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
final Long chargeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.CHARGE_ID.getValue()).getAsLong();
final Long incomeAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue()).getAsLong();
saveChargeToFundSourceMapping(productId, chargeId, incomeAccountId, portfolioProductType, isPenalty);
}
}
}
/**
* @param command
* @param element
* @param productId
* @param changes
*/
public void updateChargeToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
Map<String, Object> changes, final PortfolioProductType portfolioProductType, boolean isPenalty) {
// find all existing payment Channel to Fund source Mappings
List<ProductToGLAccountMapping> existingChargeToIncomeAccountMappings;
String arrayFragmentName;
if (isPenalty) {
existingChargeToIncomeAccountMappings = accountMappingRepository.findAllPenaltyToIncomeAccountMappings(productId,
portfolioProductType.getValue());
arrayFragmentName = LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
} else {
existingChargeToIncomeAccountMappings = accountMappingRepository.findAllFeeToIncomeAccountMappings(productId,
portfolioProductType.getValue());
arrayFragmentName = LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue();
}
JsonArray chargeToIncomeAccountMappingArray = fromApiJsonHelper.extractJsonArrayNamed(arrayFragmentName, element);
/**
* Variable stores a map representation of charges (key) and their
* associated income Id's (value) extracted from the passed in
* Jsoncommand
**/
Map<Long, Long> inputChargeToIncomeAccountMap = new HashMap<Long, Long>();
/***
* Variable stores all charges which have already been mapped to Income
* Accounts in the system
**/
Set<Long> existingCharges = new HashSet<Long>();
if (chargeToIncomeAccountMappingArray != null) {
if (changes != null) {
changes.put(arrayFragmentName, command.jsonFragment(arrayFragmentName));
}
for (int i = 0; i < chargeToIncomeAccountMappingArray.size(); i++) {
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
final Long chargeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.CHARGE_ID.getValue()).getAsLong();
final Long incomeAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue()).getAsLong();
inputChargeToIncomeAccountMap.put(chargeId, incomeAccountId);
}
// If input map is empty, delete all existing mappings
if (inputChargeToIncomeAccountMap.size() == 0) {
accountMappingRepository.deleteInBatch(existingChargeToIncomeAccountMappings);
}/**
* Else, <br/>
* update existing mappings OR <br/>
* delete old mappings (which are already present, but not passed in
* as a part of Jsoncommand)<br/>
* Create new mappings for charges that are passed in as a part of
* the Jsoncommand but not already present
*
**/
else {
for (ProductToGLAccountMapping chargeToIncomeAccountMapping : existingChargeToIncomeAccountMappings) {
Long currentCharge = chargeToIncomeAccountMapping.getCharge().getId();
existingCharges.add(currentCharge);
// update existing mappings (if required)
if (inputChargeToIncomeAccountMap.containsKey(currentCharge)) {
Long newGLAccountId = inputChargeToIncomeAccountMap.get(currentCharge);
if (newGLAccountId != chargeToIncomeAccountMapping.getGlAccount().getId()) {
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue(),
GLAccountType.INCOME, newGLAccountId);
chargeToIncomeAccountMapping.setGlAccount(glAccount);
accountMappingRepository.save(chargeToIncomeAccountMapping);
}
}// deleted payment type
else {
accountMappingRepository.delete(chargeToIncomeAccountMapping);
}
}
// create new mappings
Set<Long> incomingCharges = inputChargeToIncomeAccountMap.keySet();
incomingCharges.removeAll(existingCharges);
// incomingPaymentTypes now only contains the newly added
// payment Type mappings
for (Long newCharge : incomingCharges) {
Long newGLAccountId = inputChargeToIncomeAccountMap.get(newCharge);
saveChargeToFundSourceMapping(productId, newCharge, newGLAccountId, portfolioProductType, isPenalty);
}
}
}
}
/**
* @param command
* @param element
@@ -204,6 +330,34 @@ public class ProductToGLAccountMappingHelper {
this.accountMappingRepository.save(accountMapping);
}
/**
* @param productId
* @param jsonObject
*/
private void saveChargeToFundSourceMapping(final Long productId, final Long chargeId, final Long incomeAccountId,
final PortfolioProductType portfolioProductType, final boolean isPenalty) {
Charge charge = chargeRepositoryWrapper.findOneWithNotFoundDetection(chargeId);
// TODO Vishwas: Need to validate if given charge is fee or Penalty
// based on input condition
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue(),
GLAccountType.INCOME, incomeAccountId);
/**
* Both CASH and Accrual placeholders have the same value for income
* from Interest and penalties
**/
CASH_ACCOUNTS_FOR_LOAN placeHolderAccountType;
if (isPenalty) {
placeHolderAccountType = CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES;
} else {
placeHolderAccountType = CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES;
}
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
portfolioProductType.getValue(), placeHolderAccountType.getValue(), charge);
this.accountMappingRepository.save(accountMapping);
}
/**
* Fetches account with a particular Id and throws and Exception it is not
* of the expected Account Category ('ASSET','liability' etc)
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.producttoaccountmapping.service;
import java.util.List;
import java.util.Map;
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
public interface ProductToGLAccountMappingReadPlatformService {
@@ -16,7 +17,12 @@ public interface ProductToGLAccountMappingReadPlatformService {
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(final Long loanProductId);
public List<ChargeToGLAccountMapper> fetchFeeToIncomeAccountMappingsForLoanProduct(final Long loanProductId);
public List<ChargeToGLAccountMapper> fetchPenaltyToIncomeAccountMappingsForLoanProduct(final Long loanProductId);
public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(final Long savingsProductId, final Integer accountingType);
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForSavingsProduct(final Long savingsProductId);
}
@@ -18,8 +18,10 @@ import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
import org.mifosplatform.accounting.common.AccountingRuleType;
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -39,8 +41,11 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
private static final class ProductToGLAccountMappingMapper implements RowMapper<Map<String, Object>> {
public String schema() {
return " id as id, gl_account_id as glAccountId,product_id as productId,product_type as productType,financial_account_type as financialAccountType,"
+ " payment_type as paymentTypeId from acc_product_mapping " + " where product_type= ? ";
return " mapping.id as id, mapping.gl_account_id as glAccountId, mapping.product_id as productId, "
+ " mapping.product_type as productType,mapping.financial_account_type as financialAccountType, "
+ " mapping.payment_type as paymentTypeId, mapping.charge_id as chargeId, charge.is_penalty as penalty "
+ " from acc_product_mapping mapping left join m_charge charge on mapping.charge_id=charge.id "
+ " where mapping.product_type= ? ";
}
@Override
@@ -49,7 +54,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
final Long id = rs.getLong("id");
final Long glAccountId = rs.getLong("glAccountId");
final Long productId = rs.getLong("productId");
final Long paymentTypeId = rs.getLong("paymentTypeId");
final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentTypeId");
final Long chargeId = rs.getLong("chargeId");
final Integer productType = rs.getInt("productType");
final Integer financialAccountType = rs.getInt("financialAccountType");
@@ -60,6 +66,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
loanProductToGLAccountMap.put("productType", productType);
loanProductToGLAccountMap.put("financialAccountType", financialAccountType);
loanProductToGLAccountMap.put("paymentTypeId", paymentTypeId);
loanProductToGLAccountMap.put("chargeId", chargeId);
return loanProductToGLAccountMap;
}
@@ -71,7 +78,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
final Map<String, Object> accountMappingDetails = new LinkedHashMap<String, Object>(8);
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null ";
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null and mapping.charge_id is null";
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] {
PortfolioProductType.LOAN.getValue(), loanProductId });
@@ -138,7 +145,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
final Map<String, Object> accountMappingDetails = new LinkedHashMap<String, Object>(8);
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null ";
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null and mapping.charge_id is null ";
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] {
PortfolioProductType.SAVING.getValue(), savingsProductId });
@@ -168,14 +175,12 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
@Override
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(Long loanProductId) {
List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers = null;
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.LOAN, loanProductId, paymentTypeToGLAccountMappers);
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.LOAN, loanProductId);
}
@Override
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForSavingsProduct(Long savingsProductId) {
List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers = null;
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.SAVING, savingsProductId, paymentTypeToGLAccountMappers);
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.SAVING, savingsProductId);
}
/**
@@ -184,13 +189,14 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
* @return
*/
private List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappings(PortfolioProductType portfolioProductType,
Long loanProductId, List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers) {
Long loanProductId) {
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is not null";
final List<Map<String, Object>> paymentTypeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm, new Object[] {
portfolioProductType.getValue(), loanProductId });
List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers = null;
for (final Map<String, Object> productToGLAccountMap : paymentTypeToFundSourceMappingsList) {
if (paymentTypeToGLAccountMappers == null) {
paymentTypeToGLAccountMappers = new ArrayList<PaymentTypeToGLAccountMapper>();
@@ -203,4 +209,38 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
return paymentTypeToGLAccountMappers;
}
@Override
public List<ChargeToGLAccountMapper> fetchFeeToIncomeAccountMappingsForLoanProduct(Long loanProductId) {
return fetchChargeToIncomeAccountMappings(PortfolioProductType.LOAN, loanProductId, false);
}
@Override
public List<ChargeToGLAccountMapper> fetchPenaltyToIncomeAccountMappingsForLoanProduct(Long loanProductId) {
return fetchChargeToIncomeAccountMappings(PortfolioProductType.LOAN, loanProductId, true);
}
private List<ChargeToGLAccountMapper> fetchChargeToIncomeAccountMappings(PortfolioProductType portfolioProductType, Long loanProductId,
boolean penalty) {
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
String sql = "select " + rm.schema() + " and product_id = ? and mapping.charge_id is not null and charge.is_penalty=";
if (penalty) {
sql = sql + " 1";
} else {
sql = sql + " 0";
}
final List<Map<String, Object>> chargeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm, new Object[] {
portfolioProductType.getValue(), loanProductId });
List<ChargeToGLAccountMapper> chargeToGLAccountMappers = null;
for (final Map<String, Object> chargeToIncomeAccountMap : chargeToFundSourceMappingsList) {
if (chargeToGLAccountMappers == null) {
chargeToGLAccountMappers = new ArrayList<ChargeToGLAccountMapper>();
}
final Long glAccountId = (Long) chargeToIncomeAccountMap.get("glAccountId");
final Long chargeId = (Long) chargeToIncomeAccountMap.get("chargeId");
ChargeToGLAccountMapper chargeToGLAccountMapper = new ChargeToGLAccountMapper(chargeId, glAccountId);
chargeToGLAccountMappers.add(chargeToGLAccountMapper);
}
return chargeToGLAccountMappers;
}
}
@@ -81,6 +81,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
// advanced accounting mappings
loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null);
break;
case ACCRUAL_BASED:
@@ -119,6 +120,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
// advanced accounting mappings
loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null);
break;
}
}
@@ -18,6 +18,7 @@ import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAc
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -29,8 +30,8 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
@Autowired
public SavingsProductToGLAccountMappingHelper(GLAccountRepository glAccountRepository,
ProductToGLAccountMappingRepository glAccountMappingRepository, FromJsonHelper fromApiJsonHelper,
CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper);
CodeValueRepositoryWrapper codeValueRepositoryWrapper, ChargeRepositoryWrapper chargeRepositoryWrapper) {
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper, chargeRepositoryWrapper);
}
/*** Set of abstractions for saving Saving Products to GL Account Mappings ***/
@@ -1374,8 +1374,8 @@ public class Loan extends AbstractPersistable<Long> {
if (charge.isDueAtDisbursement()) {
charge.markAsFullyPaid();
// Add "Loan Charge Paid By" details to this transaction
LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(disbursementTransaction, charge, charge.amount());
disbursementTransaction.getLoanChargesPaid().add(loanChargePaidBy);
LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, charge.amount());
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
} else {
handleChargeAppliedTransaction(charge, disbursedOn);
}
@@ -487,6 +487,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
return this.charge.getCurrencyCode();
}
public Charge getCharge() {
return this.charge;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) { return false; }
@@ -6,9 +6,11 @@
package org.mifosplatform.portfolio.loanaccount.domain;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -374,6 +376,20 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
}
if (!this.loanChargesPaid.isEmpty()) {
final List<Map<String, Object>> loanChargesPaidData = new ArrayList<Map<String, Object>>();
for (LoanChargePaidBy chargePaidBy : this.loanChargesPaid) {
final Map<String, Object> loanChargePaidData = new LinkedHashMap<String, Object>();
loanChargePaidData.put("chargeId", chargePaidBy.getLoanCharge().getCharge().getId());
loanChargePaidData.put("isPenalty", chargePaidBy.getLoanCharge().getCharge().isPenalty());
loanChargePaidData.put("loanChargeId", chargePaidBy.getLoanCharge().getId());
loanChargePaidData.put("amount", chargePaidBy.getAmount());
loanChargesPaidData.add(loanChargePaidData);
}
thisTransactionData.put("loanChargesPaid", loanChargesPaidData);
}
return thisTransactionData;
}
@@ -7,7 +7,6 @@ package org.mifosplatform.portfolio.loanproduct.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -26,6 +25,7 @@ import javax.ws.rs.core.UriInfo;
import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService;
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
import org.mifosplatform.commands.domain.CommandWrapper;
@@ -143,7 +143,7 @@ public class LoanProductsApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails();
loanProduct = handleTemplate(loanProduct, new HashMap<String, Object>(), null);
loanProduct = handleTemplate(loanProduct);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
@@ -163,16 +163,21 @@ public class LoanProductsApiResource {
Map<String, Object> accountingMappings = null;
Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
Collection<ChargeToGLAccountMapper> feeToGLAccountMappings = null;
Collection<ChargeToGLAccountMapper> penaltyToGLAccountMappings = null;
if (loanProduct.hasAccountingEnabled()) {
accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct
.accountingRuleType().getId().intValue());
paymentChannelToFundSourceMappings = accountMappingReadPlatformService
.fetchPaymentTypeToFundSourceMappingsForLoanProduct(productId);
loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings);
feeToGLAccountMappings = accountMappingReadPlatformService.fetchFeeToIncomeAccountMappingsForLoanProduct(productId);
penaltyToGLAccountMappings = accountMappingReadPlatformService.fetchFeeToIncomeAccountMappingsForLoanProduct(productId);
loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings,
feeToGLAccountMappings, penaltyToGLAccountMappings);
}
if (settings.isTemplate()) {
loanProduct = handleTemplate(loanProduct, accountingMappings, paymentChannelToFundSourceMappings);
loanProduct = handleTemplate(loanProduct);
}
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
}
@@ -191,8 +196,7 @@ public class LoanProductsApiResource {
return this.toApiJsonSerializer.serialize(result);
}
private LoanProductData handleTemplate(final LoanProductData productData, final Map<String, Object> accountingMappings,
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings) {
private LoanProductData handleTemplate(final LoanProductData productData) {
final boolean feeChargesOnly = true;
Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
@@ -225,7 +229,6 @@ public class LoanProductsApiResource {
return new LoanProductData(productData, chargeOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings,
paymentChannelToFundSourceMappings);
fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions);
}
}
@@ -14,6 +14,7 @@ import java.util.Map;
import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.common.AccountingRuleType;
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
@@ -68,11 +69,11 @@ public class LoanProductData {
private final Collection<ChargeData> charges;
// accounting
private final EnumOptionData accountingRule;
@SuppressWarnings("unused")
private final Map<String, Object> accountingMappings;
@SuppressWarnings("unused")
private final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
private EnumOptionData accountingRule;
private Map<String, Object> accountingMappings;
private Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
private Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings;
private Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
// template related
private final Collection<FundData> fundOptions;
@@ -212,13 +213,14 @@ public class LoanProductData {
}
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings) {
return new LoanProductData(productData, productData.chargeOptions, productData.paymentTypeOptions, productData.currencyOptions,
productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions,
productData.repaymentFrequencyTypeOptions, productData.interestRateFrequencyTypeOptions, productData.fundOptions,
productData.transactionProcessingStrategyOptions, productData.accountingMappingOptions, productData.accountingRuleOptions,
accountingMappings, paymentChannelToFundSourceMappings);
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
final Collection<ChargeToGLAccountMapper> feeToGLAccountMappings,
final Collection<ChargeToGLAccountMapper> penaltyToGLAccountMappings) {
productData.accountingMappings = accountingMappings;
productData.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings;
productData.feeToIncomeAccountMappings = feeToGLAccountMappings;
productData.penaltyToIncomeAccountMappings = penaltyToGLAccountMappings;
return productData;
}
public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency,
@@ -277,6 +279,8 @@ public class LoanProductData {
this.accountingRuleOptions = null;
this.accountingMappings = null;
this.paymentChannelToFundSourceMappings = null;
this.feeToIncomeAccountMappings = null;
this.penaltyToIncomeAccountMappings = null;
}
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
@@ -285,8 +289,7 @@ public class LoanProductData {
final List<EnumOptionData> interestCalculationPeriodTypeOptions, final List<EnumOptionData> repaymentFrequencyTypeOptions,
final List<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<FundData> fundOptions,
final Collection<TransactionProcessingStrategyData> transactionStrategyOptions,
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings) {
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions) {
this.id = productData.id;
this.name = productData.name;
this.description = productData.description;
@@ -313,6 +316,10 @@ public class LoanProductData {
this.charges = nullIfEmpty(productData.charges());
this.accountingRule = productData.accountingRule;
this.accountingMappings = productData.accountingMappings;
this.paymentChannelToFundSourceMappings = productData.paymentChannelToFundSourceMappings;
this.feeToIncomeAccountMappings = productData.feeToIncomeAccountMappings;
this.penaltyToIncomeAccountMappings = productData.penaltyToIncomeAccountMappings;
this.chargeOptions = chargeOptions;
this.paymentTypeOptions = paymentTypeOptions;
@@ -344,13 +351,7 @@ public class LoanProductData {
this.accountingMappingOptions = accountingMappingOptions;
this.accountingRuleOptions = accountingRuleOptions;
if (accountingMappings == null || accountingMappings.isEmpty()) {
this.accountingMappings = null;
} else {
this.accountingMappings = accountingMappings;
}
this.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings;
}
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {