accounting integration for savings and refactoring
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
/*add accounting type field to savings product*/
|
||||
ALTER TABLE `m_savings_product`
|
||||
ADD COLUMN `accounting_type` SMALLINT(5) NOT NULL AFTER `lockin_period_frequency_enum`;
|
||||
|
||||
/*update existing savings products to have "No" accounting*/
|
||||
update m_savings_product set accounting_type=1;
|
||||
|
||||
/*track payment details for savings transactions*/
|
||||
ALTER TABLE `m_savings_account_transaction`
|
||||
ADD COLUMN `payment_detail_id` BIGINT(20) NULL DEFAULT NULL AFTER `savings_account_id`,
|
||||
ADD CONSTRAINT `FK_m_savings_account_transaction_m_payment_detail` FOREIGN KEY (`payment_detail_id`) REFERENCES `m_payment_detail` (`id`);
|
||||
|
||||
+57
@@ -103,6 +103,63 @@ public class AccountingConstants {
|
||||
}
|
||||
}
|
||||
|
||||
/*** Accounting placeholders for cash based accounting for loan products ***/
|
||||
public static enum CASH_ACCOUNTS_FOR_SAVINGS {
|
||||
SAVINGS_REFERENCE(1), SAVINGS_CONTROL(2), INTEREST_ON_SAVINGS(3), INCOME_FROM_FEES(4);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
private CASH_ACCOUNTS_FOR_SAVINGS(final Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
private static final Map<Integer, CASH_ACCOUNTS_FOR_SAVINGS> intToEnumMap = new HashMap<Integer, CASH_ACCOUNTS_FOR_SAVINGS>();
|
||||
static {
|
||||
for (final CASH_ACCOUNTS_FOR_SAVINGS type : CASH_ACCOUNTS_FOR_SAVINGS.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static CASH_ACCOUNTS_FOR_SAVINGS fromInt(final int i) {
|
||||
final CASH_ACCOUNTS_FOR_SAVINGS type = intToEnumMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Enum of all accounting related input parameter names used while
|
||||
* creating/updating a savings product
|
||||
***/
|
||||
public static enum SAVINGS_PRODUCT_ACCOUNTING_PARAMS {
|
||||
SAVINGS_REFERENCE("savingsReferenceAccountId"), SAVINGS_CONTROL("savingsControlAccountId"), INCOME_FROM_FEES(
|
||||
"incomeFromFeeAccountId"), INTEREST_ON_SAVINGS("interestOnSavingsAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING(
|
||||
"paymentChannelToFundSourceMappings"), PAYMENT_TYPE("paymentTypeId"), FUND_SOURCE("fundSourceAccountId");
|
||||
|
||||
private final String value;
|
||||
|
||||
private SAVINGS_PRODUCT_ACCOUNTING_PARAMS(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String ASSESTS_TAG_OPTION_CODE_NAME = "AssetAccountTags";
|
||||
public static final String LIABILITIES_TAG_OPTION_CODE_NAME = "LiabilityAccountTags";
|
||||
public static final String EQUITY_TAG_OPTION_CODE_NAME = "EquityAccountTags";
|
||||
|
||||
+9
@@ -6,7 +6,9 @@
|
||||
package org.mifosplatform.accounting.common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public interface AccountingDropdownReadPlatformService {
|
||||
@@ -16,4 +18,11 @@ public interface AccountingDropdownReadPlatformService {
|
||||
public List<EnumOptionData> retrieveGLAccountUsageOptions();
|
||||
|
||||
public List<EnumOptionData> retrieveJournalEntryTypeOptions();
|
||||
|
||||
public List<EnumOptionData> retrieveAccountingRuleTypeOptions();
|
||||
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForLoanProducts();
|
||||
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForSavingsProducts();
|
||||
|
||||
}
|
||||
+52
@@ -5,17 +5,29 @@
|
||||
*/
|
||||
package org.mifosplatform.accounting.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountUsage;
|
||||
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AccountingDropdownReadPlatformServiceImpl implements AccountingDropdownReadPlatformService {
|
||||
|
||||
private final GLAccountReadPlatformService accountReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public AccountingDropdownReadPlatformServiceImpl(final GLAccountReadPlatformService accountReadPlatformService) {
|
||||
this.accountReadPlatformService = accountReadPlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveGLAccountTypeOptions() {
|
||||
return AccountingEnumerations.gLAccountType(GLAccountType.values());
|
||||
@@ -31,4 +43,44 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop
|
||||
return AccountingEnumerations.journalEntryTypes(JournalEntryType.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveAccountingRuleTypeOptions() {
|
||||
return AccountingEnumerations.accountingRuleTypes(AccountingRuleType.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForLoanProducts() {
|
||||
Map<String, List<GLAccountData>> accountOptions = new HashMap<String, List<GLAccountData>>();
|
||||
List<GLAccountData> assetAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
if (assetAccountOptions.isEmpty()) {
|
||||
assetAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("assetAccountOptions", assetAccountOptions);
|
||||
|
||||
List<GLAccountData> incomeAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
|
||||
if (incomeAccountOptions.isEmpty()) {
|
||||
incomeAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
|
||||
|
||||
List<GLAccountData> expenseAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
if (expenseAccountOptions.isEmpty()) {
|
||||
expenseAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
return accountOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForSavingsProducts() {
|
||||
Map<String, List<GLAccountData>> accountOptions = retrieveAccountMappingOptionsForLoanProducts();
|
||||
List<GLAccountData> liabilityAccountOptions = accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.LIABILITY);
|
||||
if (liabilityAccountOptions.isEmpty()) {
|
||||
liabilityAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("liabilityAccountOptions", liabilityAccountOptions);
|
||||
return accountOptions;
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -80,4 +80,21 @@ public class AccountingEnumerations {
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData accountingRuleType(final int id) {
|
||||
return accountingRuleType(AccountingRuleType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData accountingRuleType(final AccountingRuleType type) {
|
||||
EnumOptionData optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), type.toString());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> accountingRuleTypes(final AccountingRuleType[] accountingRuleTypes) {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<EnumOptionData>();
|
||||
for (final AccountingRuleType accountingRuleType : accountingRuleTypes) {
|
||||
optionDatas.add(accountingRuleType(accountingRuleType));
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* 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.portfolio.loanproduct.domain;
|
||||
package org.mifosplatform.accounting.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
+18
-17
@@ -30,10 +30,10 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@Table(name = "acc_gl_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "gl_code" }, name = "acc_gl_code") })
|
||||
public class GLAccount extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "parent_id")
|
||||
private GLAccount parent;
|
||||
|
||||
|
||||
@Column(name = "hierarchy", nullable = true, length = 50)
|
||||
private String hierarchy;
|
||||
|
||||
@@ -61,8 +61,8 @@ public class GLAccount extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "description", nullable = true, length = 500)
|
||||
private String description;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "tag_id")
|
||||
private CodeValue tagId;
|
||||
|
||||
@@ -105,7 +105,8 @@ public class GLAccount extends AbstractPersistable<Long> {
|
||||
handlePropertyUpdate(command, actualChanges, GLAccountJsonInputParams.PARENT_ID.getValue(), 0L);
|
||||
handlePropertyUpdate(command, actualChanges, GLAccountJsonInputParams.TYPE.getValue(), this.type, true);
|
||||
handlePropertyUpdate(command, actualChanges, GLAccountJsonInputParams.USAGE.getValue(), this.usage, true);
|
||||
handlePropertyUpdate(command, actualChanges, GLAccountJsonInputParams.TAGID.getValue(), this.tagId==null?0L:this.tagId.getId());
|
||||
handlePropertyUpdate(command, actualChanges, GLAccountJsonInputParams.TAGID.getValue(),
|
||||
this.tagId == null ? 0L : this.tagId.getId());
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -207,7 +208,7 @@ public class GLAccount extends AbstractPersistable<Long> {
|
||||
public Integer getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
|
||||
public void generateHierarchy() {
|
||||
|
||||
if (parent != null) {
|
||||
@@ -216,21 +217,21 @@ public class GLAccount extends AbstractPersistable<Long> {
|
||||
this.hierarchy = ".";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String hierarchyOf(final Long id) {
|
||||
return this.hierarchy + id.toString() + ".";
|
||||
}
|
||||
|
||||
public boolean isDetailAccount() {
|
||||
return GLAccountUsage.DETAIL.getValue().equals(this.usage);
|
||||
}
|
||||
public boolean isDetailAccount() {
|
||||
return GLAccountUsage.DETAIL.getValue().equals(this.usage);
|
||||
}
|
||||
|
||||
public void updateTagId(CodeValue tagID) {
|
||||
this.tagId = tagID;
|
||||
}
|
||||
public void updateTagId(CodeValue tagID) {
|
||||
this.tagId = tagID;
|
||||
}
|
||||
|
||||
public void updateParentAccount(GLAccount parentAccount) {
|
||||
this.parent=parentAccount;
|
||||
this.generateHierarchy();
|
||||
}
|
||||
public void updateParentAccount(GLAccount parentAccount) {
|
||||
this.parent = parentAccount;
|
||||
this.generateHierarchy();
|
||||
}
|
||||
}
|
||||
+15
-15
@@ -66,24 +66,24 @@ public enum GLAccountType {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public boolean isAssetType() {
|
||||
return this.value.equals(GLAccountType.ASSET.getValue());
|
||||
}
|
||||
public boolean isAssetType() {
|
||||
return this.value.equals(GLAccountType.ASSET.getValue());
|
||||
}
|
||||
|
||||
public boolean isLiabilityType() {
|
||||
return this.value.equals(GLAccountType.LIABILITY.getValue());
|
||||
}
|
||||
public boolean isLiabilityType() {
|
||||
return this.value.equals(GLAccountType.LIABILITY.getValue());
|
||||
}
|
||||
|
||||
public boolean isEquityType() {
|
||||
return this.value.equals(GLAccountType.EQUITY.getValue());
|
||||
}
|
||||
public boolean isEquityType() {
|
||||
return this.value.equals(GLAccountType.EQUITY.getValue());
|
||||
}
|
||||
|
||||
public boolean isIncomeType() {
|
||||
return this.value.equals(GLAccountType.INCOME.getValue());
|
||||
}
|
||||
public boolean isIncomeType() {
|
||||
return this.value.equals(GLAccountType.INCOME.getValue());
|
||||
}
|
||||
|
||||
public boolean isExpenseType() {
|
||||
return this.value.equals(GLAccountType.EXPENSE.getValue());
|
||||
}
|
||||
public boolean isExpenseType() {
|
||||
return this.value.equals(GLAccountType.EXPENSE.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.journalentry.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SavingsDTO {
|
||||
|
||||
private Long savingsId;
|
||||
private Long savingsProductId;
|
||||
private Long officeId;
|
||||
private boolean cashBasedAccountingEnabled;
|
||||
private boolean accrualBasedAccountingEnabled;
|
||||
private List<SavingsTransactionDTO> newSavingsTransactions;
|
||||
|
||||
public SavingsDTO(final Long savingsId, final Long savingsProductId, final Long officeId, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled, final List<SavingsTransactionDTO> newSavingsTransactions) {
|
||||
this.savingsId = savingsId;
|
||||
this.savingsProductId = savingsProductId;
|
||||
this.officeId = officeId;
|
||||
this.cashBasedAccountingEnabled = cashBasedAccountingEnabled;
|
||||
this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled;
|
||||
this.newSavingsTransactions = newSavingsTransactions;
|
||||
}
|
||||
|
||||
public Long getSavingsId() {
|
||||
return this.savingsId;
|
||||
}
|
||||
|
||||
public void setSavingsId(Long savingsId) {
|
||||
this.savingsId = savingsId;
|
||||
}
|
||||
|
||||
public Long getSavingsProductId() {
|
||||
return this.savingsProductId;
|
||||
}
|
||||
|
||||
public void setSavingsProductId(Long savingsProductId) {
|
||||
this.savingsProductId = savingsProductId;
|
||||
}
|
||||
|
||||
public Long getOfficeId() {
|
||||
return this.officeId;
|
||||
}
|
||||
|
||||
public void setOfficeId(Long officeId) {
|
||||
this.officeId = officeId;
|
||||
}
|
||||
|
||||
public boolean isCashBasedAccountingEnabled() {
|
||||
return this.cashBasedAccountingEnabled;
|
||||
}
|
||||
|
||||
public void setCashBasedAccountingEnabled(boolean cashBasedAccountingEnabled) {
|
||||
this.cashBasedAccountingEnabled = cashBasedAccountingEnabled;
|
||||
}
|
||||
|
||||
public boolean isAccrualBasedAccountingEnabled() {
|
||||
return this.accrualBasedAccountingEnabled;
|
||||
}
|
||||
|
||||
public void setAccrualBasedAccountingEnabled(boolean accrualBasedAccountingEnabled) {
|
||||
this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled;
|
||||
}
|
||||
|
||||
public List<SavingsTransactionDTO> getNewSavingsTransactions() {
|
||||
return this.newSavingsTransactions;
|
||||
}
|
||||
|
||||
public void setNewSavingsTransactions(List<SavingsTransactionDTO> newSavingsTransactions) {
|
||||
this.newSavingsTransactions = newSavingsTransactions;
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
|
||||
public class SavingsTransactionDTO {
|
||||
|
||||
private final String transactionId;
|
||||
private final Date transactionDate;
|
||||
private final Long paymentTypeId;
|
||||
private final SavingsAccountTransactionEnumData transactionType;
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
/*** Boolean values determines if the transaction is reversed ***/
|
||||
private final boolean reversed;
|
||||
|
||||
public SavingsTransactionDTO(final Long paymentTypeId, final String transactionId, final Date transactionDate,
|
||||
final SavingsAccountTransactionEnumData transactionType, final BigDecimal amount, final boolean reversed) {
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
this.amount = amount;
|
||||
this.reversed = reversed;
|
||||
this.transactionType = transactionType;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
public Date getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public Long getPaymentTypeId() {
|
||||
return this.paymentTypeId;
|
||||
}
|
||||
|
||||
public SavingsAccountTransactionEnumData getTransactionType() {
|
||||
return this.transactionType;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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.journalentry.service;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
|
||||
public interface AccountingProcessorForSavings {
|
||||
|
||||
void createJournalEntriesForSavings(SavingsDTO savingsDTO);
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.journalentry.service;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AccountingProcessorForSavingsFactory {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
public AccountingProcessorForSavingsFactory(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/***
|
||||
* Looks like overkill for now, but wanted to keep the savings side of
|
||||
* accounting identical to that of Loans (would we need an Accrual based
|
||||
* accounting in the future?)
|
||||
***/
|
||||
public AccountingProcessorForSavings determineProcessor(final SavingsDTO savingsDTO) {
|
||||
|
||||
AccountingProcessorForSavings accountingProcessorForSavings = null;
|
||||
|
||||
if (savingsDTO.isCashBasedAccountingEnabled()) {
|
||||
accountingProcessorForSavings = applicationContext.getBean("cashBasedAccountingProcessorForSavings",
|
||||
AccountingProcessorForSavings.class);
|
||||
}
|
||||
|
||||
return accountingProcessorForSavings;
|
||||
}
|
||||
|
||||
}
|
||||
+113
@@ -16,9 +16,12 @@ import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosureRepository;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
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.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntry;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
|
||||
@@ -30,6 +33,7 @@ import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAc
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -83,6 +87,35 @@ public class AccountingProcessorHelper {
|
||||
return new LoanDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newLoanTransactions);
|
||||
}
|
||||
|
||||
public SavingsDTO populateSavingsDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled) {
|
||||
final Long loanId = (Long) accountingBridgeData.get("savingsId");
|
||||
final Long loanProductId = (Long) accountingBridgeData.get("savingsProductId");
|
||||
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
||||
final List<SavingsTransactionDTO> newSavingsTransactions = new ArrayList<SavingsTransactionDTO>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> newTransactionsMap = (List<Map<String, Object>>) accountingBridgeData.get("newSavingsTransactions");
|
||||
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = ((LocalDate) map.get("date")).toDate();
|
||||
final SavingsAccountTransactionEnumData transactionType = (SavingsAccountTransactionEnumData) map.get("type");
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
final boolean reversed = (Boolean) map.get("reversed");
|
||||
final Long paymentTypeId = (Long) map.get("paymentTypeId");
|
||||
|
||||
final SavingsTransactionDTO transaction = new SavingsTransactionDTO(paymentTypeId, transactionId, transactionDate,
|
||||
transactionType, amount, reversed);
|
||||
|
||||
newSavingsTransactions.add(transaction);
|
||||
|
||||
}
|
||||
|
||||
return new SavingsDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled,
|
||||
newSavingsTransactions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a pair of related Debits and Credits for
|
||||
* Accrual Based accounting.
|
||||
@@ -118,6 +151,41 @@ public class AccountingProcessorHelper {
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a pair of related Debits and Credits for
|
||||
* Cash Based accounting.
|
||||
*
|
||||
* The target accounts for debits and credits are switched in case of a
|
||||
* reversal
|
||||
*
|
||||
* @param office
|
||||
* @param accountTypeToBeDebited
|
||||
* Enum of the placeholder GLAccount to be debited
|
||||
* @param accountTypeToBeCredited
|
||||
* Enum of the placeholder of the GLAccount to be credited
|
||||
* @param savingsProductId
|
||||
* @param paymentTypeId
|
||||
* @param loanId
|
||||
* @param transactionId
|
||||
* @param transactionDate
|
||||
* @param amount
|
||||
* @param isReversal
|
||||
*/
|
||||
public void createCashBasedJournalEntriesAndReversalsForSavings(final Office office,
|
||||
final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeDebited, final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeCredited,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||
final Date transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
int accountTypeToDebitId = accountTypeToBeDebited.getValue();
|
||||
int accountTypeToCreditId = accountTypeToBeCredited.getValue();
|
||||
// reverse debits and credits for reversals
|
||||
if (isReversal) {
|
||||
accountTypeToDebitId = accountTypeToBeCredited.getValue();
|
||||
accountTypeToCreditId = accountTypeToBeDebited.getValue();
|
||||
}
|
||||
createJournalEntriesForSavings(office, accountTypeToDebitId, accountTypeToCreditId, savingsProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a pair of related Debits and Credits for
|
||||
* Cash Based accounting.
|
||||
@@ -216,6 +284,15 @@ public class AccountingProcessorHelper {
|
||||
createCreditJournalEntryForLoan(office, creditAccount, loanId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
private void createJournalEntriesForSavings(final Office office, final int accountTypeToDebitId, final int accountTypeToCreditId,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId,
|
||||
final Date transactionDate, final BigDecimal amount) {
|
||||
GLAccount debitAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToDebitId, paymentTypeId);
|
||||
GLAccount creditAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToCreditId, paymentTypeId);
|
||||
createDebitJournalEntryForSavings(office, debitAccount, savingsId, transactionId, transactionDate, amount);
|
||||
createCreditJournalEntryForSavings(office, creditAccount, savingsId, transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryOrReversalForLoan(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) {
|
||||
@@ -246,6 +323,14 @@ public class AccountingProcessorHelper {
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForSavings(final Office office, final GLAccount account, final Long savingsId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.CREDIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryForLoan(final Office office, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
@@ -254,6 +339,14 @@ public class AccountingProcessorHelper {
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryForSavings(final Office office, final GLAccount account, final Long savingsId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
|
||||
PortfolioProductType.LOAN.getValue(), accountMappingTypeId);
|
||||
@@ -272,4 +365,24 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForSavingsProduct(final Long savingsProductId, final int accountMappingTypeId,
|
||||
final Long paymentTypeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId);
|
||||
/****
|
||||
* Get more specific mapping for FUND source accounts (based on payment
|
||||
* channels). Note that fund source placeholder ID would be same for
|
||||
* both cash and accrual accounts
|
||||
***/
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()) {
|
||||
ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId, paymentTypeId);
|
||||
if (paymentChannelSpecificAccountMapping != null) {
|
||||
accountMapping = paymentChannelSpecificAccountMapping;
|
||||
}
|
||||
}
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CashBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Autowired
|
||||
public CashBasedAccountingProcessorForSavings(final AccountingProcessorHelper accountingProcessorHelper) {
|
||||
this.helper = accountingProcessorHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(SavingsDTO savingsDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Office office = this.helper.getOfficeById(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final Date transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
|
||||
helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest
|
||||
* Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -17,4 +17,6 @@ public interface JournalEntryWritePlatformService {
|
||||
CommandProcessingResult revertJournalEntry(JsonCommand command);
|
||||
|
||||
void createJournalEntriesForLoan(Map<String, Object> accountingBridgeData);
|
||||
|
||||
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
|
||||
}
|
||||
|
||||
+37
-18
@@ -22,6 +22,7 @@ import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams
|
||||
import org.mifosplatform.accounting.journalentry.command.JournalEntryCommand;
|
||||
import org.mifosplatform.accounting.journalentry.command.SingleDebitOrCreditEntryCommand;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntry;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
|
||||
@@ -56,6 +57,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final JournalEntryRepository glJournalEntryRepository;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory;
|
||||
private final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory;
|
||||
private final AccountingProcessorHelper helper;
|
||||
private final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final AccountingRuleRepository accountingRuleRepository;
|
||||
@@ -65,13 +67,15 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final JournalEntryRepository glJournalEntryRepository, final OfficeRepository officeRepository,
|
||||
final GLAccountRepository glAccountRepository, final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final AccountingProcessorHelper accountingProcessorHelper, final AccountingRuleRepository accountingRuleRepository,
|
||||
final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory) {
|
||||
final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory,
|
||||
final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory) {
|
||||
this.glClosureRepository = glClosureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.glAccountRepository = glAccountRepository;
|
||||
this.accountingProcessorForLoanFactory = accountingProcessorForLoanFactory;
|
||||
this.accountingProcessorForSavingsFactory = accountingProcessorForSavingsFactory;
|
||||
this.helper = accountingProcessorHelper;
|
||||
this.accountingRuleRepository = accountingRuleRepository;
|
||||
}
|
||||
@@ -87,9 +91,9 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final Long officeId = command.longValueOfParameterNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue());
|
||||
final Office office = this.officeRepository.findOne(officeId);
|
||||
if (office == null) { throw new OfficeNotFoundException(officeId); }
|
||||
|
||||
|
||||
final Long accountRuleId = command.longValueOfParameterNamed(JournalEntryJsonInputParams.ACCOUNTING_RULE.getValue());
|
||||
|
||||
|
||||
validateBusinessRulesForJournalEntries(journalEntryCommand);
|
||||
|
||||
/** Set a transaction Id and save these Journal entries **/
|
||||
@@ -99,7 +103,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final boolean manualEntry = true;
|
||||
|
||||
if (accountRuleId != null) {
|
||||
|
||||
|
||||
final Long accountingRuleId = command.longValueOfParameterNamed(JournalEntryJsonInputParams.ACCOUNTING_RULE.getValue());
|
||||
final BigDecimal amount = command.bigDecimalValueOfParameterNamed(JournalEntryJsonInputParams.AMOUNT.getValue());
|
||||
final AccountingRule accountingRule = this.accountingRuleRepository.findOne(accountingRuleId);
|
||||
@@ -112,24 +116,23 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
if (StringUtils.isNotBlank(journalEntryCommand.getComments())) {
|
||||
description = journalEntryCommand.getComments();
|
||||
}
|
||||
|
||||
JournalEntry creditEntry = JournalEntry.createNew(office, creditAccountHead, transactionId, manualEntry, transactionDate,
|
||||
|
||||
JournalEntry creditEntry = JournalEntry.createNew(office, creditAccountHead, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.CREDIT, amount, description, null, null, referenceNumber);
|
||||
this.glJournalEntryRepository.saveAndFlush(creditEntry);
|
||||
|
||||
JournalEntry debitEntry = JournalEntry.createNew(office, debitAccountHead, transactionId, manualEntry, transactionDate,
|
||||
|
||||
JournalEntry debitEntry = JournalEntry.createNew(office, debitAccountHead, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.DEBIT, amount, description, null, null, referenceNumber);
|
||||
this.glJournalEntryRepository.saveAndFlush(debitEntry);
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getDebits(), transactionId,
|
||||
JournalEntryType.DEBIT, referenceNumber);
|
||||
|
||||
|
||||
saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getCredits(), transactionId,
|
||||
JournalEntryType.CREDIT, referenceNumber);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(officeId)
|
||||
@@ -146,8 +149,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
* disabled
|
||||
**/
|
||||
if (creditOrDebitAccountHead.isDisabled()) {
|
||||
throw new JournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.GL_ACCOUNT_DISABLED, null, creditOrDebitAccountHead.getName(),
|
||||
creditOrDebitAccountHead.getGlCode());
|
||||
throw new JournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.GL_ACCOUNT_DISABLED, null,
|
||||
creditOrDebitAccountHead.getName(), creditOrDebitAccountHead.getGlCode());
|
||||
} else if (!creditOrDebitAccountHead.isManualEntriesAllowed()) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED, null, creditOrDebitAccountHead.getName(),
|
||||
creditOrDebitAccountHead.getGlCode()); }
|
||||
@@ -204,6 +207,23 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData) {
|
||||
|
||||
final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled");
|
||||
final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled");
|
||||
|
||||
if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) {
|
||||
final SavingsDTO savingsDTO = helper.populateSavingsDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
|
||||
accrualBasedAccountingEnabled);
|
||||
final AccountingProcessorForSavings accountingProcessorForSavings = this.accountingProcessorForSavingsFactory
|
||||
.determineProcessor(savingsDTO);
|
||||
accountingProcessorForSavings.createJournalEntriesForSavings(savingsDTO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
||||
/** check if date of Journal entry is valid ***/
|
||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||
@@ -218,15 +238,15 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
if (latestGLClosure.getClosingDate().after(transactionDate) || latestGLClosure.getClosingDate().equals(transactionDate)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
|
||||
}
|
||||
if(command.getAccountingRuleId() == null) {
|
||||
if (command.getAccountingRuleId() == null) {
|
||||
/*** check if credits and debits are valid **/
|
||||
final SingleDebitOrCreditEntryCommand[] credits = command.getCredits();
|
||||
final SingleDebitOrCreditEntryCommand[] debits = command.getDebits();
|
||||
|
||||
|
||||
// atleast one debit or credit must be present
|
||||
if ((credits == null || credits.length <= 0) || (debits == null || debits.length <= 0)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null, null, null); }
|
||||
|
||||
|
||||
// sum of all debits must be = sum of all credits
|
||||
BigDecimal creditsSum = BigDecimal.ZERO;
|
||||
BigDecimal debitsSum = BigDecimal.ZERO;
|
||||
@@ -259,7 +279,6 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
if (!StringUtils.isBlank(singleDebitOrCreditEntryCommand.getComments())) {
|
||||
comments = singleDebitOrCreditEntryCommand.getComments();
|
||||
}
|
||||
|
||||
final JournalEntry glJournalEntry = JournalEntry.createNew(office, glAccount, transactionId, manualEntry, transactionDate,
|
||||
type, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, referenceNumber);
|
||||
this.glJournalEntryRepository.saveAndFlush(glJournalEntry);
|
||||
|
||||
+48
-5
@@ -10,7 +10,9 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
@@ -18,10 +20,10 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.*;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@@ -41,9 +43,9 @@ import com.google.gson.JsonElement;
|
||||
* till we have access to the domain object it would not be possible to detect
|
||||
* if an accounting rule has actually been changed
|
||||
*
|
||||
* Hence, method {@link #validateForCreate(String)} from this class is called
|
||||
* separately for validation only if an accounting rule change is detected by
|
||||
* {@link ProductToGLAccountMappingWritePlatformService}
|
||||
* Hence, method {@link #validateForLoanProductCreate(String)} from this class
|
||||
* is called separately for validation only if an accounting rule change is
|
||||
* detected by {@link ProductToGLAccountMappingWritePlatformService}
|
||||
*
|
||||
* Also, the class is probably named wrong (*FromApiJsonDeserializer) should
|
||||
* probably be named as (*Validator) instead
|
||||
@@ -59,7 +61,7 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
public void validateForLoanProductCreate(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
@@ -126,6 +128,47 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForSavingsProductCreate(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = this.fromApiJsonHelper
|
||||
.extractIntegerNamed(accountingRuleParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(accountingRuleParamName).value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue())
|
||||
.value(savingsControlAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
|
||||
.value(savingsReferenceAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
package org.mifosplatform.accounting.producttoaccountmapping.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Component
|
||||
public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappingHelper {
|
||||
|
||||
@Autowired
|
||||
public LoanProductToGLAccountMappingHelper(GLAccountRepository glAccountRepository,
|
||||
ProductToGLAccountMappingRepository glAccountMappingRepository, FromJsonHelper fromApiJsonHelper,
|
||||
CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
|
||||
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper);
|
||||
}
|
||||
|
||||
/*** Set of abstractions for saving Loan Products to GL Account Mappings ***/
|
||||
|
||||
public void saveLoanToAssetAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.ASSET, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void saveLoanToIncomeAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.INCOME, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void saveLoanToExpenseAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.EXPENSE, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
/*** Set of abstractions for merging Savings Products to GL Account Mappings ***/
|
||||
public void mergeLoanToAssetAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.ASSET,
|
||||
PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void mergeLoanToIncomeAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.INCOME,
|
||||
PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void mergeLoanToExpenseAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.EXPENSE,
|
||||
PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
/*** Abstractions for payments channel related to loan products ***/
|
||||
|
||||
public void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
savePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
updatePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public Map<String, Object> populateChangesForNewLoanProductToGLAccountMappingCreation(final JsonElement element,
|
||||
final AccountingRuleType accountingRuleType) {
|
||||
final Map<String, Object> changes = new HashMap<String, Object>();
|
||||
|
||||
final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element);
|
||||
final Long loanPortfolioAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), element);
|
||||
final Long incomeFromInterestId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), element);
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
final Long writeOffAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
|
||||
|
||||
final Long receivableInterestAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element);
|
||||
final Long receivableFeeAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element);
|
||||
final Long receivablePenaltyAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element);
|
||||
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId);
|
||||
break;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines and updates each account mapping for given loan product with
|
||||
* changes passed in from the Json element
|
||||
*
|
||||
* @param loanProductId
|
||||
* @param changes
|
||||
* @param element
|
||||
* @param accountingRuleType
|
||||
*/
|
||||
public void handleChangesToLoanProductToGLAccountMappings(final Long loanProductId, final Map<String, Object> changes,
|
||||
final JsonElement element, final AccountingRuleType accountingRuleType) {
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
// assets (including receivables)
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(),
|
||||
changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(),
|
||||
changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteLoanProductToGLAccountMapping(final Long loanProductId) {
|
||||
deleteProductToGLAccountMapping(loanProductId, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
package org.mifosplatform.accounting.producttoaccountmapping.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingInvalidException;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
|
||||
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.paymentdetail.PaymentDetailConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@Component
|
||||
public class ProductToGLAccountMappingHelper {
|
||||
|
||||
protected final GLAccountRepository accountRepository;
|
||||
protected final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||
protected final FromJsonHelper fromApiJsonHelper;
|
||||
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
|
||||
|
||||
@Autowired
|
||||
public ProductToGLAccountMappingHelper(final GLAccountRepository glAccountRepository,
|
||||
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
|
||||
final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
|
||||
this.accountRepository = glAccountRepository;
|
||||
this.accountMappingRepository = glAccountMappingRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
||||
|
||||
}
|
||||
|
||||
public void saveProductToAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId, final GLAccountType expectedAccountType, final PortfolioProductType portfolioProductType) {
|
||||
final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element);
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), placeHolderTypeId);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
}
|
||||
|
||||
public void mergeProductToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes,
|
||||
final GLAccountType expectedAccountType, final PortfolioProductType portfolioProductType) {
|
||||
final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element);
|
||||
|
||||
// get the existing product
|
||||
if (accountId != null) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId,
|
||||
portfolioProductType.getValue(), accountTypeId);
|
||||
if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(portfolioProductType, productId,
|
||||
accountTypeName); }
|
||||
if (accountMapping.getGlAccount().getId() != accountId) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
changes.put(paramName, accountId);
|
||||
accountMapping.setGlAccount(glAccount);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the payment type to Fund source 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 savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes, final PortfolioProductType portfolioProductType) {
|
||||
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
|
||||
}
|
||||
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
|
||||
savePaymentChannelToFundSourceMapping(productId, paymentTypeId, paymentSpecificFundAccountId, portfolioProductType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command
|
||||
* @param element
|
||||
* @param productId
|
||||
* @param changes
|
||||
*/
|
||||
public void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes, final PortfolioProductType portfolioProductType) {
|
||||
// find all existing payment Channel to Fund source Mappings
|
||||
List<ProductToGLAccountMapping> existingPaymentChannelToFundSourceMappings = accountMappingRepository
|
||||
.findAllPaymentTypeToFundSourceMappings(productId, portfolioProductType.getValue());
|
||||
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
/**
|
||||
* Variable stores a map representation of Payment channels (key) and
|
||||
* their fund sources (value) extracted from the passed in Jsoncommand
|
||||
**/
|
||||
Map<Long, Long> inputPaymentChannelFundSourceMap = new HashMap<Long, Long>();
|
||||
/***
|
||||
* Variable stores all payment types which have already been mapped to
|
||||
* Fund Sources in the system
|
||||
**/
|
||||
Set<Long> existingPaymentTypes = new HashSet<Long>();
|
||||
if (paymentChannelMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
|
||||
inputPaymentChannelFundSourceMap.put(paymentTypeId, paymentSpecificFundAccountId);
|
||||
}
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputPaymentChannelFundSourceMap.size() == 0) {
|
||||
accountMappingRepository.deleteInBatch(existingPaymentChannelToFundSourceMappings);
|
||||
}/**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
* delete old mappings (which re already present, but not passed in
|
||||
* as a part of Jsoncommand)<br/>
|
||||
* Create new mappings for payment types that are passed in as a
|
||||
* part of the Jsoncommand but not already present
|
||||
*
|
||||
**/
|
||||
else {
|
||||
for (ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) {
|
||||
Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getPaymentType().getId();
|
||||
existingPaymentTypes.add(currentPaymentChannelId);
|
||||
// update existing mappings (if required)
|
||||
if (inputPaymentChannelFundSourceMap.containsKey(currentPaymentChannelId)) {
|
||||
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(currentPaymentChannelId);
|
||||
if (newGLAccountId != existingPaymentChannelToFundSourceMapping.getGlAccount().getId()) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
|
||||
GLAccountType.ASSET, newGLAccountId);
|
||||
existingPaymentChannelToFundSourceMapping.setGlAccount(glAccount);
|
||||
accountMappingRepository.save(existingPaymentChannelToFundSourceMapping);
|
||||
}
|
||||
}// deleted payment type
|
||||
else {
|
||||
accountMappingRepository.delete(existingPaymentChannelToFundSourceMapping);
|
||||
}
|
||||
}
|
||||
// create new mappings
|
||||
Set<Long> incomingPaymentTypes = inputPaymentChannelFundSourceMap.keySet();
|
||||
incomingPaymentTypes.removeAll(existingPaymentTypes);
|
||||
// incomingPaymentTypes now only contains the newly added
|
||||
// payment Type mappings
|
||||
for (Long newPaymentType : incomingPaymentTypes) {
|
||||
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(newPaymentType);
|
||||
savePaymentChannelToFundSourceMapping(productId, newPaymentType, newGLAccountId, portfolioProductType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param productId
|
||||
* @param jsonObject
|
||||
*/
|
||||
private void savePaymentChannelToFundSourceMapping(final Long productId, final Long paymentTypeId,
|
||||
final Long paymentTypeSpecificFundAccountId, final PortfolioProductType portfolioProductType) {
|
||||
CodeValue paymentType = codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(
|
||||
PaymentDetailConstants.paymentTypeCodeName, paymentTypeId);
|
||||
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), GLAccountType.ASSET,
|
||||
paymentTypeSpecificFundAccountId);
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), paymentType);
|
||||
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)
|
||||
*
|
||||
* @param paramName
|
||||
* @param expectedAccountType
|
||||
* @param accountId
|
||||
* @return
|
||||
*/
|
||||
public GLAccount getAccountByIdAndType(final String paramName, final GLAccountType expectedAccountType, final Long accountId) {
|
||||
final GLAccount glAccount = this.accountRepository.findOne(accountId);
|
||||
if (glAccount == null) { throw new GLAccountNotFoundException(accountId); }
|
||||
|
||||
// validate account is of the expected Type
|
||||
if (glAccount.getType().intValue() != expectedAccountType.getValue()) { throw new ProductToGLAccountMappingInvalidException(
|
||||
paramName, glAccount.getName(), accountId, GLAccountType.fromInt(glAccount.getType()).toString(),
|
||||
expectedAccountType.toString()); }
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType) {
|
||||
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository.findByProductIdAndProductType(
|
||||
loanProductId, portfolioProductType.getValue());
|
||||
if (productToGLAccountMappings != null && productToGLAccountMappings.size() > 0) {
|
||||
this.accountMappingRepository.deleteInBatch(productToGLAccountMappings);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -12,7 +12,11 @@ import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGL
|
||||
|
||||
public interface ProductToGLAccountMappingReadPlatformService {
|
||||
|
||||
Map<String, Object> fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType);
|
||||
public Map<String, Object> fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType);
|
||||
|
||||
List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(final Long loanProductId);
|
||||
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(final Long loanProductId);
|
||||
|
||||
public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(final Long savingsProductId, final Integer accountingType);
|
||||
|
||||
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForSavingsProduct(final Long savingsProductId);
|
||||
}
|
||||
+61
-8
@@ -14,10 +14,13 @@ import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
|
||||
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.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
@@ -33,11 +36,11 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class LoanProductToGLAccountMappingMapper implements RowMapper<Map<String, Object>> {
|
||||
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=1 ";
|
||||
+ " payment_type as paymentTypeId from acc_product_mapping " + " where product_type= ? ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,10 +70,11 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
|
||||
final Map<String, Object> accountMappingDetails = new LinkedHashMap<String, Object>(8);
|
||||
|
||||
final LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper();
|
||||
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
|
||||
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is null ";
|
||||
|
||||
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId });
|
||||
final List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] {
|
||||
PortfolioProductType.LOAN.getValue(), loanProductId });
|
||||
|
||||
if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
|
||||
|
||||
@@ -129,15 +133,63 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
return accountMappingDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(Long savingsProductId, Integer accountingType) {
|
||||
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 List<Map<String, Object>> listOfProductToGLAccountMaps = this.jdbcTemplate.query(sql, rm, new Object[] {
|
||||
PortfolioProductType.SAVING.getValue(), savingsProductId });
|
||||
|
||||
if (AccountingRuleType.CASH_BASED.getValue().equals(accountingType)) {
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : listOfProductToGLAccountMaps) {
|
||||
|
||||
final Integer financialAccountType = (Integer) productToGLAccountMap.get("financialAccountType");
|
||||
final CASH_ACCOUNTS_FOR_SAVINGS glAccountForSavings = CASH_ACCOUNTS_FOR_SAVINGS.fromInt(financialAccountType);
|
||||
|
||||
final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
|
||||
|
||||
if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), glAccountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return accountMappingDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(Long loanProductId) {
|
||||
List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers = null;
|
||||
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.LOAN, loanProductId, paymentTypeToGLAccountMappers);
|
||||
}
|
||||
|
||||
final LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper();
|
||||
@Override
|
||||
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForSavingsProduct(Long savingsProductId) {
|
||||
List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers = null;
|
||||
return fetchPaymentTypeToFundSourceMappings(PortfolioProductType.SAVING, savingsProductId, paymentTypeToGLAccountMappers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loanProductId
|
||||
* @param paymentTypeToGLAccountMappers
|
||||
* @return
|
||||
*/
|
||||
private List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappings(PortfolioProductType portfolioProductType,
|
||||
Long loanProductId, List<PaymentTypeToGLAccountMapper> paymentTypeToGLAccountMappers) {
|
||||
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[] { loanProductId });
|
||||
final List<Map<String, Object>> paymentTypeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm, new Object[] {
|
||||
portfolioProductType.getValue(), loanProductId });
|
||||
|
||||
for (final Map<String, Object> productToGLAccountMap : paymentTypeToFundSourceMappingsList) {
|
||||
if (paymentTypeToGLAccountMappers == null) {
|
||||
@@ -150,4 +202,5 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
}
|
||||
return paymentTypeToGLAccountMappers;
|
||||
}
|
||||
|
||||
}
|
||||
+5
-1
@@ -13,8 +13,12 @@ public interface ProductToGLAccountMappingWritePlatformService {
|
||||
|
||||
void createLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command);
|
||||
|
||||
void createSavingProductToGLAccountMapping(Long savingProductId, JsonCommand command);
|
||||
|
||||
Map<String, Object> updateLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command, boolean accountingRuleChanged,
|
||||
int accountingRuleTypeId);
|
||||
|
||||
void deleteLoanProductToGLAccountMapping(Long loanProductId);
|
||||
Map<String, Object> updateSavingsProductToGLAccountMapping(Long savingsProductId, JsonCommand command, boolean accountingRuleChanged,
|
||||
int accountingRuleTypeId);
|
||||
|
||||
}
|
||||
+122
-464
@@ -6,57 +6,42 @@
|
||||
package org.mifosplatform.accounting.producttoaccountmapping.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingInvalidException;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.serialization.ProductToGLAccountMappingFromApiJsonDeserializer;
|
||||
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.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.*;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@Service
|
||||
public class ProductToGLAccountMappingWritePlatformServiceImpl implements ProductToGLAccountMappingWritePlatformService {
|
||||
|
||||
private final GLAccountRepository accountRepository;
|
||||
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final ProductToGLAccountMappingFromApiJsonDeserializer deserializer;
|
||||
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
|
||||
private final LoanProductToGLAccountMappingHelper loanProductToGLAccountMappingHelper;
|
||||
private final SavingsProductToGLAccountMappingHelper savingsProductToGLAccountMappingHelper;
|
||||
|
||||
@Autowired
|
||||
public ProductToGLAccountMappingWritePlatformServiceImpl(final GLAccountRepository glAccountRepository,
|
||||
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
|
||||
final ProductToGLAccountMappingFromApiJsonDeserializer deserializer, final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
|
||||
this.accountRepository = glAccountRepository;
|
||||
this.accountMappingRepository = glAccountMappingRepository;
|
||||
public ProductToGLAccountMappingWritePlatformServiceImpl(final FromJsonHelper fromApiJsonHelper,
|
||||
final ProductToGLAccountMappingFromApiJsonDeserializer deserializer,
|
||||
LoanProductToGLAccountMappingHelper loanProductToGLAccountMappingHelper,
|
||||
SavingsProductToGLAccountMappingHelper savingsProductToGLAccountMappingHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.deserializer = deserializer;
|
||||
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
|
||||
this.loanProductToGLAccountMappingHelper = loanProductToGLAccountMappingHelper;
|
||||
this.savingsProductToGLAccountMappingHelper = savingsProductToGLAccountMappingHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,58 +56,115 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue());
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper
|
||||
.saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue());
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue());
|
||||
|
||||
// income
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue());
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue());
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
// expenses
|
||||
saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue());
|
||||
|
||||
// advanced accounting mappings
|
||||
savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
|
||||
// assets (including receivables)
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue());
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue());
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue());
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue());
|
||||
saveLoanToAssetAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToAssetAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue());
|
||||
|
||||
// income
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue());
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue());
|
||||
saveLoanToIncomeAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToIncomeAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
// expenses
|
||||
saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue());
|
||||
|
||||
// advanced accounting mappings
|
||||
savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void createSavingProductToGLAccountMapping(Long savingProductId, JsonCommand command) {
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
|
||||
final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed(accountingRuleParamName, element,
|
||||
Locale.getDefault());
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
|
||||
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue());
|
||||
|
||||
// income
|
||||
savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue());
|
||||
|
||||
// expenses
|
||||
savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue());
|
||||
|
||||
// liability
|
||||
savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue());
|
||||
|
||||
// advanced accounting mappings
|
||||
savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
|
||||
break;
|
||||
/*** Do not have accrual based accounting for now ***/
|
||||
case ACCRUAL_BASED:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Map<String, Object> updateLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command,
|
||||
@@ -131,7 +173,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
* Variable tracks all accounting mapping properties that have been
|
||||
* updated
|
||||
***/
|
||||
final Map<String, Object> changes = new HashMap<String, Object>();
|
||||
Map<String, Object> changes = new HashMap<String, Object>();
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
|
||||
|
||||
@@ -140,433 +182,49 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
* for the product and recreate a new set of mappings
|
||||
***/
|
||||
if (accountingRuleChanged) {
|
||||
this.deserializer.validateForCreate(command.json());
|
||||
handleChangesToAccountingRuleType(loanProductId, command, changes, element, accountingRuleType);
|
||||
savePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
|
||||
this.deserializer.validateForLoanProductCreate(command.json());
|
||||
loanProductToGLAccountMappingHelper.deleteLoanProductToGLAccountMapping(loanProductId);
|
||||
createLoanProductToGLAccountMapping(loanProductId, command);
|
||||
changes = loanProductToGLAccountMappingHelper.populateChangesForNewLoanProductToGLAccountMappingCreation(element,
|
||||
accountingRuleType);
|
||||
loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
|
||||
}/*** else examine and update individual changes ***/
|
||||
else {
|
||||
handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element, accountingRuleType);
|
||||
updatePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
|
||||
loanProductToGLAccountMappingHelper.handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element,
|
||||
accountingRuleType);
|
||||
loanProductToGLAccountMappingHelper.updatePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteLoanProductToGLAccountMapping(final Long loanProductId) {
|
||||
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository.findByProductIdAndProductType(
|
||||
loanProductId, PortfolioProductType.LOAN.getValue());
|
||||
if (productToGLAccountMappings != null && productToGLAccountMappings.size() > 0) {
|
||||
this.accountMappingRepository.deleteInBatch(productToGLAccountMappings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves payment type to Fund source mappings (also populates the changes
|
||||
* array if passed in)
|
||||
*
|
||||
* @param command
|
||||
* @param element
|
||||
* @param productId
|
||||
* @param changes
|
||||
*/
|
||||
private void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
|
||||
}
|
||||
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
|
||||
savePaymentChannelToFundSourceMapping(productId, paymentTypeId, paymentSpecificFundAccountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param command
|
||||
* @param element
|
||||
* @param productId
|
||||
* @param changes
|
||||
*/
|
||||
private void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
// find all existing payment Channel to Fund source Mappings
|
||||
List<ProductToGLAccountMapping> existingPaymentChannelToFundSourceMappings = accountMappingRepository
|
||||
.findAllPaymentTypeToFundSourceMappings(productId, PortfolioProductType.LOAN.getValue());
|
||||
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
/**
|
||||
* Variable stores a map representation of Payment channels (key) and
|
||||
* their fund sources (value) extracted from the passed in Jsoncommand
|
||||
**/
|
||||
Map<Long, Long> inputPaymentChannelFundSourceMap = new HashMap<Long, Long>();
|
||||
public Map<String, Object> updateSavingsProductToGLAccountMapping(Long savingsProductId, JsonCommand command,
|
||||
boolean accountingRuleChanged, int accountingRuleTypeId) {
|
||||
/***
|
||||
* Variable stores all payment types which hae already been mapped to
|
||||
* Fund Sources in the system
|
||||
**/
|
||||
Set<Long> existingPaymentTypes = new HashSet<Long>();
|
||||
if (paymentChannelMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
|
||||
}
|
||||
* Variable tracks all accounting mapping properties that have been
|
||||
* updated
|
||||
***/
|
||||
Map<String, Object> changes = new HashMap<String, Object>();
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
|
||||
|
||||
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
|
||||
inputPaymentChannelFundSourceMap.put(paymentTypeId, paymentSpecificFundAccountId);
|
||||
}
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputPaymentChannelFundSourceMap.size() == 0) {
|
||||
accountMappingRepository.deleteInBatch(existingPaymentChannelToFundSourceMappings);
|
||||
}/**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
* delete old mappings (which re already present, but not passed in
|
||||
* as a part of Jsoncommand)<br/>
|
||||
* Create new mappings for payment types that are passed in as a
|
||||
* part of the Jsoncommand but not already present
|
||||
*
|
||||
**/
|
||||
else {
|
||||
for (ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) {
|
||||
Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getPaymentType().getId();
|
||||
existingPaymentTypes.add(currentPaymentChannelId);
|
||||
// update existing mappings (if required)
|
||||
if (inputPaymentChannelFundSourceMap.containsKey(currentPaymentChannelId)) {
|
||||
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(currentPaymentChannelId);
|
||||
if (newGLAccountId != existingPaymentChannelToFundSourceMapping.getGlAccount().getId()) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
|
||||
GLAccountType.ASSET, newGLAccountId);
|
||||
existingPaymentChannelToFundSourceMapping.setGlAccount(glAccount);
|
||||
accountMappingRepository.save(existingPaymentChannelToFundSourceMapping);
|
||||
}
|
||||
}// deleted payment type
|
||||
else {
|
||||
accountMappingRepository.delete(existingPaymentChannelToFundSourceMapping);
|
||||
}
|
||||
}
|
||||
// create new mappings
|
||||
Set<Long> incomingPaymentTypes = inputPaymentChannelFundSourceMap.keySet();
|
||||
incomingPaymentTypes.removeAll(existingPaymentTypes);
|
||||
// incomingPaymentTypes now only contains the newly added
|
||||
// payment Type mappings
|
||||
for (Long newPaymentType : incomingPaymentTypes) {
|
||||
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(newPaymentType);
|
||||
savePaymentChannelToFundSourceMapping(productId, newPaymentType, newGLAccountId);
|
||||
}
|
||||
}
|
||||
/***
|
||||
* If the accounting rule has been changed, delete all existing mapping
|
||||
* for the product and recreate a new set of mappings
|
||||
***/
|
||||
if (accountingRuleChanged) {
|
||||
this.deserializer.validateForSavingsProductCreate(command.json());
|
||||
savingsProductToGLAccountMappingHelper.deleteSavingsProductToGLAccountMapping(savingsProductId);
|
||||
createSavingProductToGLAccountMapping(savingsProductId, command);
|
||||
changes = savingsProductToGLAccountMappingHelper.populateChangesForNewSavingsProductToGLAccountMappingCreation(element,
|
||||
accountingRuleType);
|
||||
savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingsProductId, changes);
|
||||
}/*** else examine and update individual changes ***/
|
||||
else {
|
||||
savingsProductToGLAccountMappingHelper.handleChangesToSavingsProductToGLAccountMappings(savingsProductId, changes, element,
|
||||
accountingRuleType);
|
||||
savingsProductToGLAccountMappingHelper.updatePaymentChannelToFundSourceMappings(command, element, savingsProductId, changes);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param productId
|
||||
* @param jsonObject
|
||||
*/
|
||||
private void savePaymentChannelToFundSourceMapping(final Long productId, final Long paymentTypeId,
|
||||
final Long paymentTypeSpecificFundAccountId) {
|
||||
CodeValue paymentType = codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(
|
||||
PaymentDetailConstants.paymentTypeCodeName, paymentTypeId);
|
||||
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), GLAccountType.ASSET,
|
||||
paymentTypeSpecificFundAccountId);
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
PortfolioProductType.LOAN.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), paymentType);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines and updates each account mapping for given loan product with
|
||||
* changes passed in from the Json element
|
||||
*
|
||||
* @param loanProductId
|
||||
* @param changes
|
||||
* @param element
|
||||
* @param accountingRuleType
|
||||
*/
|
||||
private void handleChangesToLoanProductToGLAccountMappings(final Long loanProductId, final Map<String, Object> changes,
|
||||
final JsonElement element, final AccountingRuleType accountingRuleType) {
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(), changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(), changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
// assets (including receivables)
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.toString(), changes);
|
||||
mergeLoanToAssetAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.toString(),
|
||||
changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.toString(),
|
||||
changes);
|
||||
mergeLoanToIncomeAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete all existing mapping for a product and recreates a new set of
|
||||
* mappings (to be used exclusively when the selected accounting rule has
|
||||
* changed)
|
||||
*
|
||||
* @param loanProductId
|
||||
* @param command
|
||||
* @param changes
|
||||
* @param element
|
||||
* @param accountingRuleType
|
||||
*/
|
||||
private void handleChangesToAccountingRuleType(final Long loanProductId, final JsonCommand command, final Map<String, Object> changes,
|
||||
final JsonElement element, final AccountingRuleType accountingRuleType) {
|
||||
deleteLoanProductToGLAccountMapping(loanProductId);
|
||||
createLoanProductToGLAccountMapping(loanProductId, command);
|
||||
final Long fundAccountId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element);
|
||||
final Long loanPortfolioAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), element);
|
||||
final Long incomeFromInterestId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), element);
|
||||
final Long incomeFromFeeId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
final Long writeOffAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
|
||||
|
||||
final Long receivableInterestAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element);
|
||||
final Long receivableFeeAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), element);
|
||||
final Long receivablePenaltyAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), element);
|
||||
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #saveLoanToAccountMapping(JsonElement, String, Long, int, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param placeHolderTypeId
|
||||
*/
|
||||
private void saveLoanToAssetAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveLoanToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.ASSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #saveLoanToAccountMapping(JsonElement, String, Long, int, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param placeHolderTypeId
|
||||
*/
|
||||
private void saveLoanToIncomeAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveLoanToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.INCOME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #saveLoanToAccountMapping(JsonElement, String, Long, int, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param placeHolderTypeId
|
||||
*/
|
||||
private void saveLoanToExpenseAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveLoanToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param placeHolderTypeId
|
||||
* @param expectedAccountType
|
||||
*/
|
||||
private void saveLoanToAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId, final GLAccountType expectedAccountType) {
|
||||
final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element);
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
PortfolioProductType.LOAN.getValue(), placeHolderTypeId);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #mergeLoanToAccountMappingChanges(JsonElement, String, Long, int, String, Map, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param accountTypeId
|
||||
* @param accountTypeName
|
||||
* @param changes
|
||||
*/
|
||||
private void mergeLoanToAssetAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeLoanToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.ASSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #mergeLoanToAccountMappingChanges(JsonElement, String, Long, int, String, Map, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param accountTypeId
|
||||
* @param accountTypeName
|
||||
* @param changes
|
||||
*/
|
||||
private void mergeLoanToIncomeAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeLoanToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.INCOME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility wrapper for
|
||||
* {@link #mergeLoanToAccountMappingChanges(JsonElement, String, Long, int, String, Map, GLAccountType)}
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param accountTypeId
|
||||
* @param accountTypeName
|
||||
* @param changes
|
||||
*/
|
||||
private void mergeLoanToExpenseAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeLoanToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method merges changes passed in through JSON element
|
||||
*
|
||||
* @param element
|
||||
* @param paramName
|
||||
* @param productId
|
||||
* @param accountTypeId
|
||||
* @param accountTypeName
|
||||
* @param changes
|
||||
* @param expectedAccountType
|
||||
*/
|
||||
private void mergeLoanToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes,
|
||||
final GLAccountType expectedAccountType) {
|
||||
final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element);
|
||||
|
||||
// get the existing product
|
||||
if (accountId != null) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId,
|
||||
PortfolioProductType.LOAN.getValue(), accountTypeId);
|
||||
if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, productId,
|
||||
accountTypeName); }
|
||||
if (accountMapping.getGlAccount().getId() != accountId) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
changes.put(paramName, accountId);
|
||||
accountMapping.setGlAccount(glAccount);
|
||||
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)
|
||||
*
|
||||
* @param paramName
|
||||
* @param expectedAccountType
|
||||
* @param accountId
|
||||
* @return
|
||||
*/
|
||||
private GLAccount getAccountByIdAndType(final String paramName, final GLAccountType expectedAccountType, final Long accountId) {
|
||||
final GLAccount glAccount = this.accountRepository.findOne(accountId);
|
||||
if (glAccount == null) { throw new GLAccountNotFoundException(accountId); }
|
||||
|
||||
// validate account is of the expected Type
|
||||
if (glAccount.getType().intValue() != expectedAccountType.getValue()) { throw new ProductToGLAccountMappingInvalidException(
|
||||
paramName, glAccount.getName(), accountId, GLAccountType.fromInt(glAccount.getType()).toString(),
|
||||
expectedAccountType.toString()); }
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
package org.mifosplatform.accounting.producttoaccountmapping.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Component
|
||||
public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMappingHelper {
|
||||
|
||||
@Autowired
|
||||
public SavingsProductToGLAccountMappingHelper(GLAccountRepository glAccountRepository,
|
||||
ProductToGLAccountMappingRepository glAccountMappingRepository, FromJsonHelper fromApiJsonHelper,
|
||||
CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
|
||||
super(glAccountRepository, glAccountMappingRepository, fromApiJsonHelper, codeValueRepositoryWrapper);
|
||||
}
|
||||
|
||||
/*** Set of abstractions for saving Saving Products to GL Account Mappings ***/
|
||||
|
||||
public void saveSavingsToAssetAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.ASSET, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToIncomeAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.INCOME, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToExpenseAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.EXPENSE, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveSavingsToLiabilityAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.LIABILITY, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
/*** Set of abstractions for merging Savings Products to GL Account Mappings ***/
|
||||
|
||||
public void mergeSavingsToAssetAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.ASSET,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToIncomeAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.INCOME,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToExpenseAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes, GLAccountType.EXPENSE,
|
||||
PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void mergeSavingsToLiabilityAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes,
|
||||
GLAccountType.LIABILITY, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
/*** Abstractions for payments channel related to savings products ***/
|
||||
|
||||
public void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
savePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
Map<String, Object> changes) {
|
||||
updatePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public Map<String, Object> populateChangesForNewSavingsProductToGLAccountMappingCreation(final JsonElement element,
|
||||
final AccountingRuleType accountingRuleType) {
|
||||
final Map<String, Object> changes = new HashMap<String, Object>();
|
||||
|
||||
final Long savingsReferenceId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), element);
|
||||
final Long incomeFromFeesId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), element);
|
||||
final Long interestOnSavingsId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
final Long savingsControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
|
||||
element);
|
||||
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), savingsControlId);
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
break;
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examines and updates each account mapping for given loan product with
|
||||
* changes passed in from the Json element
|
||||
*
|
||||
* @param savingsProductId
|
||||
* @param changes
|
||||
* @param element
|
||||
* @param accountingRuleType
|
||||
*/
|
||||
public void handleChangesToSavingsProductToGLAccountMappings(final Long savingsProductId, final Map<String, Object> changes,
|
||||
final JsonElement element, final AccountingRuleType accountingRuleType) {
|
||||
switch (accountingRuleType) {
|
||||
case NONE:
|
||||
break;
|
||||
case CASH_BASED:
|
||||
// asset
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.toString(), changes);
|
||||
|
||||
// income
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.toString(), changes);
|
||||
|
||||
// liability
|
||||
mergeSavingsToLiabilityAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.toString(), changes);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteSavingsProductToGLAccountMapping(final Long savingsProductId) {
|
||||
deleteProductToGLAccountMapping(savingsProductId, PortfolioProductType.SAVING);
|
||||
}
|
||||
}
|
||||
+8
-25
@@ -24,9 +24,8 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
@@ -81,9 +80,9 @@ public class LoanProductsApiResource {
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final LoanDropdownReadPlatformService dropdownReadPlatformService;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final GLAccountReadPlatformService accountReadPlatformService;
|
||||
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
||||
@@ -92,9 +91,9 @@ public class LoanProductsApiResource {
|
||||
final DefaultToApiJsonSerializer<LoanProductData> toApiJsonSerializer,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final GLAccountReadPlatformService accountReadPlatformService,
|
||||
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
|
||||
final CodeValueReadPlatformService codeValueReadPlatformService) {
|
||||
final CodeValueReadPlatformService codeValueReadPlatformService,
|
||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) {
|
||||
this.context = context;
|
||||
this.loanProductReadPlatformService = readPlatformService;
|
||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||
@@ -104,9 +103,9 @@ public class LoanProductsApiResource {
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.accountReadPlatformService = accountReadPlatformService;
|
||||
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
|
||||
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -218,26 +217,10 @@ public class LoanProductsApiResource {
|
||||
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions = this.dropdownReadPlatformService
|
||||
.retreiveTransactionProcessingStrategies();
|
||||
|
||||
Map<String, List<GLAccountData>> accountOptions = new HashMap<String, List<GLAccountData>>();
|
||||
List<GLAccountData> assetAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
if (assetAccountOptions.isEmpty()) {
|
||||
assetAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("assetAccountOptions", assetAccountOptions);
|
||||
Map<String, List<GLAccountData>> accountOptions = accountingDropdownReadPlatformService
|
||||
.retrieveAccountMappingOptionsForLoanProducts();
|
||||
|
||||
List<GLAccountData> incomeAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
|
||||
if (incomeAccountOptions.isEmpty()) {
|
||||
incomeAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
|
||||
|
||||
List<GLAccountData> expenseAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
if (expenseAccountOptions.isEmpty()) {
|
||||
expenseAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
|
||||
List<EnumOptionData> accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions();
|
||||
List<EnumOptionData> accountingRuleTypeOptions = accountingDropdownReadPlatformService.retrieveAccountingRuleTypeOptions();
|
||||
|
||||
return new LoanProductData(productData, chargeOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
|
||||
interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
|
||||
|
||||
+4
-3
@@ -11,6 +11,8 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
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.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
@@ -18,7 +20,6 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.fund.data.FundData;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -182,7 +183,7 @@ public class LoanProductData {
|
||||
final Long transactionProcessingStrategyId = null;
|
||||
final String transactionProcessingStrategyName = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final EnumOptionData accountingType = LoanEnumerations.accountingRuleType(AccountingRuleType.NONE);
|
||||
final EnumOptionData accountingType = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE);
|
||||
|
||||
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
|
||||
minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
|
||||
@@ -346,7 +347,7 @@ public class LoanProductData {
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
return this.accountingRule.getId() > 1;
|
||||
return this.accountingRule.getId() > AccountingRuleType.NONE.getValue();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
+1
-1
@@ -16,13 +16,13 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
-2
@@ -27,6 +27,4 @@ public interface LoanDropdownReadPlatformService {
|
||||
|
||||
Collection<TransactionProcessingStrategyData> retreiveTransactionProcessingStrategies();
|
||||
|
||||
List<EnumOptionData> retrieveAccountingRuleTypeOptions();
|
||||
|
||||
}
|
||||
-9
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanproduct.service;
|
||||
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.accountingRuleType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.amortizationType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestCalculationPeriodType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestRateFrequencyType;
|
||||
@@ -21,7 +20,6 @@ import java.util.List;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
|
||||
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -103,11 +101,4 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
return strategyOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveAccountingRuleTypeOptions() {
|
||||
List<EnumOptionData> accountingRuleTypeOptions = Arrays.asList(accountingRuleType(AccountingRuleType.NONE),
|
||||
accountingRuleType(AccountingRuleType.CASH_BASED), accountingRuleType(AccountingRuleType.ACCRUAL_BASED));
|
||||
return accountingRuleTypeOptions;
|
||||
}
|
||||
|
||||
}
|
||||
-12
@@ -11,7 +11,6 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -45,8 +44,6 @@ public class LoanEnumerations {
|
||||
return interestType(id);
|
||||
} else if (typeName.equals(INTEREST_CALCULATION_PERIOD_TYPE)) {
|
||||
return interestCalculationPeriodType(id);
|
||||
} else if (typeName.equals(ACCOUNTING_RULE_TYPE)) {
|
||||
return accountingRuleType(id);
|
||||
} else if (typeName.equals(LOAN_TYPE)) { return loanType(id); }
|
||||
return null;
|
||||
}
|
||||
@@ -337,15 +334,6 @@ public class LoanEnumerations {
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData accountingRuleType(final int id) {
|
||||
return accountingRuleType(AccountingRuleType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData accountingRuleType(final AccountingRuleType type) {
|
||||
EnumOptionData optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), type.toString());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData loanType(final Integer loanTypeId) {
|
||||
return loanType(LoanType.fromInt(loanTypeId));
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingEnumerations;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
@@ -140,7 +141,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaidEvery");
|
||||
|
||||
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
||||
final EnumOptionData accountingRuleType = LoanEnumerations.accountingRuleType(accountingRuleId);
|
||||
final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
||||
|
||||
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
|
||||
final BigDecimal minInterestRatePerPeriod = rs.getBigDecimal("minInterestRatePerPeriod");
|
||||
|
||||
+13
-3
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
@@ -20,12 +22,15 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -42,18 +47,21 @@ public class SavingsAccountTransactionsApiResource {
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountTransactionsApiResource(final PlatformSecurityContext context,
|
||||
final DefaultToApiJsonSerializer<SavingsAccountTransactionData> toApiJsonSerializer,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
|
||||
final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
|
||||
final CodeValueReadPlatformService codeValueReadPlatformService) {
|
||||
this.context = context;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
|
||||
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
@@ -71,8 +79,10 @@ public class SavingsAccountTransactionsApiResource {
|
||||
|
||||
// FIXME - KW - for now just send back generic default information for
|
||||
// both deposit/withdrawal templates
|
||||
final SavingsAccountTransactionData savingsAccount = this.savingsAccountReadPlatformService
|
||||
.retrieveDepositTransactionTemplate(savingsId);
|
||||
SavingsAccountTransactionData savingsAccount = this.savingsAccountReadPlatformService.retrieveDepositTransactionTemplate(savingsId);
|
||||
final Collection<CodeValueData> paymentTypeOptions = codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
|
||||
savingsAccount = SavingsAccountTransactionData.templateOnTop(savingsAccount, paymentTypeOptions);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, savingsAccount,
|
||||
|
||||
+15
-2
@@ -9,6 +9,7 @@ import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
|
||||
|
||||
@@ -49,6 +50,13 @@ public class SavingsApiConstants {
|
||||
public static final String withdrawalFeeTypeParamName = "withdrawalFeeType";
|
||||
public static final String annualFeeAmountParamName = "annualFeeAmount";
|
||||
public static final String annualFeeOnMonthDayParamName = "annualFeeOnMonthDay";
|
||||
public static final String accountingRuleParamName = "accountingRule";
|
||||
public static final String paymentTypeIdParamName = "paymentTypeId";
|
||||
public static final String accountNumberParamName = "accountNumber";
|
||||
public static final String checkNumberParamName = "checkNumber";
|
||||
public static final String routingCodeParamName = "routingCode";
|
||||
public static final String receiptNumberParamName = "receiptNumber";
|
||||
public static final String bankNumberParamName = "bankNumber";
|
||||
|
||||
// transaction parameters
|
||||
public static final String transactionDateParamName = "transactionDate";
|
||||
@@ -59,7 +67,11 @@ public class SavingsApiConstants {
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName,
|
||||
interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
annualFeeAmountParamName, annualFeeOnMonthDayParamName));
|
||||
annualFeeAmountParamName, annualFeeOnMonthDayParamName, accountingRuleParamName,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue()));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of
|
||||
@@ -99,7 +111,8 @@ public class SavingsApiConstants {
|
||||
"withdrawalFeeTypeOptions"));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName));
|
||||
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
|
||||
accountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
||||
"accountId", accountNoParamName, "currency", "amount"));
|
||||
|
||||
+55
-12
@@ -7,6 +7,9 @@ package org.mifosplatform.portfolio.savings.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
@@ -20,9 +23,17 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService;
|
||||
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.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
@@ -31,6 +42,7 @@ import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSeria
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
|
||||
@@ -55,6 +67,9 @@ public class SavingsProductsApiResource {
|
||||
private final DefaultToApiJsonSerializer<SavingsProductData> toApiJsonSerializer;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsProductsApiResource(final SavingsProductReadPlatformService savingProductReadPlatformService,
|
||||
@@ -62,7 +77,9 @@ public class SavingsProductsApiResource {
|
||||
final CurrencyReadPlatformService currencyReadPlatformService, final PlatformSecurityContext context,
|
||||
final DefaultToApiJsonSerializer<SavingsProductData> toApiJsonSerializer,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper) {
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper, final CodeValueReadPlatformService codeValueReadPlatformService,
|
||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
|
||||
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService) {
|
||||
this.savingProductReadPlatformService = savingProductReadPlatformService;
|
||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||
this.currencyReadPlatformService = currencyReadPlatformService;
|
||||
@@ -70,6 +87,9 @@ public class SavingsProductsApiResource {
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -120,15 +140,25 @@ public class SavingsProductsApiResource {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
SavingsProductData savingProduct = this.savingProductReadPlatformService.retrieveOne(productId);
|
||||
SavingsProductData savingProductData = this.savingProductReadPlatformService.retrieveOne(productId);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
if (settings.isTemplate()) {
|
||||
savingProduct = handleTemplateRelatedData(savingProduct);
|
||||
Map<String, Object> accountingMappings = null;
|
||||
Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
if (savingProductData.hasAccountingEnabled()) {
|
||||
accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForSavingsProduct(productId,
|
||||
savingProductData.accountingRuleTypeId());
|
||||
paymentChannelToFundSourceMappings = accountMappingReadPlatformService
|
||||
.fetchPaymentTypeToFundSourceMappingsForSavingsProduct(productId);
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer.serialize(settings, savingProduct, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
|
||||
if (settings.isTemplate()) {
|
||||
savingProductData = handleTemplateRelatedData(savingProductData, accountingMappings, paymentChannelToFundSourceMappings);
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer
|
||||
.serialize(settings, savingProductData, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -139,13 +169,14 @@ public class SavingsProductsApiResource {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
SavingsProductData savingProduct = handleTemplateRelatedData(null);
|
||||
SavingsProductData savingProduct = handleTemplateRelatedData(null, new HashMap<String, Object>(), null);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, savingProduct, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
private SavingsProductData handleTemplateRelatedData(final SavingsProductData savingsProduct) {
|
||||
private SavingsProductData handleTemplateRelatedData(final SavingsProductData savingsProduct,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings) {
|
||||
|
||||
final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations
|
||||
.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY);
|
||||
@@ -159,6 +190,8 @@ public class SavingsProductsApiResource {
|
||||
final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations
|
||||
.interestCalculationDaysInYearType(SavingsInterestCalculationDaysInYearType.DAYS_365);
|
||||
|
||||
final EnumOptionData accountingRule = AccountingEnumerations.accountingRuleType(AccountingRuleType.NONE);
|
||||
|
||||
CurrencyData currency = CurrencyData.blank();
|
||||
final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
|
||||
if (currencyOptions.size() == 1) {
|
||||
@@ -182,16 +215,26 @@ public class SavingsProductsApiResource {
|
||||
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
|
||||
|
||||
final Collection<CodeValueData> paymentTypeOptions = codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
|
||||
final Collection<EnumOptionData> accountingRuleOptions = this.accountingDropdownReadPlatformService
|
||||
.retrieveAccountingRuleTypeOptions();
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = accountingDropdownReadPlatformService
|
||||
.retrieveAccountMappingOptionsForSavingsProducts();
|
||||
|
||||
SavingsProductData savingsProductToReturn = null;
|
||||
if (savingsProduct != null) {
|
||||
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions);
|
||||
} else {
|
||||
savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
interestCalculationType, interestCalculationDaysInYearType, accountingRule, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions);
|
||||
}
|
||||
|
||||
return savingsProductToReturn;
|
||||
|
||||
+29
-5
@@ -6,9 +6,12 @@
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a savings account transaction.
|
||||
@@ -22,11 +25,18 @@ public class SavingsAccountTransactionData {
|
||||
private final String accountNo;
|
||||
private final LocalDate date;
|
||||
private final CurrencyData currency;
|
||||
private final PaymentDetailData paymentDetailData;
|
||||
private final BigDecimal amount;
|
||||
|
||||
// templates
|
||||
final Collection<CodeValueData> paymentTypeOptions;
|
||||
|
||||
public static SavingsAccountTransactionData create(final Long id, final SavingsAccountTransactionEnumData transactionType,
|
||||
final Long savingsId, final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount) {
|
||||
return new SavingsAccountTransactionData(id, transactionType, savingsId, savingsAccountNo, date, currency, amount);
|
||||
final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date,
|
||||
final CurrencyData currency, final BigDecimal amount) {
|
||||
final Collection<CodeValueData> paymentTypeOptions = null;
|
||||
return new SavingsAccountTransactionData(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, date, currency,
|
||||
amount, paymentTypeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransactionData template(final Long savingsId, final String savingsAccountNo,
|
||||
@@ -34,17 +44,31 @@ public class SavingsAccountTransactionData {
|
||||
final Long id = null;
|
||||
final SavingsAccountTransactionEnumData transactionType = null;
|
||||
final BigDecimal amount = null;
|
||||
return new SavingsAccountTransactionData(id, transactionType, savingsId, savingsAccountNo, defaultLocalDate, currency, amount);
|
||||
final PaymentDetailData paymentDetailData = null;
|
||||
final Collection<CodeValueData> paymentTypeOptions = null;
|
||||
return new SavingsAccountTransactionData(id, transactionType, paymentDetailData, savingsId, savingsAccountNo, defaultLocalDate,
|
||||
currency, amount, null);
|
||||
}
|
||||
|
||||
private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType, final Long savingsId,
|
||||
final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount) {
|
||||
public static SavingsAccountTransactionData templateOnTop(final SavingsAccountTransactionData savingsAccountTransactionData,
|
||||
final Collection<CodeValueData> paymentTypeOptions) {
|
||||
return new SavingsAccountTransactionData(savingsAccountTransactionData.id, savingsAccountTransactionData.transactionType,
|
||||
savingsAccountTransactionData.paymentDetailData, savingsAccountTransactionData.accountId,
|
||||
savingsAccountTransactionData.accountNo, savingsAccountTransactionData.date, savingsAccountTransactionData.currency,
|
||||
savingsAccountTransactionData.amount, paymentTypeOptions);
|
||||
}
|
||||
|
||||
private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final Long savingsId, final String savingsAccountNo, final LocalDate date,
|
||||
final CurrencyData currency, final BigDecimal amount, final Collection<CodeValueData> paymentTypeOptions) {
|
||||
this.id = id;
|
||||
this.transactionType = transactionType;
|
||||
this.paymentDetailData = paymentDetailData;
|
||||
this.accountId = savingsId;
|
||||
this.accountNo = savingsAccountNo;
|
||||
this.date = date;
|
||||
this.currency = currency;
|
||||
this.amount = amount;
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
}
|
||||
}
|
||||
+20
@@ -5,15 +5,24 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.bankNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.checkNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.paymentTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.receiptNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.routingCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionDateParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -62,6 +71,17 @@ public class SavingsAccountTransactionDataValidator {
|
||||
final BigDecimal transactionAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(transactionAmountParamName).value(transactionAmount).notNull().positiveAmount();
|
||||
|
||||
// Validate all string payment detail fields for max length
|
||||
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed(paymentTypeIdParamName, element);
|
||||
baseDataValidator.reset().parameter(paymentTypeIdParamName).value(paymentTypeId).ignoreIfNull().integerGreaterThanZero();
|
||||
final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList(accountNumberParamName, checkNumberParamName,
|
||||
routingCodeParamName, receiptNumberParamName, bankNumberParamName));
|
||||
for (String paymentDetailParameterName : paymentDetailParameters) {
|
||||
final String paymentDetailParameterValue = fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element);
|
||||
baseDataValidator.reset().parameter(paymentDetailParameterName).value(paymentDetailParameterValue).ignoreIfNull()
|
||||
.notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
|
||||
+33
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType;
|
||||
|
||||
/**
|
||||
* Immutable data object represent savings account transaction type
|
||||
* enumerations.
|
||||
@@ -16,9 +18,40 @@ public class SavingsAccountTransactionEnumData {
|
||||
private final String code;
|
||||
private final String value;
|
||||
|
||||
private final boolean deposit;
|
||||
private final boolean withdrawal;
|
||||
private final boolean interestPosting;
|
||||
private final boolean feeDeduction;
|
||||
|
||||
public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.deposit = Long.valueOf(SavingsAccountTransactionType.DEPOSIT.getValue()).equals(this.id);
|
||||
this.withdrawal = Long.valueOf(SavingsAccountTransactionType.WITHDRAWAL.getValue()).equals(this.id);
|
||||
this.interestPosting = Long.valueOf(SavingsAccountTransactionType.INTEREST_POSTING.getValue()).equals(this.id);
|
||||
this.feeDeduction = Long.valueOf(SavingsAccountTransactionType.ANNUAL_FEE.getValue()).equals(this.id)
|
||||
|| Long.valueOf(SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue()).equals(this.id);
|
||||
}
|
||||
|
||||
public boolean isDeposit() {
|
||||
return this.deposit;
|
||||
}
|
||||
|
||||
public boolean isWithdrawal() {
|
||||
return this.withdrawal;
|
||||
}
|
||||
|
||||
public boolean isDepositOrWithdrawal() {
|
||||
return this.deposit || this.withdrawal;
|
||||
}
|
||||
|
||||
public boolean isInterestPosting() {
|
||||
return this.interestPosting;
|
||||
}
|
||||
|
||||
public boolean isFeeDeduction() {
|
||||
return this.feeDeduction;
|
||||
}
|
||||
|
||||
}
|
||||
+90
-23
@@ -7,8 +7,14 @@ package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
|
||||
@@ -34,6 +40,13 @@ public class SavingsProductData {
|
||||
private final BigDecimal annualFeeAmount;
|
||||
private final MonthDay annualFeeOnMonthDay;
|
||||
|
||||
// accounting
|
||||
private final EnumOptionData accountingRule;
|
||||
@SuppressWarnings("unused")
|
||||
private final Map<String, Object> accountingMappings;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
|
||||
|
||||
// template
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
@@ -49,15 +62,23 @@ public class SavingsProductData {
|
||||
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<CodeValueData> paymentTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> accountingRuleOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||
|
||||
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final Collection<CurrencyData> currencyOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions) {
|
||||
|
||||
final Long id = null;
|
||||
final String name = null;
|
||||
@@ -70,34 +91,42 @@ public class SavingsProductData {
|
||||
final EnumOptionData withdrawalFeeType = null;
|
||||
final BigDecimal annualFeeAmount = null;
|
||||
final MonthDay annualFeeMonthDay = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeMonthDay, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, accountingRule, annualFeeAmount,
|
||||
annualFeeMonthDay, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SavingsProductData} that contains and exist
|
||||
* {@link SavingsProductData} data with further template data for dropdowns.
|
||||
*/
|
||||
public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection<CurrencyData> currencyOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions) {
|
||||
|
||||
return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.description, existingProduct.currency,
|
||||
existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeAmount,
|
||||
existingProduct.withdrawalFeeType, existingProduct.annualFeeAmount, existingProduct.annualFeeOnMonthDay, currencyOptions,
|
||||
existingProduct.withdrawalFeeType, existingProduct.accountingRule, existingProduct.annualFeeAmount,
|
||||
existingProduct.annualFeeOnMonthDay, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions);
|
||||
}
|
||||
|
||||
public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency,
|
||||
@@ -105,7 +134,11 @@ public class SavingsProductData {
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay) {
|
||||
final EnumOptionData withdrawalFeeType, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final EnumOptionData accountingType) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
@@ -114,13 +147,17 @@ public class SavingsProductData {
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<CodeValueData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, accountingType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions);
|
||||
}
|
||||
|
||||
public static SavingsProductData lookup(final Long id, final String name) {
|
||||
@@ -137,8 +174,11 @@ public class SavingsProductData {
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal withdrawalFeeAmount = null;
|
||||
final EnumOptionData withdrawalFeeType = null;
|
||||
final EnumOptionData accountingType = null;
|
||||
final BigDecimal annualFeeAmount = null;
|
||||
final MonthDay annualFeeMonthDay = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
@@ -147,13 +187,17 @@ public class SavingsProductData {
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
final Collection<CodeValueData> paymentTypeOptions = null;
|
||||
final Collection<EnumOptionData> accountingRuleOptions = null;
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeMonthDay, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, accountingType, annualFeeAmount,
|
||||
annualFeeMonthDay, accountingMappings, paymentChannelToFundSourceMappings, currencyOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions);
|
||||
}
|
||||
|
||||
private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency,
|
||||
@@ -161,12 +205,16 @@ public class SavingsProductData {
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final EnumOptionData withdrawalFeeType, final EnumOptionData accountingType, final BigDecimal annualFeeAmount,
|
||||
final MonthDay annualFeeOnMonthDay, final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
@@ -176,6 +224,7 @@ public class SavingsProductData {
|
||||
this.interestPostingPeriodType = interestPostingPeriodType;
|
||||
this.interestCalculationType = interestCalculationType;
|
||||
this.interestCalculationDaysInYearType = interestCalculationDaysInYearType;
|
||||
this.accountingRule = accountingType;
|
||||
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
@@ -191,5 +240,23 @@ public class SavingsProductData {
|
||||
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
|
||||
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
|
||||
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.accountingMappingOptions = accountingMappingOptions;
|
||||
this.accountingRuleOptions = accountingRuleOptions;
|
||||
if (accountingMappings == null || accountingMappings.isEmpty()) {
|
||||
this.accountingMappings = null;
|
||||
} else {
|
||||
this.accountingMappings = accountingMappings;
|
||||
}
|
||||
this.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings;
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
return this.accountingRule.getId() > AccountingRuleType.NONE.getValue();
|
||||
}
|
||||
|
||||
public int accountingRuleTypeId() {
|
||||
return this.accountingRule.getId().intValue();
|
||||
}
|
||||
}
|
||||
+95
@@ -28,10 +28,13 @@ import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.SAVINGS_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
@@ -40,7 +43,9 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
@@ -154,6 +159,35 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
|
||||
if (isCashBasedAccounting(accountingRuleType)) {
|
||||
|
||||
final Long savingsControlAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue())
|
||||
.value(savingsControlAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
|
||||
.value(savingsReferenceAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -250,10 +284,71 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
}
|
||||
|
||||
final Long savingsControlAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue()).value(savingsControlAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long savingsReferenceAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
|
||||
.value(savingsReferenceAccountId).ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
|
||||
.value(interestOnSavingsAccountId).ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromFeeId = fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private boolean isCashBasedAccounting(final Integer accountingRuleType) {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*
|
||||
* @param baseDataValidator
|
||||
* @param element
|
||||
*/
|
||||
private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (fromApiJsonHelper.parameterExists(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
||||
if (paymentChannelMappingArray != null && paymentChannelMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
|
||||
final Long paymentTypeId = jsonObject.get(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
|
||||
final Long paymentSpecificFundAccountId = jsonObject.get(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue())
|
||||
.getAsLong();
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.parameter(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.toString()).value(paymentTypeId).notNull()
|
||||
.integerGreaterThanZero();
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.parameter(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
|
||||
+ SAVINGS_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(paymentSpecificFundAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < paymentChannelMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
-7
@@ -16,8 +16,10 @@ import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -47,11 +49,13 @@ import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||
import org.slf4j.Logger;
|
||||
@@ -271,7 +275,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return SavingsAccountStatusType.fromInt(this.status).isActive();
|
||||
}
|
||||
|
||||
public void activate(final DateTimeFormatter formatter, final LocalDate activationDate) {
|
||||
public void activate(final DateTimeFormatter formatter, final LocalDate activationDate, List<Long> existingTransactionIds,
|
||||
List<Long> existingReversedTransactionIds) {
|
||||
|
||||
if (isActive()) {
|
||||
final String defaultUserMessage = "Cannot activate account. Account is already active.";
|
||||
@@ -305,7 +310,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
// activating account.
|
||||
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
|
||||
if (minRequiredOpeningBalance.isGreaterThanZero()) {
|
||||
deposit(formatter, activationDate, minRequiredOpeningBalance.getAmount());
|
||||
/**
|
||||
* Vishwas: TODO activate API should be modified to accept payment
|
||||
* details (for entering minimum balance)
|
||||
**/
|
||||
deposit(formatter, activationDate, minRequiredOpeningBalance.getAmount(), existingTransactionIds,
|
||||
existingReversedTransactionIds, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +343,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return lockedInUntilLocalDate;
|
||||
}
|
||||
|
||||
public void postInterest(final LocalDate interestPostingUpToDate) {
|
||||
public void postInterest(final LocalDate interestPostingUpToDate, List<Long> existingTransactionIds,
|
||||
List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final SavingsInterestPostingPeriodType postingPeriodType = SavingsInterestPostingPeriodType.fromInt(this.interestPostingPeriodType);
|
||||
final List<LocalDate> postingLocalDates = determineInterestPostingDates(getActivationLocalDate(), interestPostingUpToDate,
|
||||
@@ -344,6 +355,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
Money interestPostedToDate = Money.zero(this.currency);
|
||||
|
||||
boolean recalucateDailyBalanceDetails = false;
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
for (LocalDate postingDate : postingLocalDates) {
|
||||
Money interestEarnedToBePostedForPeriod = findInterestEarnedToBePostedOn(interestPostedToDate, postingDate, compoundingPeriods);
|
||||
|
||||
@@ -734,7 +747,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction deposit(final DateTimeFormatter formatter, final LocalDate transactionDate,
|
||||
final BigDecimal transactionAmount) {
|
||||
final BigDecimal transactionAmount, List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds,
|
||||
final PaymentDetail paymentDetail) {
|
||||
|
||||
if (isNotActive()) {
|
||||
final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
|
||||
@@ -771,8 +785,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money amount = Money.of(this.currency, transactionAmount);
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, transactionDate, amount);
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, paymentDetail, transactionDate, amount);
|
||||
this.transactions.add(transaction);
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
@@ -792,7 +809,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction withdraw(final DateTimeFormatter formatter, final LocalDate transactionDate,
|
||||
final BigDecimal transactionAmount) {
|
||||
final BigDecimal transactionAmount, List<Long> existingTransactionIds, List<Long> existingReversedTransactionIds,
|
||||
final PaymentDetail paymentDetail) {
|
||||
|
||||
if (isNotActive()) {
|
||||
|
||||
@@ -843,6 +861,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money transactionAmountMoney = Money.of(this.currency, transactionAmount);
|
||||
|
||||
if (isNotEnoughFundsToWithdraw(transactionAmountMoney)) {
|
||||
@@ -850,7 +871,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), transactionAmount);
|
||||
}
|
||||
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, transactionDate, transactionAmountMoney);
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, paymentDetail, transactionDate,
|
||||
transactionAmountMoney);
|
||||
this.transactions.add(transaction);
|
||||
|
||||
if (isAutomaticWithdrawalFee()) {
|
||||
@@ -875,6 +897,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
/***TODO Fixme: Annual fee seems to be added for all withdrawals?**/
|
||||
final Money annualFee = Money.of(this.currency, this.annualFeeAmount);
|
||||
SavingsAccountTransaction annualFeeTransaction = SavingsAccountTransaction.annualFee(this, transactionDate, annualFee);
|
||||
this.transactions.add(annualFeeTransaction);
|
||||
@@ -1096,6 +1119,53 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>();
|
||||
accountingBridgeData.put("savingsId", this.getId());
|
||||
accountingBridgeData.put("savingsProductId", this.productId());
|
||||
accountingBridgeData.put("officeId", this.officeId());
|
||||
accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnSavingsProduct());
|
||||
accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnSavingsProduct());
|
||||
|
||||
final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
|
||||
for (SavingsAccountTransaction transaction : this.transactions) {
|
||||
if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) {
|
||||
newLoanTransactions.add(transaction.toMapData(currencyData));
|
||||
} else if (!existingTransactionIds.contains(transaction.getId())) {
|
||||
newLoanTransactions.add(transaction.toMapData(currencyData));
|
||||
}
|
||||
}
|
||||
|
||||
accountingBridgeData.put("newSavingsTransactions", newLoanTransactions);
|
||||
return accountingBridgeData;
|
||||
}
|
||||
|
||||
private Collection<Long> findExistingTransactionIds() {
|
||||
|
||||
Collection<Long> ids = new ArrayList<Long>();
|
||||
|
||||
for (SavingsAccountTransaction transaction : this.transactions) {
|
||||
ids.add(transaction.getId());
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Collection<Long> findExistingReversedTransactionIds() {
|
||||
|
||||
final Collection<Long> ids = new ArrayList<Long>();
|
||||
|
||||
for (SavingsAccountTransaction transaction : this.transactions) {
|
||||
if (transaction.isReversed()) {
|
||||
ids.add(transaction.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void update(final Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
@@ -1117,6 +1187,18 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return this.accountNumberRequiresAutoGeneration;
|
||||
}
|
||||
|
||||
public Long productId() {
|
||||
return this.product.getId();
|
||||
}
|
||||
|
||||
private Boolean isCashBasedAccountingEnabledOnSavingsProduct() {
|
||||
return this.product.isCashBasedAccountingEnabled();
|
||||
}
|
||||
|
||||
private Boolean isAccrualBasedAccountingEnabledOnSavingsProduct() {
|
||||
return this.product.isAccrualBasedAccountingEnabled();
|
||||
}
|
||||
|
||||
public Long officeId() {
|
||||
Long officeId = null;
|
||||
if (this.client != null) {
|
||||
@@ -1142,4 +1224,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
return this.currency;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-2
@@ -21,6 +21,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdr
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -64,8 +65,12 @@ public class SavingsAccountAssembler {
|
||||
* Assembles a new {@link SavingsAccount} from JSON details passed in
|
||||
* request inheriting details where relevant from chosen
|
||||
* {@link SavingsProduct}.
|
||||
*
|
||||
* @param existingReversedTransactionIds
|
||||
* @param existingTransactionIds
|
||||
*/
|
||||
public SavingsAccount assembleFrom(final JsonCommand command) {
|
||||
public SavingsAccount assembleFrom(final JsonCommand command, List<Long> existingTransactionIds,
|
||||
List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final JsonElement element = command.parsedJson();
|
||||
|
||||
@@ -198,7 +203,7 @@ public class SavingsAccountAssembler {
|
||||
if (active) {
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
account.activate(formatter, activationDate);
|
||||
account.activate(formatter, activationDate, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
return account;
|
||||
|
||||
+45
-6
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -17,8 +19,12 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
/**
|
||||
@@ -34,6 +40,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
@JoinColumn(name = "savings_account_id", nullable = false)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "payment_detail_id", nullable = true)
|
||||
private PaymentDetail paymentDetail;
|
||||
|
||||
@Column(name = "transaction_type_enum", nullable = false)
|
||||
private final Integer typeOf;
|
||||
|
||||
@@ -66,14 +76,18 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
this.typeOf = null;
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
|
||||
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final PaymentDetail paymentDetail,
|
||||
final LocalDate date, final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.DEPOSIT.getValue(), date, amount, isReversed);
|
||||
return new SavingsAccountTransaction(savingsAccount, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date, amount,
|
||||
isReversed);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
|
||||
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final PaymentDetail paymentDetail,
|
||||
final LocalDate date, final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.WITHDRAWAL.getValue(), date, amount, isReversed);
|
||||
return new SavingsAccountTransaction(savingsAccount, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(), date,
|
||||
amount, isReversed);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
|
||||
@@ -90,17 +104,23 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount,
|
||||
isReversed);
|
||||
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount, isReversed);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Integer typeOf, final LocalDate transactionLocalDate,
|
||||
final Money amount, final boolean isReversed) {
|
||||
this(savingsAccount, null, typeOf, transactionLocalDate, amount, isReversed);
|
||||
}
|
||||
|
||||
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final PaymentDetail paymentDetail, final Integer typeOf,
|
||||
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) {
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.typeOf = typeOf;
|
||||
this.dateOf = transactionLocalDate.toDate();
|
||||
this.amount = amount.getAmount();
|
||||
this.reversed = isReversed;
|
||||
this.paymentDetail = paymentDetail;
|
||||
|
||||
}
|
||||
|
||||
public LocalDate transactionLocalDate() {
|
||||
@@ -209,4 +229,23 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
final Money transactionAmount = getAmount(amountToCheck.getCurrency());
|
||||
return transactionAmount.isNotEqualTo(amountToCheck);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMapData(final CurrencyData currencyData) {
|
||||
final Map<String, Object> thisTransactionData = new LinkedHashMap<String, Object>();
|
||||
|
||||
final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(this.typeOf);
|
||||
|
||||
thisTransactionData.put("id", this.getId());
|
||||
thisTransactionData.put("type", transactionType);
|
||||
thisTransactionData.put("reversed", Boolean.valueOf(this.isReversed()));
|
||||
thisTransactionData.put("date", this.getTransactionLocalDate());
|
||||
thisTransactionData.put("currency", currencyData);
|
||||
thisTransactionData.put("amount", this.amount);
|
||||
|
||||
if (this.paymentDetail != null) {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
}
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
}
|
||||
+33
-3
@@ -22,6 +22,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.namePa
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountingRuleParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -33,6 +34,7 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
@@ -93,6 +95,12 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
@Column(name = "lockin_period_frequency_enum", nullable = true)
|
||||
private Integer lockinPeriodFrequencyType;
|
||||
|
||||
/**
|
||||
* A value from the {@link AccountingRuleType} enumeration.
|
||||
*/
|
||||
@Column(name = "accounting_type", nullable = false)
|
||||
private Integer accountingRule;
|
||||
|
||||
@Column(name = "withdrawal_fee_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal withdrawalFeeAmount;
|
||||
|
||||
@@ -114,11 +122,11 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final BigDecimal annualFeeAmount,
|
||||
final MonthDay annualFeeOnMonthDay) {
|
||||
final MonthDay annualFeeOnMonthDay, final AccountingRuleType accountingRuleType) {
|
||||
|
||||
return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay);
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay, accountingRuleType);
|
||||
}
|
||||
|
||||
protected SavingsProduct() {
|
||||
@@ -132,7 +140,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final BigDecimal annualFeeAmount,
|
||||
final MonthDay annualFeeOnMonthDay) {
|
||||
final MonthDay annualFeeOnMonthDay, final AccountingRuleType accountingRuleType) {
|
||||
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
@@ -163,6 +171,10 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
|
||||
if (accountingRuleType != null) {
|
||||
this.accountingRule = accountingRuleType.getValue();
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
@@ -356,6 +368,12 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
this.annualFeeOnMonth = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(accountingRuleParamName, this.accountingRule)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(accountingRuleParamName);
|
||||
actualChanges.put(accountingRuleParamName, newValue);
|
||||
this.accountingRule = newValue;
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
@@ -401,4 +419,16 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
return (this.lockinPeriodFrequency == null && this.lockinPeriodFrequencyType != null)
|
||||
|| (this.lockinPeriodFrequencyType == null && this.lockinPeriodFrequency != null);
|
||||
}
|
||||
|
||||
public boolean isCashBasedAccountingEnabled() {
|
||||
return AccountingRuleType.CASH_BASED.getValue().equals(this.accountingRule);
|
||||
}
|
||||
|
||||
public boolean isAccrualBasedAccountingEnabled() {
|
||||
return AccountingRuleType.ACCRUAL_BASED.getValue().equals(this.accountingRule);
|
||||
}
|
||||
|
||||
public Integer getAccountingType() {
|
||||
return this.accountingRule;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -25,6 +25,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdr
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -86,10 +87,11 @@ public class SavingsProductAssembler {
|
||||
|
||||
final BigDecimal annualFeeAmount = command.bigDecimalValueOfParameterNamed(annualFeeAmountParamName);
|
||||
final MonthDay monthDayOfAnnualFee = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
|
||||
|
||||
return SavingsProduct.createNew(name, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
monthDayOfAnnualFee);
|
||||
monthDayOfAnnualFee, accountingRuleType);
|
||||
}
|
||||
}
|
||||
+26
-2
@@ -12,6 +12,7 @@ import java.util.Collection;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
@@ -22,6 +23,7 @@ import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountSummaryData;
|
||||
@@ -342,12 +344,17 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, ");
|
||||
sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,");
|
||||
sqlBuilder.append("sa.id as savingsId, sa.account_no as accountNo, ");
|
||||
sqlBuilder.append("pd.payment_type_cv_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, ");
|
||||
sqlBuilder.append("pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, ");
|
||||
sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, ");
|
||||
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
|
||||
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol ");
|
||||
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
|
||||
sqlBuilder.append("cv.code_value as paymentTypeName ");
|
||||
sqlBuilder.append("from m_savings_account sa ");
|
||||
sqlBuilder.append("join m_savings_account_transaction tr on tr.savings_account_id = sa.id ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sa.currency_code ");
|
||||
sqlBuilder.append("left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id ");
|
||||
sqlBuilder.append("left join m_code_value cv on pd.payment_type_cv_id = cv.id ");
|
||||
|
||||
this.schemaSql = sqlBuilder.toString();
|
||||
}
|
||||
@@ -368,6 +375,22 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final Long savingsId = rs.getLong("savingsId");
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
|
||||
PaymentDetailData paymentDetailData = null;
|
||||
if (transactionType.isDepositOrWithdrawal()) {
|
||||
final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType");
|
||||
if (paymentTypeId != null) {
|
||||
final String typeName = rs.getString("paymentTypeName");
|
||||
CodeValueData paymentType = CodeValueData.instance(paymentTypeId, typeName);
|
||||
final String accountNumber = rs.getString("accountNumber");
|
||||
final String checkNumber = rs.getString("checkNumber");
|
||||
final String routingCode = rs.getString("routingCode");
|
||||
final String receiptNumber = rs.getString("receiptNumber");
|
||||
final String bankNumber = rs.getString("bankNumber");
|
||||
paymentDetailData = new PaymentDetailData(id, paymentType, accountNumber, checkNumber, routingCode, receiptNumber,
|
||||
bankNumber);
|
||||
}
|
||||
}
|
||||
|
||||
final String currencyCode = rs.getString("currencyCode");
|
||||
final String currencyName = rs.getString("currencyName");
|
||||
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||
@@ -376,7 +399,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
|
||||
currencyNameCode);
|
||||
|
||||
return SavingsAccountTransactionData.create(id, transactionType, savingsId, accountNo, date, currency, amount);
|
||||
return SavingsAccountTransactionData.create(id, transactionType, paymentDetailData, savingsId, accountNo, date, currency,
|
||||
amount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-6
@@ -6,19 +6,25 @@
|
||||
package org.mifosplatform.portfolio.savings.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
@@ -26,6 +32,8 @@ import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataValidator;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDataValidator;
|
||||
@@ -59,6 +67,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final SavingsProductRepository savingsProductRepository;
|
||||
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -67,7 +78,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountAssembler savingAccountAssembler, final SavingsAccountDataValidator savingsAccountDataValidator,
|
||||
final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator,
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository,
|
||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository) {
|
||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository,
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
@@ -78,6 +92,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.savingsProductRepository = savingsProductRepository;
|
||||
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -115,7 +132,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountDataValidator.validateForCreate(command.json());
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
if (account.isAccountNumberRequiresAutoGeneration()) {
|
||||
@@ -126,6 +146,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Long savingsId = account.getId();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -237,10 +259,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
account.activate(fmt, activationDate);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
account.activate(fmt, activationDate, existingReversedTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -266,17 +293,26 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
|
||||
final SavingsAccountTransaction deposit = account.deposit(fmt, transactionDate, transactionAmount);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final SavingsAccountTransaction deposit = account.deposit(fmt, transactionDate, transactionAmount, existingTransactionIds,
|
||||
existingReversedTransactionIds, paymentDetail);
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(deposit);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(transactionId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes)//
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -301,16 +337,25 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(fmt, transactionDate, transactionAmount);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(fmt, transactionDate, transactionAmount, existingTransactionIds,
|
||||
existingReversedTransactionIds, paymentDetail);
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(withdrawal);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(transactionId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes)//
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -337,13 +382,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Override
|
||||
public CommandProcessingResult postInterest(final Long savingsId, final JsonCommand command) {
|
||||
this.context.authenticatedUser();
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(today);
|
||||
account.postInterest(today, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
@@ -352,4 +401,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -11,6 +11,7 @@ import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingEnumerations;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
@@ -89,7 +90,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
|
||||
sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,");
|
||||
sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay ");
|
||||
sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay, ");
|
||||
sqlBuilder.append("sp.accounting_type as accountingType ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
|
||||
|
||||
@@ -134,6 +136,9 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
.interestCalculationDaysInYearType(interestCalculationDaysInYearTypeValue);
|
||||
}
|
||||
|
||||
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
|
||||
final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
|
||||
|
||||
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
|
||||
|
||||
Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
|
||||
@@ -163,7 +168,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
return SavingsProductData.instance(id, name, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay);
|
||||
annualFeeOnMonthDay, accountingRuleType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.savings.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -23,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountingRuleParamName;
|
||||
|
||||
@Service
|
||||
public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements SavingsProductWritePlatformService {
|
||||
@@ -32,16 +34,19 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final SavingsProductRepository savingProductRepository;
|
||||
private final SavingsProductDataValidator fromApiJsonDataValidator;
|
||||
private final SavingsProductAssembler savingsProductAssembler;
|
||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final SavingsProductRepository savingProductRepository, final SavingsProductDataValidator fromApiJsonDataValidator,
|
||||
final SavingsProductAssembler savingsProductAssembler) {
|
||||
final SavingsProductAssembler savingsProductAssembler,
|
||||
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) {
|
||||
this.context = context;
|
||||
this.savingProductRepository = savingProductRepository;
|
||||
this.fromApiJsonDataValidator = fromApiJsonDataValidator;
|
||||
this.savingsProductAssembler = savingsProductAssembler;
|
||||
this.logger = LoggerFactory.getLogger(SavingsProductWritePlatformServiceJpaRepositoryImpl.class);
|
||||
this.accountMappingWritePlatformService = accountMappingWritePlatformService;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -78,6 +83,9 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingProductRepository.save(product);
|
||||
|
||||
// save accounting mappings
|
||||
accountMappingWritePlatformService.createSavingProductToGLAccountMapping(product.getId(), command);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(product.getId()) //
|
||||
.build();
|
||||
@@ -99,6 +107,13 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (product == null) { throw new SavingsProductNotFoundException(productId); }
|
||||
|
||||
final Map<String, Object> changes = product.update(command);
|
||||
|
||||
// accounting related changes
|
||||
boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName);
|
||||
final Map<String, Object> accountingMappingChanges = accountMappingWritePlatformService.updateSavingsProductToGLAccountMapping(
|
||||
product.getId(), command, accountingTypeChanged, product.getAccountingType());
|
||||
changes.putAll(accountingMappingChanges);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingProductRepository.saveAndFlush(product);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user