optionally account different fees and penalties under different heads
This commit is contained in:
@@ -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`);
|
||||
+2
-1
@@ -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;
|
||||
|
||||
|
||||
Executable
+29
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+17
-1
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+90
-1
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -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 **/
|
||||
|
||||
+20
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+25
-1
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-1
@@ -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);
|
||||
}
|
||||
|
||||
+17
-2
@@ -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>();
|
||||
|
||||
+155
-1
@@ -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)
|
||||
|
||||
+6
@@ -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);
|
||||
|
||||
}
|
||||
+50
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
+2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -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 ***/
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
+4
@@ -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; }
|
||||
|
||||
+16
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -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);
|
||||
}
|
||||
}
|
||||
+22
-21
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user