Merge branch 'client-fees' into develop
This commit is contained in:
+2
-1
@@ -223,7 +223,8 @@ public class AccountingConstants {
|
||||
public static enum FINANCIAL_ACTIVITY {
|
||||
ASSET_TRANSFER(100, "assetTransfer", GLAccountType.ASSET), LIABILITY_TRANSFER(200, "liabilityTransfer", GLAccountType.LIABILITY),
|
||||
CASH_AT_MAINVAULT (101, "cashAtMainVault", GLAccountType.ASSET),
|
||||
CASH_AT_TELLER (102, "cashAtTeller", GLAccountType.ASSET),OPENING_BALANCES_TRANSFER_CONTRA (300,"openingBalancesTransferContra",GLAccountType.EQUITY);;
|
||||
CASH_AT_TELLER (102, "cashAtTeller", GLAccountType.ASSET),OPENING_BALANCES_TRANSFER_CONTRA (300,"openingBalancesTransferContra",GLAccountType.EQUITY),
|
||||
ASSET_FUND_SOURCE(103, "fundSource", GLAccountType.ASSET);
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
+2
@@ -25,6 +25,8 @@ public interface AccountingDropdownReadPlatformService {
|
||||
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForSavingsProducts();
|
||||
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForCharges();
|
||||
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptions();
|
||||
|
||||
}
|
||||
+64
-27
@@ -58,42 +58,79 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop
|
||||
return retrieveAccountMappingOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForCharges() {
|
||||
// only get income and liability accounts
|
||||
boolean includeIncomeAccounts = true;
|
||||
boolean includeLiabilityAccounts = true;
|
||||
|
||||
boolean includeAssetAccounts = false;
|
||||
boolean includeExpenseAccounts = false;
|
||||
boolean includeEquityAccounts = false;
|
||||
|
||||
return retrieveAccountMappingOptions(includeAssetAccounts, includeIncomeAccounts, includeExpenseAccounts, includeLiabilityAccounts,
|
||||
includeEquityAccounts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<GLAccountData>> retrieveAccountMappingOptions() {
|
||||
boolean includeAssetAccounts = true;
|
||||
boolean includeIncomeAccounts = true;
|
||||
boolean includeExpenseAccounts = true;
|
||||
boolean includeLiabilityAccounts = true;
|
||||
boolean includeEquityAccounts = true;
|
||||
return retrieveAccountMappingOptions(includeAssetAccounts, includeIncomeAccounts, includeExpenseAccounts, includeLiabilityAccounts,
|
||||
includeEquityAccounts);
|
||||
}
|
||||
|
||||
private Map<String, List<GLAccountData>> retrieveAccountMappingOptions(boolean includeAssetAccounts, boolean includeIncomeAccounts,
|
||||
boolean includeExpenseAccounts, boolean includeLiabilityAccounts, boolean includeEquityAccounts) {
|
||||
final Map<String, List<GLAccountData>> accountOptions = new HashMap<>();
|
||||
List<GLAccountData> assetAccountOptions = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
if (assetAccountOptions.isEmpty()) {
|
||||
assetAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("assetAccountOptions", assetAccountOptions);
|
||||
|
||||
List<GLAccountData> incomeAccountOptions = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
|
||||
if (incomeAccountOptions.isEmpty()) {
|
||||
incomeAccountOptions = null;
|
||||
if (includeAssetAccounts) {
|
||||
List<GLAccountData> assetAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
if (assetAccountOptions.isEmpty()) {
|
||||
assetAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("assetAccountOptions", assetAccountOptions);
|
||||
}
|
||||
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
|
||||
|
||||
List<GLAccountData> expenseAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
if (expenseAccountOptions.isEmpty()) {
|
||||
expenseAccountOptions = null;
|
||||
if (includeIncomeAccounts) {
|
||||
List<GLAccountData> incomeAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
|
||||
if (incomeAccountOptions.isEmpty()) {
|
||||
incomeAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
|
||||
List<GLAccountData> liabilityAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.LIABILITY);
|
||||
if (liabilityAccountOptions.isEmpty()) {
|
||||
liabilityAccountOptions = null;
|
||||
if (includeExpenseAccounts) {
|
||||
List<GLAccountData> expenseAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
if (expenseAccountOptions.isEmpty()) {
|
||||
expenseAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
}
|
||||
|
||||
if (includeLiabilityAccounts) {
|
||||
List<GLAccountData> liabilityAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.LIABILITY);
|
||||
if (liabilityAccountOptions.isEmpty()) {
|
||||
liabilityAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("liabilityAccountOptions", liabilityAccountOptions);
|
||||
}
|
||||
|
||||
if (includeEquityAccounts) {
|
||||
List<GLAccountData> equityAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.EQUITY);
|
||||
if (equityAccountOptions.isEmpty()) {
|
||||
equityAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("equityAccountOptions", equityAccountOptions);
|
||||
}
|
||||
accountOptions.put("liabilityAccountOptions", liabilityAccountOptions);
|
||||
|
||||
List<GLAccountData> equityAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.EQUITY);
|
||||
if (equityAccountOptions.isEmpty()) {
|
||||
equityAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("equityAccountOptions",equityAccountOptions);
|
||||
|
||||
return accountOptions;
|
||||
}
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.mifosplatform.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class ClientChargePaymentDTO {
|
||||
|
||||
private final Long chargeId;
|
||||
private final BigDecimal amount;
|
||||
private final Long clientChargeId;
|
||||
private final boolean isPenalty;
|
||||
private final Long incomeAccountId;
|
||||
|
||||
public ClientChargePaymentDTO(Long chargeId, BigDecimal amount, Long clientChargeId, boolean isPenalty, Long incomeAccountId) {
|
||||
super();
|
||||
this.chargeId = chargeId;
|
||||
this.amount = amount;
|
||||
this.clientChargeId = clientChargeId;
|
||||
this.isPenalty = isPenalty;
|
||||
this.incomeAccountId = incomeAccountId;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public Long getClientChargeId() {
|
||||
return this.clientChargeId;
|
||||
}
|
||||
|
||||
public boolean isPenalty() {
|
||||
return this.isPenalty;
|
||||
}
|
||||
|
||||
public Long getChargeId() {
|
||||
return chargeId;
|
||||
}
|
||||
|
||||
public Long getIncomeAccountId() {
|
||||
return this.incomeAccountId;
|
||||
}
|
||||
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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 java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransactionType;
|
||||
|
||||
public class ClientTransactionDTO {
|
||||
|
||||
private final Long officeId;
|
||||
private final Long clientId;
|
||||
private String currencyCode;
|
||||
|
||||
private final Long transactionId;
|
||||
private final Date transactionDate;
|
||||
private final Long paymentTypeId;
|
||||
private final EnumOptionData transactionType;
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
private final Boolean accountingEnabled;
|
||||
|
||||
/*** Boolean values determines if the transaction is reversed ***/
|
||||
private final boolean reversed;
|
||||
|
||||
/** Breakdowns of fees this Transaction pays **/
|
||||
private final List<ClientChargePaymentDTO> chargePayments;
|
||||
|
||||
public ClientTransactionDTO(final Long clientId, final Long officeId, final Long paymentTypeId, final Long transactionId,
|
||||
final Date transactionDate, final EnumOptionData transactionType, final String currencyCode, final BigDecimal amount,
|
||||
final boolean reversed, final boolean accountingEnabled, final List<ClientChargePaymentDTO> clientChargePayments) {
|
||||
this.clientId = clientId;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
this.amount = amount;
|
||||
this.reversed = reversed;
|
||||
this.transactionType = transactionType;
|
||||
this.chargePayments = clientChargePayments;
|
||||
this.officeId = officeId;
|
||||
this.accountingEnabled = accountingEnabled;
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
public Long getOfficeId() {
|
||||
return this.officeId;
|
||||
}
|
||||
|
||||
public Date getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public Long getPaymentTypeId() {
|
||||
return this.paymentTypeId;
|
||||
}
|
||||
|
||||
public EnumOptionData getTransactionType() {
|
||||
return transactionType;
|
||||
}
|
||||
|
||||
public boolean isChargePayment() {
|
||||
return ClientTransactionType.PAY_CHARGE.getValue().equals(new Integer(this.transactionType.getId().intValue()));
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return this.currencyCode;
|
||||
}
|
||||
|
||||
public List<ClientChargePaymentDTO> getChargePayments() {
|
||||
return this.chargePayments;
|
||||
}
|
||||
|
||||
public Long getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
public Boolean getAccountingEnabled() {
|
||||
return this.accountingEnabled;
|
||||
}
|
||||
|
||||
public Long getClientId() {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-3
@@ -21,6 +21,7 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
@@ -60,6 +61,10 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@JoinColumn(name = "savings_transaction_id", nullable = false)
|
||||
private SavingsAccountTransaction savingsTransaction;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_transaction_id", nullable = false)
|
||||
private ClientTransaction clientTransaction;
|
||||
|
||||
@Column(name = "reversed", nullable = false)
|
||||
private boolean reversed = false;
|
||||
|
||||
@@ -92,10 +97,10 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
final String currencyCode, final String transactionId, final boolean manualEntry, final Date transactionDate,
|
||||
final JournalEntryType journalEntryType, final BigDecimal amount, final String description, final Integer entityType,
|
||||
final Long entityId, final String referenceNumber, final LoanTransaction loanTransaction,
|
||||
final SavingsAccountTransaction savingsTransaction) {
|
||||
final SavingsAccountTransaction savingsTransaction, final ClientTransaction clientTransaction) {
|
||||
return new JournalEntry(office, paymentDetail, glAccount, currencyCode, transactionId, manualEntry, transactionDate,
|
||||
journalEntryType.getValue(), amount, description, entityType, entityId, referenceNumber, loanTransaction,
|
||||
savingsTransaction);
|
||||
savingsTransaction, clientTransaction);
|
||||
}
|
||||
|
||||
protected JournalEntry() {
|
||||
@@ -105,7 +110,8 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public JournalEntry(final Office office, final PaymentDetail paymentDetail, final GLAccount glAccount, final String currencyCode,
|
||||
final String transactionId, final boolean manualEntry, final Date transactionDate, final Integer type, final BigDecimal amount,
|
||||
final String description, final Integer entityType, final Long entityId, final String referenceNumber,
|
||||
final LoanTransaction loanTransaction, final SavingsAccountTransaction savingsTransaction) {
|
||||
final LoanTransaction loanTransaction, final SavingsAccountTransaction savingsTransaction,
|
||||
final ClientTransaction clientTransaction) {
|
||||
this.office = office;
|
||||
this.glAccount = glAccount;
|
||||
this.reversalJournalEntry = null;
|
||||
@@ -122,6 +128,7 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.currencyCode = currencyCode;
|
||||
this.loanTransaction = loanTransaction;
|
||||
this.savingsTransaction = savingsTransaction;
|
||||
this.clientTransaction = clientTransaction;
|
||||
this.paymentDetail = paymentDetail;
|
||||
}
|
||||
|
||||
@@ -181,4 +188,8 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public ClientTransaction getClientTransaction() {
|
||||
return this.clientTransaction;
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.ClientTransactionDTO;
|
||||
|
||||
public interface AccountingProcessorForClientTransactions {
|
||||
|
||||
void createJournalEntriesForClientTransaction(ClientTransactionDTO clientTransactionDTO);
|
||||
}
|
||||
+186
-40
@@ -23,7 +23,10 @@ import org.mifosplatform.accounting.common.AccountingConstants.FINANCIAL_ACTIVIT
|
||||
import org.mifosplatform.accounting.financialactivityaccount.domain.FinancialActivityAccount;
|
||||
import org.mifosplatform.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper;
|
||||
import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.ClientChargePaymentDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.ClientTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
@@ -37,12 +40,15 @@ import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProd
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransaction;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransactionRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
@@ -58,12 +64,15 @@ public class AccountingProcessorHelper {
|
||||
|
||||
public static final String LOAN_TRANSACTION_IDENTIFIER = "L";
|
||||
public static final String SAVINGS_TRANSACTION_IDENTIFIER = "S";
|
||||
public static final String CLIENT_TRANSACTION_IDENTIFIER = "C";
|
||||
private final JournalEntryRepository glJournalEntryRepository;
|
||||
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository;
|
||||
private final GLClosureRepository closureRepository;
|
||||
private final GLAccountRepositoryWrapper accountRepositoryWrapper;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
private final ClientTransactionRepositoryWrapper clientTransactionRepository;
|
||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
||||
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||
|
||||
@@ -73,7 +82,9 @@ public class AccountingProcessorHelper {
|
||||
final OfficeRepository officeRepository, final LoanTransactionRepository loanTransactionRepository,
|
||||
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository,
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||
final GLAccountRepositoryWrapper accountRepositoryWrapper,
|
||||
final ClientTransactionRepositoryWrapper clientTransactionRepositoryWrapper) {
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
this.accountMappingRepository = accountMappingRepository;
|
||||
this.closureRepository = closureRepository;
|
||||
@@ -82,6 +93,8 @@ public class AccountingProcessorHelper {
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
this.financialActivityAccountRepository = financialActivityAccountRepository;
|
||||
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
||||
this.accountRepositoryWrapper = accountRepositoryWrapper;
|
||||
this.clientTransactionRepository = clientTransactionRepositoryWrapper;
|
||||
}
|
||||
|
||||
public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
@@ -202,6 +215,45 @@ public class AccountingProcessorHelper {
|
||||
accrualBasedAccountingEnabled, newSavingsTransactions);
|
||||
}
|
||||
|
||||
public ClientTransactionDTO populateClientTransactionDtoFromMap(final Map<String, Object> accountingBridgeData) {
|
||||
|
||||
final Long transactionOfficeId = (Long) accountingBridgeData.get("officeId");
|
||||
final Long clientId = (Long) accountingBridgeData.get("clientId");
|
||||
final Long transactionId = (Long) accountingBridgeData.get("id");
|
||||
final Date transactionDate = ((LocalDate) accountingBridgeData.get("date")).toDate();
|
||||
final EnumOptionData transactionType = (EnumOptionData) accountingBridgeData.get("type");
|
||||
final BigDecimal amount = (BigDecimal) accountingBridgeData.get("amount");
|
||||
final boolean reversed = (Boolean) accountingBridgeData.get("reversed");
|
||||
final Long paymentTypeId = (Long) accountingBridgeData.get("paymentTypeId");
|
||||
final String currencyCode = (String) accountingBridgeData.get("currencyCode");
|
||||
final Boolean accountingEnabled = (Boolean) accountingBridgeData.get("accountingEnabled");
|
||||
|
||||
final List<ClientChargePaymentDTO> clientChargePaymentDTOs = new ArrayList<>();
|
||||
// extract client charge payment details (if exists)
|
||||
if (accountingBridgeData.containsKey("clientChargesPaid")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> clientChargesPaidData = (List<Map<String, Object>>) accountingBridgeData
|
||||
.get("clientChargesPaid");
|
||||
for (final Map<String, Object> clientChargePaid : clientChargesPaidData) {
|
||||
final Long chargeId = (Long) clientChargePaid.get("chargeId");
|
||||
final Long clientChargeId = (Long) clientChargePaid.get("clientChargeId");
|
||||
final boolean isPenalty = (Boolean) clientChargePaid.get("isPenalty");
|
||||
final BigDecimal chargeAmountPaid = (BigDecimal) clientChargePaid.get("amount");
|
||||
final Long incomeAccountId = (Long) clientChargePaid.get("incomeAccountId");
|
||||
final ClientChargePaymentDTO clientChargePaymentDTO = new ClientChargePaymentDTO(chargeId, chargeAmountPaid, clientChargeId,
|
||||
isPenalty, incomeAccountId);
|
||||
clientChargePaymentDTOs.add(clientChargePaymentDTO);
|
||||
}
|
||||
}
|
||||
|
||||
final ClientTransactionDTO clientTransactionDTO = new ClientTransactionDTO(clientId, transactionOfficeId, paymentTypeId,
|
||||
transactionId, transactionDate, transactionType, currencyCode, amount, reversed, accountingEnabled,
|
||||
clientChargePaymentDTOs);
|
||||
|
||||
return clientTransactionDTO;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a pair of related Debits and Credits for
|
||||
* Accrual Based accounting.
|
||||
@@ -223,9 +275,8 @@ public class AccountingProcessorHelper {
|
||||
* @param isReversal
|
||||
*/
|
||||
public void createAccrualBasedJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId,
|
||||
final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount,
|
||||
final Boolean isReversal) {
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId,
|
||||
final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
int accountTypeToDebitId = accountTypeToBeDebited;
|
||||
int accountTypeToCreditId = accountTypeToBeCredited;
|
||||
// reverse debits and credits for reversals
|
||||
@@ -233,8 +284,8 @@ public class AccountingProcessorHelper {
|
||||
accountTypeToDebitId = accountTypeToBeCredited;
|
||||
accountTypeToCreditId = accountTypeToBeDebited;
|
||||
}
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, amount);
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,9 +405,8 @@ public class AccountingProcessorHelper {
|
||||
* @param isReversal
|
||||
*/
|
||||
public void createCashBasedJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode,
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId,
|
||||
final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount,
|
||||
final Boolean isReversal) {
|
||||
final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId,
|
||||
final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
int accountTypeToDebitId = accountTypeToBeDebited;
|
||||
int accountTypeToCreditId = accountTypeToBeCredited;
|
||||
// reverse debits and credits for reversals
|
||||
@@ -364,8 +414,8 @@ public class AccountingProcessorHelper {
|
||||
accountTypeToDebitId = accountTypeToBeCredited;
|
||||
accountTypeToCreditId = accountTypeToBeDebited;
|
||||
}
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId,
|
||||
loanId, transactionId, transactionDate, amount);
|
||||
createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
|
||||
transactionId, transactionDate, amount);
|
||||
}
|
||||
|
||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode,
|
||||
@@ -394,8 +444,9 @@ public class AccountingProcessorHelper {
|
||||
* transaction Date
|
||||
**/
|
||||
if (latestGLClosure != null) {
|
||||
if (latestGLClosure.getClosingDate().after(transactionDate) || latestGLClosure.getClosingDate().equals(transactionDate)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
|
||||
if (latestGLClosure.getClosingDate().after(transactionDate)
|
||||
|| latestGLClosure.getClosingDate().equals(transactionDate)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,21 +604,21 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForLoan(final Office office, final String currencyCode, final GLAccount account,
|
||||
final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
private void createCreditJournalEntryForClientPayments(final Office office, final String currencyCode, final GLAccount account,
|
||||
final Long clientId, final Long transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
ClientTransaction clientTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String modifiedTransactionId = transactionId;
|
||||
if (StringUtils.isNumeric(transactionId)) {
|
||||
long id = Long.parseLong(transactionId);
|
||||
loanTransaction = this.loanTransactionRepository.findOne(id);
|
||||
modifiedTransactionId = LOAN_TRANSACTION_IDENTIFIER + transactionId;
|
||||
}
|
||||
|
||||
clientTransaction = this.clientTransactionRepository.findOneWithNotFoundDetection(clientId, transactionId);
|
||||
|
||||
String modifiedTransactionId = transactionId.toString();
|
||||
modifiedTransactionId = CLIENT_TRANSACTION_IDENTIFIER + transactionId;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId, null,
|
||||
loanTransaction, savingsAccountTransaction);
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.CLIENT.getValue(), clientId, null,
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -576,6 +627,7 @@ public class AccountingProcessorHelper {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
ClientTransaction clientTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String modifiedTransactionId = transactionId;
|
||||
if (StringUtils.isNumeric(transactionId)) {
|
||||
@@ -585,7 +637,26 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId,
|
||||
null, loanTransaction, savingsAccountTransaction);
|
||||
null, loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForLoan(final Office office, final String currencyCode, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
ClientTransaction clientTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String modifiedTransactionId = transactionId;
|
||||
if (StringUtils.isNumeric(transactionId)) {
|
||||
long id = Long.parseLong(transactionId);
|
||||
loanTransaction = this.loanTransactionRepository.findOne(id);
|
||||
modifiedTransactionId = LOAN_TRANSACTION_IDENTIFIER + transactionId;
|
||||
}
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId, null,
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -594,6 +665,7 @@ public class AccountingProcessorHelper {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
ClientTransaction clientTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String modifiedTransactionId = transactionId;
|
||||
if (StringUtils.isNumeric(transactionId)) {
|
||||
@@ -603,7 +675,7 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId, null,
|
||||
loanTransaction, savingsAccountTransaction);
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -612,6 +684,7 @@ public class AccountingProcessorHelper {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
ClientTransaction clientTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
String modifiedTransactionId = transactionId;
|
||||
if (StringUtils.isNumeric(transactionId)) {
|
||||
@@ -620,8 +693,26 @@ public class AccountingProcessorHelper {
|
||||
modifiedTransactionId = SAVINGS_TRANSACTION_IDENTIFIER + transactionId;
|
||||
}
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId,
|
||||
null, loanTransaction, savingsAccountTransaction);
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null,
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryForClientPayments(final Office office, final String currencyCode, final GLAccount account,
|
||||
final Long clientId, final Long transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
ClientTransaction clientTransaction = null;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
|
||||
clientTransaction = this.clientTransactionRepository.findOneWithNotFoundDetection(clientId, transactionId);
|
||||
String modifiedTransactionId = transactionId.toString();
|
||||
modifiedTransactionId = CLIENT_TRANSACTION_IDENTIFIER + transactionId;
|
||||
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.CLIENT.getValue(), clientId, null,
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -659,12 +750,13 @@ public class AccountingProcessorHelper {
|
||||
private GLAccount getLinkedGLAccountForLoanCharges(final Long loanProductId, final int accountMappingTypeId, final Long chargeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
|
||||
PortfolioProductType.LOAN.getValue(), accountMappingTypeId);
|
||||
/*****
|
||||
* Get more specific mappings for Charges and penalties (based on the
|
||||
* actual charge /penalty coupled with the loan product). Note the
|
||||
* income from fees and income from penalties placeholder ID would be
|
||||
* the same for both cash and accrual based accounts
|
||||
*****/
|
||||
/*****
|
||||
* Get more specific mappings for Charges and penalties (based
|
||||
* on the actual charge /penalty coupled with the loan product).
|
||||
* Note the income from fees and income from penalties
|
||||
* placeholder ID would be the same for both cash and accrual
|
||||
* based accounts
|
||||
*****/
|
||||
|
||||
// Vishwas TODO: remove this condition as it should always be true
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue()
|
||||
@@ -679,15 +771,17 @@ public class AccountingProcessorHelper {
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForSavingsCharges(final Long savingsProductId, final int accountMappingTypeId, final Long chargeId) {
|
||||
private GLAccount getLinkedGLAccountForSavingsCharges(final Long savingsProductId, final int accountMappingTypeId,
|
||||
final Long chargeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId);
|
||||
/*****
|
||||
* Get more specific mappings for Charges and penalties (based on the
|
||||
* actual charge /penalty coupled with the loan product). Note the
|
||||
* income from fees and income from penalties placeholder ID would be
|
||||
* the same for both cash and accrual based accounts
|
||||
*****/
|
||||
/*****
|
||||
* Get more specific mappings for Charges and penalties (based
|
||||
* on the actual charge /penalty coupled with the loan product).
|
||||
* Note the income from fees and income from penalties
|
||||
* placeholder ID would be the same for both cash and accrual
|
||||
* based accounts
|
||||
*****/
|
||||
|
||||
// Vishwas TODO: remove this condition as it should always be true
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue()
|
||||
@@ -737,4 +831,56 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
return isOrganizationAccount;
|
||||
}
|
||||
|
||||
public BigDecimal createCreditJournalEntryOrReversalForClientPayments(final Office office, final String currencyCode,
|
||||
final Long clientId, final Long transactionId, final Date transactionDate, final Boolean isReversal,
|
||||
final List<ClientChargePaymentDTO> clientChargePaymentDTOs) {
|
||||
/***
|
||||
* Map to track each account affected and the net credit to be made for
|
||||
* a particular account
|
||||
***/
|
||||
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
||||
for (final ClientChargePaymentDTO clientChargePaymentDTO : clientChargePaymentDTOs) {
|
||||
if (clientChargePaymentDTO.getIncomeAccountId() != null) {
|
||||
final GLAccount chargeSpecificAccount = getGLAccountById(clientChargePaymentDTO.getIncomeAccountId());
|
||||
BigDecimal chargeSpecificAmount = clientChargePaymentDTO.getAmount();
|
||||
|
||||
// adjust net credit amount if the account is already present in
|
||||
// the map
|
||||
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
|
||||
final BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
|
||||
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
|
||||
}
|
||||
creditDetailsMap.put(chargeSpecificAccount, chargeSpecificAmount);
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
|
||||
for (final Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
|
||||
final GLAccount account = entry.getKey();
|
||||
final BigDecimal amount = entry.getValue();
|
||||
totalCreditedAmount = totalCreditedAmount.add(amount);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForClientPayments(office, currencyCode, account, clientId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createCreditJournalEntryForClientPayments(office, currencyCode, account, clientId, transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
return totalCreditedAmount;
|
||||
}
|
||||
|
||||
public void createDebitJournalEntryOrReversalForClientChargePayments(final Office office, final String currencyCode,
|
||||
final Long clientId, final Long transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) {
|
||||
final GLAccount account = financialActivityAccountRepository
|
||||
.findByFinancialActivityTypeWithNotFoundDetection(FINANCIAL_ACTIVITY.ASSET_FUND_SOURCE.getValue()).getGlAccount();
|
||||
if (isReversal) {
|
||||
createCreditJournalEntryForClientPayments(office, currencyCode, account, clientId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
createDebitJournalEntryForClientPayments(office, currencyCode, account, clientId, transactionId, transactionDate, amount);
|
||||
}
|
||||
}
|
||||
|
||||
private GLAccount getGLAccountById(final Long accountId) {
|
||||
return this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
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.journalentry.data.ClientTransactionDTO;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CashBasedAccountingProcessorForClientTransactions implements AccountingProcessorForClientTransactions {
|
||||
|
||||
AccountingProcessorHelper helper;
|
||||
|
||||
@Autowired
|
||||
public CashBasedAccountingProcessorForClientTransactions(final AccountingProcessorHelper accountingProcessorHelper) {
|
||||
this.helper = accountingProcessorHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForClientTransaction(ClientTransactionDTO clientTransactionDTO) {
|
||||
if (clientTransactionDTO.getAccountingEnabled()) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(clientTransactionDTO.getOfficeId());
|
||||
final Date transactionDate = clientTransactionDTO.getTransactionDate();
|
||||
final Office office = this.helper.getOfficeById(clientTransactionDTO.getOfficeId());
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
/** Handle client payments **/
|
||||
if (clientTransactionDTO.isChargePayment()) {
|
||||
createJournalEntriesForChargePayments(clientTransactionDTO, office);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single debit to fund source and multiple credits for the income
|
||||
* account mapped with each charge this payment pays off
|
||||
*
|
||||
* In case the loan transaction is a reversal, all debits are turned into
|
||||
* credits and vice versa
|
||||
*/
|
||||
private void createJournalEntriesForChargePayments(final ClientTransactionDTO clientTransactionDTO, final Office office) {
|
||||
// client properties
|
||||
final Long clientId = clientTransactionDTO.getClientId();
|
||||
|
||||
// transaction properties
|
||||
final String currencyCode = clientTransactionDTO.getCurrencyCode();
|
||||
final Long transactionId = clientTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = clientTransactionDTO.getTransactionDate();
|
||||
final BigDecimal amount = clientTransactionDTO.getAmount();
|
||||
final boolean isReversal = clientTransactionDTO.isReversed();
|
||||
|
||||
if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
BigDecimal totalCreditedAmount = this.helper.createCreditJournalEntryOrReversalForClientPayments(office, currencyCode, clientId,
|
||||
transactionId, transactionDate, isReversal, clientTransactionDTO.getChargePayments());
|
||||
|
||||
/***
|
||||
* create a single Debit entry (or reversal) for the entire amount
|
||||
* that was credited (accounting is turned on at the level of for
|
||||
* each charge that has been paid by this transaction)
|
||||
**/
|
||||
this.helper.createDebitJournalEntryOrReversalForClientChargePayments(office, currencyCode, clientId, transactionId,
|
||||
transactionDate, totalCreditedAmount, isReversal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -20,6 +20,8 @@ public interface JournalEntryWritePlatformService {
|
||||
|
||||
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
|
||||
|
||||
void createJournalEntriesForClientTransactions(Map<String, Object> accountingBridgeData);
|
||||
|
||||
CommandProcessingResult defineOpeningBalance(JsonCommand command);
|
||||
|
||||
|
||||
}
|
||||
|
||||
+43
-23
@@ -27,6 +27,7 @@ import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformServi
|
||||
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.ClientTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntry;
|
||||
@@ -52,6 +53,7 @@ import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransaction;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
@@ -82,6 +84,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final PlatformSecurityContext context;
|
||||
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper;
|
||||
private final CashBasedAccountingProcessorForClientTransactions accountingProcessorForClientTransactions;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
|
||||
@@ -93,7 +96,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final GLAccountReadPlatformService glAccountReadPlatformService,
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository, final PlatformSecurityContext context,
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) {
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper,
|
||||
final CashBasedAccountingProcessorForClientTransactions accountingProcessorForClientTransactions) {
|
||||
this.glClosureRepository = glClosureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
@@ -108,6 +112,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
this.context = context;
|
||||
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
|
||||
this.financialActivityAccountRepositoryWrapper = financialActivityAccountRepositoryWrapper;
|
||||
this.accountingProcessorForClientTransactions = accountingProcessorForClientTransactions;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -248,18 +253,21 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDebitAndCreditAmounts(final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits) {
|
||||
private void checkDebitAndCreditAmounts(final SingleDebitOrCreditEntryCommand[] credits,
|
||||
final SingleDebitOrCreditEntryCommand[] debits) {
|
||||
// sum of all debits must be = sum of all credits
|
||||
BigDecimal creditsSum = BigDecimal.ZERO;
|
||||
BigDecimal debitsSum = BigDecimal.ZERO;
|
||||
for (final SingleDebitOrCreditEntryCommand creditEntryCommand : credits) {
|
||||
if (creditEntryCommand.getAmount() == null || creditEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
|
||||
if (creditEntryCommand.getAmount() == null
|
||||
|| creditEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
|
||||
creditsSum = creditsSum.add(creditEntryCommand.getAmount());
|
||||
}
|
||||
for (final SingleDebitOrCreditEntryCommand debitEntryCommand : debits) {
|
||||
if (debitEntryCommand.getAmount() == null || debitEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
|
||||
if (debitEntryCommand.getAmount() == null
|
||||
|| debitEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
|
||||
debitsSum = debitsSum.add(debitEntryCommand.getAmount());
|
||||
}
|
||||
if (creditsSum.compareTo(debitsSum) != 0) { throw new JournalEntryInvalidException(
|
||||
@@ -283,8 +291,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
@Override
|
||||
public CommandProcessingResult revertJournalEntry(final JsonCommand command) {
|
||||
// is the transaction Id valid
|
||||
final List<JournalEntry> journalEntries = this.glJournalEntryRepository.findUnReversedManualJournalEntriesByTransactionId(command
|
||||
.getTransactionId());
|
||||
final List<JournalEntry> journalEntries = this.glJournalEntryRepository
|
||||
.findUnReversedManualJournalEntriesByTransactionId(command.getTransactionId());
|
||||
String reversalComment = command.stringValueOfParameterNamed("comments");
|
||||
|
||||
if (journalEntries.size() <= 1) { throw new JournalEntriesNotFoundException(command.getTransactionId()); }
|
||||
@@ -311,12 +319,14 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetails(),
|
||||
journalEntry.getGlAccount(), journalEntry.getCurrencyCode(), reversalTransactionId, manualEntry,
|
||||
journalEntry.getTransactionDate(), JournalEntryType.CREDIT, journalEntry.getAmount(), reversalComment, null, null,
|
||||
journalEntry.getReferenceNumber(), journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction());
|
||||
journalEntry.getReferenceNumber(), journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction(),
|
||||
journalEntry.getClientTransaction());
|
||||
} else {
|
||||
reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetails(),
|
||||
journalEntry.getGlAccount(), journalEntry.getCurrencyCode(), reversalTransactionId, manualEntry,
|
||||
journalEntry.getTransactionDate(), JournalEntryType.DEBIT, journalEntry.getAmount(), reversalComment, null, null,
|
||||
journalEntry.getReferenceNumber(), journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction());
|
||||
journalEntry.getReferenceNumber(), journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction(),
|
||||
journalEntry.getClientTransaction());
|
||||
}
|
||||
// save the reversal entry
|
||||
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
|
||||
@@ -384,8 +394,9 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
// shouldn't be before an accounting closure
|
||||
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(command.getOfficeId());
|
||||
if (latestGLClosure != null) {
|
||||
if (latestGLClosure.getClosingDate().after(transactionDate) || latestGLClosure.getClosingDate().equals(transactionDate)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
|
||||
if (latestGLClosure.getClosingDate().after(transactionDate)
|
||||
|| latestGLClosure.getClosingDate().equals(transactionDate)) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
|
||||
}
|
||||
|
||||
/*** check if credits and debits are valid **/
|
||||
@@ -393,16 +404,16 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
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); }
|
||||
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); }
|
||||
|
||||
checkDebitAndCreditAmounts(credits, debits);
|
||||
}
|
||||
|
||||
private void saveAllDebitOrCreditEntries(final JournalEntryCommand command, final Office office, final PaymentDetail paymentDetail,
|
||||
final String currencyCode, final Date transactionDate,
|
||||
final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, final String transactionId,
|
||||
final JournalEntryType type, final String referenceNumber) {
|
||||
final String currencyCode, final Date transactionDate, final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands,
|
||||
final String transactionId, final JournalEntryType type, final String referenceNumber) {
|
||||
final boolean manualEntry = true;
|
||||
for (final SingleDebitOrCreditEntryCommand singleDebitOrCreditEntryCommand : singleDebitOrCreditEntryCommands) {
|
||||
final GLAccount glAccount = this.glAccountRepository.findOne(singleDebitOrCreditEntryCommand.getGlAccountId());
|
||||
@@ -418,9 +429,10 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
/** Validate current code is appropriate **/
|
||||
this.organisationCurrencyRepository.findOneWithNotFoundDetection(currencyCode);
|
||||
|
||||
final ClientTransaction clientTransaction = null;
|
||||
final JournalEntry glJournalEntry = JournalEntry.createNew(office, paymentDetail, glAccount, currencyCode, transactionId,
|
||||
manualEntry, transactionDate, type, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, referenceNumber,
|
||||
null, null);
|
||||
null, null, clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(glJournalEntry);
|
||||
}
|
||||
}
|
||||
@@ -499,9 +511,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
}
|
||||
|
||||
private void saveAllDebitOrCreditOpeningBalanceEntries(final JournalEntryCommand command, final Office office,
|
||||
final String currencyCode, final Date transactionDate,
|
||||
final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, final String transactionId,
|
||||
final JournalEntryType type, final Long contraAccountId) {
|
||||
final String currencyCode, final Date transactionDate, final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands,
|
||||
final String transactionId, final JournalEntryType type, final Long contraAccountId) {
|
||||
|
||||
final boolean manualEntry = true;
|
||||
final GLAccount contraAccount = this.glAccountRepository.findOne(contraAccountId);
|
||||
@@ -526,12 +537,15 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
comments = singleDebitOrCreditEntryCommand.getComments();
|
||||
}
|
||||
|
||||
final ClientTransaction clientTransaction = null;
|
||||
final JournalEntry glJournalEntry = JournalEntry.createNew(office, null, glAccount, currencyCode, transactionId, manualEntry,
|
||||
transactionDate, type, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null);
|
||||
transactionDate, type, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null,
|
||||
clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(glJournalEntry);
|
||||
|
||||
final JournalEntry contraEntry = JournalEntry.createNew(office, null, contraAccount, currencyCode, transactionId, manualEntry,
|
||||
transactionDate, contraType, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null);
|
||||
transactionDate, contraType, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null,
|
||||
clientTransaction);
|
||||
this.glJournalEntryRepository.saveAndFlush(contraEntry);
|
||||
}
|
||||
}
|
||||
@@ -553,4 +567,10 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
"Defining Opening balances not allowed after journal entries posted", transactionIds); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForClientTransactions(Map<String, Object> accountingBridgeData) {
|
||||
final ClientTransactionDTO clientTransactionDTO = this.helper.populateClientTransactionDtoFromMap(accountingBridgeData);
|
||||
accountingProcessorForClientTransactions.createJournalEntriesForClientTransaction(clientTransactionDTO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-1
@@ -9,7 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PortfolioProductType {
|
||||
LOAN(1, "productType.loan"), SAVING(2, "productType.saving");
|
||||
LOAN(1, "productType.loan"), SAVING(2, "productType.saving"), CLIENT(2, "productType.client");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -33,6 +33,7 @@ public enum PortfolioProductType {
|
||||
}
|
||||
|
||||
private static final Map<Integer, PortfolioProductType> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final PortfolioProductType type : PortfolioProductType.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
@@ -52,4 +53,8 @@ public enum PortfolioProductType {
|
||||
return this.value.equals(PortfolioProductType.LOAN.getValue());
|
||||
}
|
||||
|
||||
public boolean isClient() {
|
||||
return this.value.equals(PortfolioProductType.CLIENT.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -39,6 +39,7 @@ import org.mifosplatform.organisation.teller.exception.CashierExistForTellerExce
|
||||
import org.mifosplatform.organisation.teller.exception.CashierNotFoundException;
|
||||
import org.mifosplatform.organisation.teller.exception.TellerNotFoundException;
|
||||
import org.mifosplatform.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransaction;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -177,8 +178,8 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
|
||||
Set<Cashier> isTellerIdPresentInCashier = teller.getCashiers();
|
||||
|
||||
for (final Cashier tellerIdInCashier : isTellerIdPresentInCashier) {
|
||||
if (tellerIdInCashier.getTeller().getId().toString().equalsIgnoreCase(tellerId.toString())) { throw new CashierExistForTellerException(
|
||||
tellerId); }
|
||||
if (tellerIdInCashier.getTeller().getId().toString()
|
||||
.equalsIgnoreCase(tellerId.toString())) { throw new CashierExistForTellerException(tellerId); }
|
||||
|
||||
}
|
||||
tellerRepository.delete(teller);
|
||||
@@ -407,6 +408,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
|
||||
final Long time = System.currentTimeMillis();
|
||||
final String uniqueVal = String.valueOf(time) + currentUser.getId() + cashierOffice.getId();
|
||||
final String transactionId = Long.toHexString(Long.parseLong(uniqueVal));
|
||||
ClientTransaction clientTransaction = null;
|
||||
|
||||
final JournalEntry debitJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment
|
||||
// detail
|
||||
@@ -415,7 +417,8 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
|
||||
transactionId, false, // manual entry
|
||||
cashierTxn.getTxnDate(), JournalEntryType.DEBIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description
|
||||
null, null, null, // entity Type, entityId, reference number
|
||||
null, null); // Loan and Savings Txn
|
||||
null, null, clientTransaction); // Loan and Savings Txn
|
||||
|
||||
final JournalEntry creditJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment
|
||||
// detail
|
||||
creditAccount, "USD", // FIXME: Take currency code from the
|
||||
@@ -423,7 +426,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
|
||||
transactionId, false, // manual entry
|
||||
cashierTxn.getTxnDate(), JournalEntryType.CREDIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description
|
||||
null, null, null, // entity Type, entityId, reference number
|
||||
null, null); // Loan and Savings Txn
|
||||
null, null, clientTransaction); // Loan and Savings Txn
|
||||
|
||||
this.glJournalEntryRepository.saveAndFlush(debitJournalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(creditJournalEntry);
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.mifosplatform.portfolio.charge.api;
|
||||
|
||||
public class ChargesApiConstants {
|
||||
|
||||
public static final String glAccountIdParamName = "incomeAccountId";
|
||||
|
||||
}
|
||||
+5
-4
@@ -41,10 +41,11 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("singleton")
|
||||
public class ChargesApiResource {
|
||||
|
||||
private final Set<String> CHARGES_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "name", "amount", "currency", "penalty",
|
||||
"active", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions",
|
||||
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions", "loanChargeCalculationTypeOptions",
|
||||
"loanChargeTimeTypeOptions", "savingsChargeCalculationTypeOptions", "savingsChargeTimeTypeOptions"));
|
||||
private final Set<String> CHARGES_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "name", "amount", "currency", "penalty", "active",
|
||||
"chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "chargeAppliesToOptions",
|
||||
"chargeTimeTypeOptions", "currencyOptions", "loanChargeCalculationTypeOptions", "loanChargeTimeTypeOptions",
|
||||
"savingsChargeCalculationTypeOptions", "savingsChargeTimeTypeOptions", "incomeAccount", "clientChargeCalculationTypeOptions",
|
||||
"clientChargeTimeTypeOptions"));
|
||||
|
||||
private final String resourceNameForPermissions = "CHARGE";
|
||||
|
||||
|
||||
+24
-8
@@ -9,9 +9,11 @@ import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||
@@ -38,6 +40,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
private final BigDecimal minCap;
|
||||
private final BigDecimal maxCap;
|
||||
private final EnumOptionData feeFrequency;
|
||||
private final GLAccountData incomeOrLiabilityAccount;
|
||||
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
private final List<EnumOptionData> chargeCalculationTypeOptions;//
|
||||
@@ -53,18 +56,21 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
private final List<EnumOptionData> clientChargeTimeTypeOptions;
|
||||
private final List<EnumOptionData> feeFrequencyOptions;
|
||||
|
||||
private final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions;
|
||||
|
||||
public static ChargeData template(final Collection<CurrencyData> currencyOptions,
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
||||
final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargePaymentModeOptions,
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions, final List<EnumOptionData> loansChargeTimeTypeOptions,
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions, final List<EnumOptionData> savingsChargeTimeTypeOptions,
|
||||
final List<EnumOptionData> clientChargeCalculationTypeOptions, final List<EnumOptionData> clientChargeTimeTypeOptions,
|
||||
final List<EnumOptionData> feeFrequencyOptions) {
|
||||
|
||||
final List<EnumOptionData> feeFrequencyOptions, final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions) {
|
||||
final GLAccountData account = null;
|
||||
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
|
||||
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions,
|
||||
loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions,
|
||||
clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, null, null, null, null, null, feeFrequencyOptions);
|
||||
clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, null, null, null, null, null, feeFrequencyOptions, account,
|
||||
incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
|
||||
@@ -74,13 +80,15 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions,
|
||||
template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions,
|
||||
template.clientChargeCalculationTypeOptions, template.clientChargeTimeTypeOptions, charge.feeOnMonthDay, charge.feeInterval,
|
||||
charge.minCap, charge.maxCap, charge.feeFrequency, template.feeFrequencyOptions);
|
||||
charge.minCap, charge.maxCap, charge.feeFrequency, template.feeFrequencyOptions, charge.incomeOrLiabilityAccount,
|
||||
template.incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
||||
final EnumOptionData chargePaymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final boolean penalty,
|
||||
final boolean active, final BigDecimal minCap, final BigDecimal maxCap, final EnumOptionData feeFrequency) {
|
||||
final boolean active, final BigDecimal minCap, final BigDecimal maxCap, final EnumOptionData feeFrequency,
|
||||
final GLAccountData accountData) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions = null;
|
||||
@@ -94,12 +102,14 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final List<EnumOptionData> feeFrequencyOptions = null;
|
||||
final List<EnumOptionData> clientChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions = null;
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions,
|
||||
clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, feeFrequencyOptions);
|
||||
clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, feeFrequencyOptions, accountData,
|
||||
incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
|
||||
@@ -128,12 +138,15 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions = null;
|
||||
final EnumOptionData feeFrequency = null;
|
||||
final List<EnumOptionData> feeFrequencyOptions = null;
|
||||
final GLAccountData account = null;
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions,
|
||||
clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, feeFrequencyOptions);
|
||||
clientChargeTimeTypeOptions, feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, feeFrequencyOptions, account,
|
||||
incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
@@ -146,7 +159,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions, final List<EnumOptionData> clientChargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions, final MonthDay feeOnMonthDay, final Integer feeInterval,
|
||||
final BigDecimal minCap, final BigDecimal maxCap, final EnumOptionData feeFrequency,
|
||||
final List<EnumOptionData> feeFrequencyOptions) {
|
||||
final List<EnumOptionData> feeFrequencyOptions, final GLAccountData account,
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
@@ -174,6 +188,8 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
this.loanChargeTimeTypeOptions = loansChargeTimeTypeOptions;
|
||||
this.feeFrequency = feeFrequency;
|
||||
this.feeFrequencyOptions = feeFrequencyOptions;
|
||||
this.incomeOrLiabilityAccount = account;
|
||||
this.incomeOrLiabilityAccountOptions = incomeOrLiabilityAccountOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+40
-4
@@ -13,18 +13,24 @@ import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.api.ChargesApiConstants;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeMustBePenaltyException;
|
||||
@@ -85,7 +91,11 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
@Column(name = "fee_frequency", nullable = true)
|
||||
private Integer feeFrequency;
|
||||
|
||||
public static Charge fromJson(final JsonCommand command) {
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "income_or_liability_account_id")
|
||||
private GLAccount account;
|
||||
|
||||
public static Charge fromJson(final JsonCommand command, final GLAccount account) {
|
||||
|
||||
final String name = command.stringValueOfParameterNamed("name");
|
||||
final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
|
||||
@@ -108,7 +118,7 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
final Integer feeFrequency = command.integerValueOfParameterNamed("feeFrequency");
|
||||
|
||||
return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode,
|
||||
feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency);
|
||||
feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, account);
|
||||
}
|
||||
|
||||
protected Charge() {
|
||||
@@ -118,7 +128,7 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active,
|
||||
final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final BigDecimal minCap,
|
||||
final BigDecimal maxCap, final Integer feeFrequency) {
|
||||
final BigDecimal maxCap, final Integer feeFrequency, final GLAccount account) {
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
this.currencyCode = currencyCode;
|
||||
@@ -127,6 +137,7 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
this.chargeCalculation = chargeCalculationType.getValue();
|
||||
this.penalty = penalty;
|
||||
this.active = active;
|
||||
this.account = account;
|
||||
this.chargePaymentMode = paymentMode == null ? null : paymentMode.getValue();
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
@@ -461,6 +472,11 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(this.name); }
|
||||
if (!penalty && ChargeTimeType.fromInt(this.chargeTime).isOverdueInstallment()) { throw new ChargeMustBePenaltyException(name); }
|
||||
|
||||
if (command.isChangeInLongParameterNamed(ChargesApiConstants.glAccountIdParamName, getIncomeAccountId())) {
|
||||
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
|
||||
actualChanges.put(ChargesApiConstants.glAccountIdParamName, newValue);
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
return actualChanges;
|
||||
@@ -484,10 +500,14 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
||||
final EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
|
||||
final EnumOptionData feeFrequencyType = ChargeEnumerations.chargePaymentMode(this.feeFrequency);
|
||||
GLAccountData accountData = null;
|
||||
if (account != null) {
|
||||
accountData = new GLAccountData(account.getId(), account.getName(), account.getGlCode());
|
||||
}
|
||||
final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
|
||||
return ChargeData.instance(getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
|
||||
chargePaymentmode, getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active, this.minCap, this.maxCap,
|
||||
feeFrequencyType);
|
||||
feeFrequencyType, accountData);
|
||||
}
|
||||
|
||||
public Integer getChargePaymentMode() {
|
||||
@@ -525,4 +545,20 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
public Integer feeFrequency() {
|
||||
return this.feeFrequency;
|
||||
}
|
||||
|
||||
public GLAccount getAccount() {
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public void setAccount(GLAccount account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
private Long getIncomeAccountId() {
|
||||
Long incomeAccountId = null;
|
||||
if (this.account != null) {
|
||||
incomeAccountId = this.account.getId();
|
||||
}
|
||||
return incomeAccountId;
|
||||
}
|
||||
}
|
||||
+20
-7
@@ -23,6 +23,7 @@ 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.charge.api.ChargesApiConstants;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||
@@ -39,9 +40,10 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("name", "amount", "locale", "currencyCode",
|
||||
"currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
|
||||
"active", "chargePaymentMode", "feeOnMonthDay", "feeInterval", "monthDayFormat", "minCap", "maxCap", "feeFrequency"));
|
||||
private final Set<String> supportedParameters = new HashSet<>(
|
||||
Arrays.asList("name", "amount", "locale", "currencyCode", "currencyOptions", "chargeAppliesTo", "chargeTimeType",
|
||||
"chargeCalculationType", "chargeCalculationTypeOptions", "penalty", "active", "chargePaymentMode", "feeOnMonthDay",
|
||||
"feeInterval", "monthDayFormat", "minCap", "maxCap", "feeFrequency", ChargesApiConstants.glAccountIdParamName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -145,13 +147,18 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
.isOneOfTheseValues(ChargeTimeType.validClientValues());
|
||||
}
|
||||
|
||||
// final ChargeTimeType ctt =
|
||||
// ChargeTimeType.fromInt(chargeTimeType);
|
||||
|
||||
if (chargeCalculationType != null) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType)
|
||||
.isOneOfTheseValues(ChargeCalculationType.validValuesForSavings());
|
||||
.isOneOfTheseValues(ChargeCalculationType.validValuesForClients());
|
||||
}
|
||||
|
||||
// GL Account can be linked to clients
|
||||
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) {
|
||||
final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element);
|
||||
baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull()
|
||||
.longGreaterThanZero();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", element);
|
||||
@@ -286,6 +293,12 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("feeFrequency").value(feeFrequency).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) {
|
||||
final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element);
|
||||
baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull()
|
||||
.longGreaterThanZero();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
|
||||
+24
-5
@@ -11,8 +11,11 @@ import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
@@ -45,16 +48,19 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
|
||||
private final DropdownReadPlatformService dropdownReadPlatformService;
|
||||
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public ChargeReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService,
|
||||
final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
|
||||
final DropdownReadPlatformService dropdownReadPlatformService, final MifosEntityAccessUtil mifosEntityAccessUtil) {
|
||||
final DropdownReadPlatformService dropdownReadPlatformService, final MifosEntityAccessUtil mifosEntityAccessUtil,
|
||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) {
|
||||
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.currencyReadPlatformService = currencyReadPlatformService;
|
||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,11 +124,13 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
.retrieveClientCalculationTypes();
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveClientCollectionTimeTypes();
|
||||
final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = this.accountingDropdownReadPlatformService
|
||||
.retrieveAccountMappingOptionsForCharges();
|
||||
|
||||
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
|
||||
allowedChargeTimeOptions, chargePaymentOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions,
|
||||
clientChargeTimeTypeOptions, feeFrequencyOptions);
|
||||
clientChargeTimeTypeOptions, feeFrequencyOptions, incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -245,8 +253,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
+ "c.is_active as active, oc.name as currencyName, oc.decimal_places as currencyDecimalPlaces, "
|
||||
+ "oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||
+ "oc.internationalized_name_code as currencyNameCode, c.fee_on_day as feeOnDay, c.fee_on_month as feeOnMonth, "
|
||||
+ "c.fee_interval as feeInterval, c.fee_frequency as feeFrequency,c.min_cap as minCap,c.max_cap as maxCap "
|
||||
+ "from m_charge c " + "join m_organisation_currency oc on c.currency_code = oc.code";
|
||||
+ "c.fee_interval as feeInterval, c.fee_frequency as feeFrequency,c.min_cap as minCap,c.max_cap as maxCap, "
|
||||
+ "c.income_or_liability_account_id as glAccountId , acc.name as glAccountName, acc.gl_code as glCode "
|
||||
+ "from m_charge c " + "join m_organisation_currency oc on c.currency_code = oc.code "
|
||||
+ " LEFT JOIN acc_gl_account acc on acc.id = c.income_or_liability_account_id ";
|
||||
}
|
||||
|
||||
public String loanProductChargeSchema() {
|
||||
@@ -303,8 +313,17 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
final BigDecimal minCap = rs.getBigDecimal("minCap");
|
||||
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
|
||||
|
||||
// extract GL Account
|
||||
final Long glAccountId = JdbcSupport.getLong(rs, "glAccountId");
|
||||
final String glAccountName = rs.getString("glAccountName");
|
||||
final String glCode = rs.getString("glCode");
|
||||
GLAccountData glAccountData = null;
|
||||
if (glAccountId != null) {
|
||||
glAccountData = new GLAccountData(glAccountId, glAccountName, glCode);
|
||||
}
|
||||
|
||||
return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType,
|
||||
chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active, minCap, maxCap, feeFrequencyType);
|
||||
chargePaymentMode, feeOnMonthDay, feeInterval, penalty, active, minCap, maxCap, feeFrequencyType, glAccountData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+40
-17
@@ -10,6 +10,8 @@ import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -19,6 +21,7 @@ import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessTyp
|
||||
import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType;
|
||||
import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.charge.api.ChargesApiConstants;
|
||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepository;
|
||||
import org.mifosplatform.portfolio.charge.exception.ChargeCannotBeDeletedException;
|
||||
@@ -47,20 +50,21 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
|
||||
private final ChargeRepository chargeRepository;
|
||||
private final LoanProductRepository loanProductRepository;
|
||||
private final MifosEntityAccessUtil mifosEntityAccessUtil;
|
||||
private final GLAccountRepositoryWrapper gLAccountRepository;
|
||||
|
||||
@Autowired
|
||||
public ChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final ChargeRepository chargeRepository, final LoanProductRepository loanProductRepository, final RoutingDataSource dataSource,
|
||||
final MifosEntityAccessUtil mifosEntityAccessUtil
|
||||
) {
|
||||
this.context = context;
|
||||
final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, final ChargeRepository chargeRepository,
|
||||
final LoanProductRepository loanProductRepository, final RoutingDataSource dataSource,
|
||||
final MifosEntityAccessUtil mifosEntityAccessUtil, final GLAccountRepositoryWrapper glAccountRepository) {
|
||||
this.context = context;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.dataSource = dataSource;
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.loanProductRepository = loanProductRepository;
|
||||
this.mifosEntityAccessUtil = mifosEntityAccessUtil;
|
||||
this.gLAccountRepository = glAccountRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -68,18 +72,25 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
|
||||
@CacheEvict(value = "charges", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')")
|
||||
public CommandProcessingResult createCharge(final JsonCommand command) {
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.context.authenticatedUser();
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final Charge charge = Charge.fromJson(command);
|
||||
// Retrieve linked GLAccount for Client charges (if present)
|
||||
final Long glAccountId = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
|
||||
|
||||
GLAccount glAccount = null;
|
||||
if (glAccountId != null) {
|
||||
glAccount = this.gLAccountRepository.findOneWithNotFoundDetection(glAccountId);
|
||||
}
|
||||
|
||||
final Charge charge = Charge.fromJson(command, glAccount);
|
||||
this.chargeRepository.save(charge);
|
||||
|
||||
// check if the office specific products are enabled. If yes, then save this savings product against a specific office
|
||||
// check if the office specific products are enabled. If yes, then
|
||||
// save this savings product against a specific office
|
||||
// i.e. this savings product is specific for this office.
|
||||
mifosEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice(
|
||||
MifosEntityAccessType.OFFICE_ACCESS_TO_CHARGES,
|
||||
MifosEntityType.CHARGE,
|
||||
charge.getId());
|
||||
mifosEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice(MifosEntityAccessType.OFFICE_ACCESS_TO_CHARGES,
|
||||
MifosEntityType.CHARGE, charge.getId());
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(charge.getId()).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
@@ -114,10 +125,21 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
|
||||
if (isChargeExistWithLoans || isChargeExistWithSavings) { throw new ChargeCannotBeUpdatedException(
|
||||
"error.msg.charge.cannot.be.updated.it.is.used.in.loan", "This charge cannot be updated, it is used in loan"); }
|
||||
}
|
||||
}else if((changes.containsKey("feeFrequency") || changes.containsKey("feeInterval")) && chargeForUpdate.isLoanCharge()){
|
||||
} else if ((changes.containsKey("feeFrequency") || changes.containsKey("feeInterval")) && chargeForUpdate.isLoanCharge()) {
|
||||
final Boolean isChargeExistWithLoans = isAnyLoanProductsAssociateWithThisCharge(chargeId);
|
||||
if (isChargeExistWithLoans) { throw new ChargeCannotBeUpdatedException(
|
||||
"error.msg.charge.frequency.cannot.be.updated.it.is.used.in.loan", "This charge frequency cannot be updated, it is used in loan"); }
|
||||
"error.msg.charge.frequency.cannot.be.updated.it.is.used.in.loan",
|
||||
"This charge frequency cannot be updated, it is used in loan"); }
|
||||
}
|
||||
|
||||
// Has account Id been changed ?
|
||||
if (changes.containsKey(ChargesApiConstants.glAccountIdParamName)) {
|
||||
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
|
||||
GLAccount newIncomeAccount = null;
|
||||
if (newValue != null) {
|
||||
newIncomeAccount = this.gLAccountRepository.findOneWithNotFoundDetection(newValue);
|
||||
}
|
||||
chargeForUpdate.setAccount(newIncomeAccount);
|
||||
}
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
@@ -144,9 +166,10 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP
|
||||
final Boolean isChargeExistWithSavings = isAnySavingsAssociateWithThisCharge(chargeId);
|
||||
|
||||
// TODO: Change error messages around:
|
||||
if (!loanProducts.isEmpty() || isChargeExistWithLoans || isChargeExistWithSavings) { throw new ChargeCannotBeDeletedException(
|
||||
"error.msg.charge.cannot.be.deleted.it.is.already.used.in.loan",
|
||||
"This charge cannot be deleted, it is already used in loan"); }
|
||||
if (!loanProducts.isEmpty() || isChargeExistWithLoans
|
||||
|| isChargeExistWithSavings) { throw new ChargeCannotBeDeletedException(
|
||||
"error.msg.charge.cannot.be.deleted.it.is.already.used.in.loan",
|
||||
"This charge cannot be deleted, it is already used in loan"); }
|
||||
|
||||
chargeForDelete.delete();
|
||||
|
||||
|
||||
+5
@@ -59,6 +59,11 @@ public class ClientChargePaidBy extends AbstractPersistable<Long> {
|
||||
|
||||
public void setClientCharge(ClientCharge clientCharge) {
|
||||
this.clientCharge = clientCharge;
|
||||
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+58
@@ -6,8 +6,12 @@
|
||||
package org.mifosplatform.portfolio.client.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
@@ -25,6 +29,8 @@ import javax.persistence.UniqueConstraint;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
@@ -123,6 +129,54 @@ public class ClientTransaction extends AbstractPersistable<Long> {
|
||||
this.reversed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the content of this Client Transaction to a map which can be
|
||||
* passed to the accounting module
|
||||
*
|
||||
* @param currencyData
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> toMapData() {
|
||||
final Map<String, Object> thisTransactionData = new LinkedHashMap<>();
|
||||
|
||||
final EnumOptionData transactionType = ClientEnumerations.clientTransactionType(this.typeOf);
|
||||
Boolean accountingEnabledForAtleastOneCharge = false;
|
||||
|
||||
thisTransactionData.put("id", getId());
|
||||
thisTransactionData.put("officeId", this.office.getId());
|
||||
thisTransactionData.put("type", transactionType);
|
||||
thisTransactionData.put("reversed", Boolean.valueOf(this.reversed));
|
||||
thisTransactionData.put("date", getTransactionDate());
|
||||
thisTransactionData.put("currencyCode", this.currencyCode);
|
||||
thisTransactionData.put("amount", this.amount);
|
||||
|
||||
if (this.paymentDetail != null) {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
}
|
||||
|
||||
if (!this.clientChargePaidByCollection.isEmpty()) {
|
||||
final List<Map<String, Object>> clientChargesPaidData = new ArrayList<>();
|
||||
for (final ClientChargePaidBy clientChargePaidBy : this.clientChargePaidByCollection) {
|
||||
final Map<String, Object> clientChargePaidData = new LinkedHashMap<>();
|
||||
clientChargePaidData.put("chargeId", clientChargePaidBy.getClientCharge().getCharge().getId());
|
||||
clientChargePaidData.put("isPenalty", clientChargePaidBy.getClientCharge().getCharge().isPenalty());
|
||||
clientChargePaidData.put("clientChargeId", clientChargePaidBy.getClientCharge().getId());
|
||||
clientChargePaidData.put("amount", clientChargePaidBy.getAmount());
|
||||
GLAccount glAccount = clientChargePaidBy.getClientCharge().getCharge().getAccount();
|
||||
if (glAccount != null) {
|
||||
accountingEnabledForAtleastOneCharge = true;
|
||||
clientChargePaidData.put("incomeAccountId", glAccount.getId());
|
||||
}
|
||||
clientChargesPaidData.add(clientChargePaidData);
|
||||
}
|
||||
thisTransactionData.put("clientChargesPaid", clientChargesPaidData);
|
||||
}
|
||||
|
||||
thisTransactionData.put("accountingEnabled", accountingEnabledForAtleastOneCharge);
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
|
||||
public boolean isPayChargeTransaction() {
|
||||
return ClientTransactionType.PAY_CHARGE.getValue().equals(this.typeOf);
|
||||
}
|
||||
@@ -159,4 +213,8 @@ public class ClientTransaction extends AbstractPersistable<Long> {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return new LocalDate(this.dateOf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-3
@@ -15,6 +15,7 @@ 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.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
@@ -58,6 +59,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
private final ClientChargeRepositoryWrapper clientChargeRepository;
|
||||
private final ClientTransactionRepository clientTransactionRepository;
|
||||
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public ClientChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -65,7 +67,8 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
final ClientRepositoryWrapper clientRepository, final HolidayRepositoryWrapper holidayRepositoryWrapper,
|
||||
final ConfigurationDomainService configurationDomainService, final ClientChargeRepositoryWrapper clientChargeRepository,
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository, final ClientTransactionRepository clientTransactionRepository,
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService) {
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.context = context;
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.clientChargeDataValidator = clientChargeDataValidator;
|
||||
@@ -76,6 +79,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
this.clientTransactionRepository = clientTransactionRepository;
|
||||
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,12 +138,15 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
|
||||
ClientTransaction clientTransaction = ClientTransaction.payCharge(client, client.getOffice(), paymentDetail, transactionDate,
|
||||
chargePaid, clientCharge.getCurrency().getCode(), getAppUserIfPresent());
|
||||
this.clientTransactionRepository.save(clientTransaction);
|
||||
this.clientTransactionRepository.saveAndFlush(clientTransaction);
|
||||
|
||||
// update charge paid by associations
|
||||
final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, amountPaid);
|
||||
clientTransaction.getClientChargePaidByCollection().add(chargePaidBy);
|
||||
|
||||
// generate accounting entries
|
||||
generateAccountingEntries(clientTransaction);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(clientCharge.getId()) //
|
||||
.withOfficeId(clientCharge.getClient().getOffice().getId()) //
|
||||
@@ -148,6 +155,11 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
|
||||
}
|
||||
|
||||
private void generateAccountingEntries(ClientTransaction clientTransaction) {
|
||||
Map<String, Object> accountingBridgeData = clientTransaction.toMapData();
|
||||
journalEntryWritePlatformService.createJournalEntriesForClientTransactions(accountingBridgeData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult waiveCharge(Long clientId, Long clientChargeId) {
|
||||
final Client client = this.clientRepository.getActiveClient(clientId);
|
||||
@@ -294,7 +306,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
*/
|
||||
@Override
|
||||
public CommandProcessingResult updateCharge(Long clientId, JsonCommand command) {
|
||||
this.clientChargeDataValidator.validateAdd(command.json());
|
||||
// this.clientChargeDataValidator.validateAdd(command.json());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
|
||||
@@ -27,14 +29,17 @@ public class ClientTransactionWritePlatformServiceJpaRepositoryImpl implements C
|
||||
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public ClientTransactionWritePlatformServiceJpaRepositoryImpl(final ClientTransactionRepositoryWrapper clientTransactionRepository,
|
||||
final ClientRepositoryWrapper clientRepositoryWrapper,
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepositoryWrapper) {
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepositoryWrapper,
|
||||
JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.clientTransactionRepository = clientTransactionRepository;
|
||||
this.clientRepository = clientRepositoryWrapper;
|
||||
this.organisationCurrencyRepository = organisationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,6 +71,10 @@ public class ClientTransactionWritePlatformServiceJpaRepositoryImpl implements C
|
||||
}
|
||||
}
|
||||
|
||||
// generate accounting entries
|
||||
this.clientTransactionRepository.saveAndFlush(clientTransaction);
|
||||
generateAccountingEntries(clientTransaction);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(transactionId) //
|
||||
.withOfficeId(client.officeId()) //
|
||||
@@ -73,4 +82,9 @@ public class ClientTransactionWritePlatformServiceJpaRepositoryImpl implements C
|
||||
.build();
|
||||
}
|
||||
|
||||
private void generateAccountingEntries(ClientTransaction clientTransaction) {
|
||||
Map<String, Object> accountingBridgeData = clientTransaction.toMapData();
|
||||
journalEntryWritePlatformService.createJournalEntriesForClientTransactions(accountingBridgeData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-1
@@ -15,6 +15,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
@@ -133,10 +134,13 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions = null;
|
||||
|
||||
final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
|
||||
// this field is applicable only for client charges
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
||||
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions);
|
||||
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions,
|
||||
incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
-1
@@ -10,9 +10,11 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
@@ -142,11 +144,14 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
final List<EnumOptionData> clientChargeTimeTypeOptions = null;
|
||||
|
||||
final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();
|
||||
// this field is applicable only for client charges
|
||||
final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null;
|
||||
|
||||
// TODO AA : revisit for merge conflict - Not sure method signature
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions);
|
||||
savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions,
|
||||
incomeOrLiabilityAccountOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- Charges have a reference to an Income or Liability account that gets credited when a payment is made
|
||||
ALTER TABLE `m_charge`
|
||||
ADD COLUMN `income_or_liability_account_id` BIGINT(20) NULL AFTER `fee_frequency`,
|
||||
ADD CONSTRAINT `FK_m_charge_acc_gl_account` FOREIGN KEY (`income_or_liability_account_id`) REFERENCES `acc_gl_account` (`id`);
|
||||
|
||||
--Journal entries also refer to Client transactions
|
||||
ALTER TABLE `acc_gl_journal_entry`
|
||||
ADD COLUMN `client_transaction_id` BIGINT(20) NULL DEFAULT NULL AFTER `savings_transaction_id`,
|
||||
ADD CONSTRAINT `FK_acc_gl_journal_entry_m_client_transaction` FOREIGN KEY (`client_transaction_id`) REFERENCES `m_client_transaction` (`id`);
|
||||
Reference in New Issue
Block a user