wip:initial work for accrual accounting and refactoring
This commit is contained in:
-143
@@ -1,143 +0,0 @@
|
||||
/**
|
||||
* 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.glaccount.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
public class LoanTransactionDTO {
|
||||
|
||||
private String transactionId;
|
||||
private Date transactionDate;
|
||||
|
||||
private BigDecimal amount;
|
||||
/*** Breakup of amounts in case of repayments **/
|
||||
private BigDecimal principal;
|
||||
private BigDecimal interest;
|
||||
private BigDecimal fees;
|
||||
private BigDecimal penalties;
|
||||
|
||||
/*** Boolean values determine type of loan transaction ***/
|
||||
private boolean disbursement;
|
||||
private boolean repayment;
|
||||
private boolean repaymentAtDisbursement;
|
||||
private boolean contra;
|
||||
private boolean writeOff;
|
||||
|
||||
public LoanTransactionDTO(final String transactionId, final Date transactionDate, final BigDecimal amount, final BigDecimal principal,
|
||||
final BigDecimal interest, final BigDecimal fees, final BigDecimal penalties, final boolean disbursement,
|
||||
final boolean repayment, final boolean repaymentAtDisbursement, final boolean contra, final boolean writeOff) {
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
this.amount = amount;
|
||||
this.principal = principal;
|
||||
this.interest = interest;
|
||||
this.fees = fees;
|
||||
this.penalties = penalties;
|
||||
this.disbursement = disbursement;
|
||||
this.repayment = repayment;
|
||||
this.repaymentAtDisbursement = repaymentAtDisbursement;
|
||||
this.contra = contra;
|
||||
this.writeOff = writeOff;
|
||||
}
|
||||
|
||||
public Date getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public void setTransactionDate(final Date transactionDate) {
|
||||
this.transactionDate = transactionDate;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(final String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public void setAmount(final BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public void setPrincipal(final BigDecimal principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public BigDecimal getInterest() {
|
||||
return this.interest;
|
||||
}
|
||||
|
||||
public void setInterest(final BigDecimal interest) {
|
||||
this.interest = interest;
|
||||
}
|
||||
|
||||
public BigDecimal getFees() {
|
||||
return this.fees;
|
||||
}
|
||||
|
||||
public void setFees(final BigDecimal fees) {
|
||||
this.fees = fees;
|
||||
}
|
||||
|
||||
public BigDecimal getPenalties() {
|
||||
return this.penalties;
|
||||
}
|
||||
|
||||
public void setPenalties(final BigDecimal penalties) {
|
||||
this.penalties = penalties;
|
||||
}
|
||||
|
||||
public boolean isDisbursement() {
|
||||
return this.disbursement;
|
||||
}
|
||||
|
||||
public void setDisbursement(final boolean disbursement) {
|
||||
this.disbursement = disbursement;
|
||||
}
|
||||
|
||||
public boolean isRepayment() {
|
||||
return this.repayment;
|
||||
}
|
||||
|
||||
public void setRepayment(final boolean repayment) {
|
||||
this.repayment = repayment;
|
||||
}
|
||||
|
||||
public boolean isContra() {
|
||||
return this.contra;
|
||||
}
|
||||
|
||||
public void setContra(final boolean contra) {
|
||||
this.contra = contra;
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return this.writeOff;
|
||||
}
|
||||
|
||||
public void setWriteOff(final boolean writeOff) {
|
||||
this.writeOff = writeOff;
|
||||
}
|
||||
|
||||
public boolean isRepaymentAtDisbursement() {
|
||||
return this.repaymentAtDisbursement;
|
||||
}
|
||||
|
||||
public void setRepaymentAtDisbursement(final boolean repaymentAtDisbursement) {
|
||||
this.repaymentAtDisbursement = repaymentAtDisbursement;
|
||||
}
|
||||
|
||||
}
|
||||
+15
-3
@@ -3,8 +3,9 @@
|
||||
* 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.glaccount.data;
|
||||
package org.mifosplatform.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public class LoanDTO {
|
||||
@@ -12,15 +13,18 @@ public class LoanDTO {
|
||||
private Long loanId;
|
||||
private Long loanProductId;
|
||||
private Long officeId;
|
||||
private BigDecimal calculatedInterest;
|
||||
private boolean cashBasedAccountingEnabled;
|
||||
private boolean accrualBasedAccountingEnabled;
|
||||
private List<LoanTransactionDTO> newLoanTransactions;
|
||||
|
||||
public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled, final List<LoanTransactionDTO> newLoanTransactions) {
|
||||
public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final BigDecimal calculatedInterest,
|
||||
final boolean cashBasedAccountingEnabled, final boolean accrualBasedAccountingEnabled,
|
||||
final List<LoanTransactionDTO> newLoanTransactions) {
|
||||
this.loanId = loanId;
|
||||
this.loanProductId = loanProductId;
|
||||
this.officeId = officeId;
|
||||
this.calculatedInterest = calculatedInterest;
|
||||
this.cashBasedAccountingEnabled = cashBasedAccountingEnabled;
|
||||
this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled;
|
||||
this.newLoanTransactions = newLoanTransactions;
|
||||
@@ -73,4 +77,12 @@ public class LoanDTO {
|
||||
public void setNewLoanTransactions(final List<LoanTransactionDTO> newLoanTransactions) {
|
||||
this.newLoanTransactions = newLoanTransactions;
|
||||
}
|
||||
|
||||
public BigDecimal getCalculatedInterest() {
|
||||
return this.calculatedInterest;
|
||||
}
|
||||
|
||||
public void setCalculatedInterest(BigDecimal calculatedInterest) {
|
||||
this.calculatedInterest = calculatedInterest;
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
|
||||
public class LoanTransactionDTO {
|
||||
|
||||
private final String transactionId;
|
||||
private final Date transactionDate;
|
||||
private final LoanTransactionEnumData transactionType;
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
/*** Breakup of amounts in case of repayments **/
|
||||
private final BigDecimal principal;
|
||||
private final BigDecimal interest;
|
||||
private final BigDecimal fees;
|
||||
private final BigDecimal penalties;
|
||||
|
||||
/*** Boolean values determines if the transaction is reversed ***/
|
||||
private final boolean reversed;
|
||||
|
||||
public LoanTransactionDTO(final String transactionId, final Date transactionDate, final LoanTransactionEnumData transactionType,
|
||||
final BigDecimal amount, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees,
|
||||
final BigDecimal penalties, final boolean reversed) {
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
this.amount = amount;
|
||||
this.principal = principal;
|
||||
this.interest = interest;
|
||||
this.fees = fees;
|
||||
this.penalties = penalties;
|
||||
this.reversed = reversed;
|
||||
this.transactionType = transactionType;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
public Date getTransactionDate() {
|
||||
return this.transactionDate;
|
||||
}
|
||||
|
||||
public LoanTransactionEnumData getTransactionType() {
|
||||
return this.transactionType;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public BigDecimal getInterest() {
|
||||
return this.interest;
|
||||
}
|
||||
|
||||
public BigDecimal getFees() {
|
||||
return this.fees;
|
||||
}
|
||||
|
||||
public BigDecimal getPenalties() {
|
||||
return this.penalties;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
|
||||
public interface AccountingProcessorForLoan {
|
||||
|
||||
void createJournalEntriesForLoan(LoanDTO loanDTO);
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AccountingProcessorForLoanFactory {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
public AccountingProcessorForLoanFactory(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public AccountingProcessorForLoan determineProcessor(final LoanDTO loanDTO) {
|
||||
|
||||
AccountingProcessorForLoan accountingProcessorForLoan = null;
|
||||
|
||||
if (loanDTO.isCashBasedAccountingEnabled()) {
|
||||
accountingProcessorForLoan = applicationContext
|
||||
.getBean("cashBasedAccountingProcessorForLoan", AccountingProcessorForLoan.class);
|
||||
}
|
||||
|
||||
else if (loanDTO.isAccrualBasedAccountingEnabled()) {
|
||||
accountingProcessorForLoan = applicationContext.getBean("accrualBasedAccountingProcessorForLoan",
|
||||
AccountingProcessorForLoan.class);
|
||||
}
|
||||
|
||||
return accountingProcessorForLoan;
|
||||
}
|
||||
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosureRepository;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntry;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
|
||||
import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidException;
|
||||
import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AccountingProcessorHelper {
|
||||
|
||||
private final JournalEntryRepository glJournalEntryRepository;
|
||||
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||
private final GLClosureRepository closureRepository;
|
||||
private final OfficeRepository officeRepository;
|
||||
|
||||
@Autowired
|
||||
public AccountingProcessorHelper(final JournalEntryRepository glJournalEntryRepository,
|
||||
final ProductToGLAccountMappingRepository accountMappingRepository, final GLClosureRepository closureRepository,
|
||||
final OfficeRepository officeRepository) {
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
this.accountMappingRepository = accountMappingRepository;
|
||||
this.closureRepository = closureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
}
|
||||
|
||||
public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled) {
|
||||
final Long loanId = (Long) accountingBridgeData.get("loanId");
|
||||
final Long loanProductId = (Long) accountingBridgeData.get("loanProductId");
|
||||
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
||||
final BigDecimal calculatedInterest = (BigDecimal) accountingBridgeData.get("calculatedInterest");
|
||||
|
||||
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<LoanTransactionDTO>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> newTransactionsMap = (List<Map<String, Object>>) accountingBridgeData.get("newLoanTransactions");
|
||||
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = ((LocalDate) map.get("date")).toDate();
|
||||
final LoanTransactionEnumData transactionType = (LoanTransactionEnumData) map.get("type");
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
|
||||
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
|
||||
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
|
||||
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
|
||||
final boolean reversed = (Boolean) map.get("reversed");
|
||||
|
||||
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionId, transactionDate, transactionType, amount,
|
||||
principal, interest, fees, penalties, reversed);
|
||||
|
||||
newLoanTransactions.add(transaction);
|
||||
|
||||
}
|
||||
|
||||
return new LoanDTO(loanId, loanProductId, officeId, calculatedInterest, cashBasedAccountingEnabled, accrualBasedAccountingEnabled,
|
||||
newLoanTransactions);
|
||||
}
|
||||
|
||||
public GLAccount getLinkedCashAccountsForLoanProduct(final Long loanProductId, final CASH_ACCOUNTS_FOR_LOAN finAccountType) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountType(loanProductId, PortfolioProductType.LOAN.getValue(),
|
||||
finAccountType.getValue());
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
public GLAccount getLinkedAccrualAccountsForLoanProduct(final Long loanProductId, final ACCRUAL_ACCOUNTS_FOR_LOAN finAccountType) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountType(loanProductId, PortfolioProductType.LOAN.getValue(),
|
||||
finAccountType.getValue());
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
public void createCreditJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.CREDIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
public void createDebitJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.DEBIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param latestGLClosure
|
||||
* @param transactionDate
|
||||
*/
|
||||
public void checkForBranchClosures(final GLClosure latestGLClosure, final Date transactionDate) {
|
||||
/**
|
||||
* check if an accounting closure has happened for this branch after the
|
||||
* 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); }
|
||||
}
|
||||
}
|
||||
|
||||
public GLClosure getLatestClosureByBranch(long officeId) {
|
||||
return this.closureRepository.getLatestGLClosureByBranch(officeId);
|
||||
}
|
||||
|
||||
public Office getOfficeById(long officeId) {
|
||||
return this.officeRepository.findOne(officeId);
|
||||
}
|
||||
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AccrualBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Autowired
|
||||
public AccrualBasedAccountingProcessorForLoan(final AccountingProcessorHelper accountingProcessorHelper) {
|
||||
this.helper = accountingProcessorHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForLoan(LoanDTO loanDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
|
||||
final Office office = this.helper.getOfficeById(loanDTO.getOfficeId());
|
||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
/** Handle Disbursements **/
|
||||
if (loanTransactionDTO.getTransactionType().isDisbursement()) {
|
||||
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/*** Handle Apply charges ***/
|
||||
// TODO
|
||||
|
||||
/***
|
||||
* Handle repayments, repayments at disbursement and reversal of
|
||||
* Repayments and Repayments at disbursement
|
||||
***/
|
||||
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()) {
|
||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/** Handle Write Offs and waivers **/
|
||||
else if ((loanTransactionDTO.getTransactionType().isWriteOff() || loanTransactionDTO.getTransactionType().isWaiveInterest() || loanTransactionDTO
|
||||
.getTransactionType().isWaiveCharges()) && !loanTransactionDTO.isReversed()) {
|
||||
createJournalEntriesForWriteOff(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debit loan Portfolio and credit Fund source for Disbursement. Also
|
||||
* recognise the receivable interest (Debit "Interest Receivable" and credit
|
||||
* "Income from Interest")
|
||||
*
|
||||
* @param loanDTO
|
||||
* @param loanTransactionDTO
|
||||
* @param office
|
||||
*/
|
||||
private void createJournalEntriesForDisbursements(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||
final Office office) {
|
||||
|
||||
// TODO: remove the junk transaction Id
|
||||
String junkTransactionId = "junk" + FileUtils.generateRandomString();
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
||||
|
||||
// create journal entries for the disbursement (or disbursement
|
||||
// reversal)
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
final GLAccount fundSourceAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
if (isReversed) {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, disbursalAmount);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
}
|
||||
|
||||
// create journal entries for recognising interest (or reversal)
|
||||
BigDecimal interestApplied = loanDTO.getCalculatedInterest();
|
||||
if (interestApplied != null && !(interestApplied.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
|
||||
final GLAccount interestReceivableAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE);
|
||||
final GLAccount interestOnLoansAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, junkTransactionId, transactionDate,
|
||||
interestApplied);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, junkTransactionId,
|
||||
transactionDate, interestApplied);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestReceivableAccount, loanId, junkTransactionId, transactionDate,
|
||||
interestApplied);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestOnLoansAccount, loanId, junkTransactionId, transactionDate,
|
||||
interestApplied);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single Debit for fund source and multiple credits if applicable
|
||||
* (loan portfolio for principal repayments, Interest receivable for
|
||||
* interest repayments, Fee receivable for fees payment and Penalty
|
||||
* Receivable from penalties for penalty payment)
|
||||
*
|
||||
* <br/>
|
||||
*
|
||||
* In case the loan transaction has been reversed, all debits are turned
|
||||
* into credits and vice versa
|
||||
*/
|
||||
private void createJournalEntriesForRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
|
||||
final GLAccount interestAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
}
|
||||
}
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
final GLAccount incomeFromFeesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
}
|
||||
}
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
|
||||
final GLAccount incomeFromPenaltiesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
}
|
||||
}
|
||||
final GLAccount fundSourceAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
if (isReversed) {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles write offs using the following posting rules <br/>
|
||||
*
|
||||
* <b>Principal Write off</b>: Debits "Losses Written Off" and Credits
|
||||
* "Loan Portfolio"<br/>
|
||||
*
|
||||
* <b>Interest Write off</b>:Debits "Losses Written off" and and Credits
|
||||
* "Receivable Interest" <br/>
|
||||
*
|
||||
* <b>Fee Write off</b>:Debits "Losses Written off" and and Credits
|
||||
* "Receivable Fees" <br/>
|
||||
*
|
||||
* <b>Penalty Write off</b>: Debits "Losses Written off" and and Credits
|
||||
* "Receivable Penalties" <br/>
|
||||
*
|
||||
* @param loanTransactionDTO
|
||||
* @param loanDTO
|
||||
* @param office
|
||||
*/
|
||||
private void createJournalEntriesForWriteOff(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
|
||||
final GLAccount interestAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate, interestAmount);
|
||||
}
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
final GLAccount incomeFromFeesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate, feesAmount);
|
||||
}
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
|
||||
final GLAccount incomeFromPenaltiesAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
}
|
||||
final GLAccount fundSourceAccount = helper.getLinkedAccrualAccountsForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF);
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CashBasedAccountingProcessorForLoan implements AccountingProcessorForLoan {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Autowired
|
||||
public CashBasedAccountingProcessorForLoan(final AccountingProcessorHelper accountingProcessorHelper) {
|
||||
this.helper = accountingProcessorHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForLoan(LoanDTO loanDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
|
||||
final Office office = this.helper.getOfficeById(loanDTO.getOfficeId());
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
/** Handle Disbursements and reversals of disbursements **/
|
||||
if (loanTransactionDTO.getTransactionType().isDisbursement() && !loanTransactionDTO.isReversed()) {
|
||||
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
/***
|
||||
* Logic for repayments, repayments at disbursement and reversal of
|
||||
* Repayments and Repayments at disbursement
|
||||
***/
|
||||
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()) {
|
||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
/***
|
||||
* Only principal write off affects cash based accounting (interest
|
||||
* and fee write off need not be considered). Debit losses written
|
||||
* off and credit Loan Portfolio
|
||||
**/
|
||||
else if (loanTransactionDTO.getTransactionType().isWriteOff() && !loanTransactionDTO.isReversed()) {
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final GLAccount lossesWrittenOffAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF);
|
||||
helper.createDebitJournalEntryForLoanProduct(office, lossesWrittenOffAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
||||
*
|
||||
* All debits are turned into credits and vice versa in case of disbursement
|
||||
* reversals
|
||||
*
|
||||
*
|
||||
* @param loanDTO
|
||||
* @param loanTransactionDTO
|
||||
* @param office
|
||||
*/
|
||||
private void createJournalEntriesForDisbursements(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||
final Office office) {
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversed = loanTransactionDTO.isReversed();
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
final GLAccount fundSourceAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
if (isReversed) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, disbursalAmount);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
helper.createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
disbursalAmount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single Debit to fund source and multiple credits if applicable
|
||||
* (loan portfolio for principal repayments, Interest on loans for interest
|
||||
* repayments, Income from fees for fees payment and Income from penalties
|
||||
* for penalty payment)
|
||||
*
|
||||
* In case the loan transaction is a reversal, all debits are turned into
|
||||
* credits and vice versa
|
||||
*/
|
||||
private void createJournalEntriesForRepayments(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
if (isReversal) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
|
||||
final GLAccount interestAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS);
|
||||
if (isReversal) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate,
|
||||
interestAmount);
|
||||
}
|
||||
}
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
final GLAccount incomeFromFeesAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES);
|
||||
if (isReversal) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate,
|
||||
feesAmount);
|
||||
}
|
||||
}
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
|
||||
final GLAccount incomeFromPenaltiesAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES);
|
||||
if (isReversal) {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
} else {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
}
|
||||
}
|
||||
final GLAccount fundSourceAccount = helper.getLinkedCashAccountsForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
if (isReversal) {
|
||||
helper.createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
} else {
|
||||
helper.createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate,
|
||||
totalDebitAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-206
@@ -6,7 +6,6 @@
|
||||
package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -16,15 +15,13 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosureRepository;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.mifosplatform.accounting.glaccount.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.glaccount.data.LoanTransactionDTO;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException;
|
||||
import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams;
|
||||
import org.mifosplatform.accounting.journalentry.command.JournalEntryCommand;
|
||||
import org.mifosplatform.accounting.journalentry.command.SingleDebitOrCreditEntryCommand;
|
||||
import org.mifosplatform.accounting.journalentry.data.LoanDTO;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntry;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
|
||||
@@ -32,9 +29,6 @@ import org.mifosplatform.accounting.journalentry.exception.JournalEntriesNotFoun
|
||||
import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidException;
|
||||
import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||
import org.mifosplatform.accounting.journalentry.serialization.JournalEntryCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -58,20 +52,23 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final GLAccountRepository glAccountRepository;
|
||||
private final JournalEntryRepository glJournalEntryRepository;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||
private final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory;
|
||||
private final AccountingProcessorHelper helper;
|
||||
private final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
|
||||
final GLAccountRepository glAccountRepository, final JournalEntryRepository glJournalEntryRepository,
|
||||
final OfficeRepository officeRepository, final ProductToGLAccountMappingRepository accountMappingRepository,
|
||||
final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
|
||||
final JournalEntryRepository glJournalEntryRepository, final OfficeRepository officeRepository,
|
||||
final GLAccountRepository glAccountRepository, final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final AccountingProcessorHelper accountingProcessorHelper,
|
||||
final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory) {
|
||||
this.glClosureRepository = glClosureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
this.glAccountRepository = glAccountRepository;
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
this.accountMappingRepository = accountMappingRepository;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.glAccountRepository = glAccountRepository;
|
||||
this.accountingProcessorForLoanFactory = accountingProcessorForLoanFactory;
|
||||
this.helper = accountingProcessorHelper;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -148,195 +145,15 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled");
|
||||
final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled");
|
||||
|
||||
if (cashBasedAccountingEnabled) {
|
||||
final LoanDTO loanDTO = populateDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled, accrualBasedAccountingEnabled);
|
||||
|
||||
createJournalEntriesUsingCashRules(loanDTO);
|
||||
} else if (accrualBasedAccountingEnabled) {
|
||||
// TODO Vishwas: add accrual based accounting rules
|
||||
if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) {
|
||||
final LoanDTO loanDTO = helper.populateLoanDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
|
||||
accrualBasedAccountingEnabled);
|
||||
final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory
|
||||
.determineProcessor(loanDTO);
|
||||
accountingProcessorForLoan.createJournalEntriesForLoan(loanDTO);
|
||||
}
|
||||
}
|
||||
|
||||
private LoanDTO populateDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
final boolean accrualBasedAccountingEnabled) {
|
||||
final Long loanId = (Long) accountingBridgeData.get("loanId");
|
||||
final Long loanProductId = (Long) accountingBridgeData.get("loanProductId");
|
||||
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
||||
|
||||
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<LoanTransactionDTO>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> newTransactionsMap = (List<Map<String, Object>>) accountingBridgeData.get("newLoanTransactions");
|
||||
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = ((LocalDate) map.get("date")).toDate();
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
|
||||
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
|
||||
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
|
||||
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
|
||||
final boolean disbursement = (Boolean) map.get("disbursement");
|
||||
final boolean repayment = (Boolean) map.get("repayment");
|
||||
final boolean repaymentAtDisbursement = (Boolean) map.get("repaymentAtDisbursement");
|
||||
final boolean contra = (Boolean) map.get("contra");
|
||||
final boolean writeOff = (Boolean) map.get("writeOff");
|
||||
|
||||
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionId, transactionDate, amount, principal, interest,
|
||||
fees, penalties, disbursement, repayment, repaymentAtDisbursement, contra, writeOff);
|
||||
|
||||
newLoanTransactions.add(transaction);
|
||||
|
||||
}
|
||||
|
||||
return new LoanDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newLoanTransactions);
|
||||
}
|
||||
|
||||
private void createJournalEntriesUsingCashRules(final LoanDTO loanDTO) {
|
||||
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(loanDTO.getOfficeId());
|
||||
final Office office = this.officeRepository.findOne(loanDTO.getOfficeId());
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
/**
|
||||
* check if an accounting closure has happened for this branch after
|
||||
* the 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); }
|
||||
}
|
||||
|
||||
/*** Debit loan Portfolio and credit Fund source for Disbursal **/
|
||||
if (loanTransactionDTO.isDisbursement() && !loanTransactionDTO.isContra()) {
|
||||
|
||||
final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
final GLAccount fundSourceAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
|
||||
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
|
||||
createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate, disbursalAmount);
|
||||
createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, disbursalAmount);
|
||||
} else if (loanTransactionDTO.isRepayment() || loanTransactionDTO.isRepaymentAtDisbursement() || loanTransactionDTO.isContra()) {
|
||||
createJournalEntriesForRepaymentOrContraUsingCashRules(office, loanProductId, loanTransactionDTO, transactionDate,
|
||||
transactionId, loanId);
|
||||
}/***
|
||||
* Only principal write off affects cash based accounting (interest
|
||||
* and fee write off need not be considered). Debit losses written
|
||||
* off and credit Loan Portfolio
|
||||
**/
|
||||
else if (loanTransactionDTO.isWriteOff()) {
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final GLAccount lossesWrittenOffAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF);
|
||||
createDebitJournalEntryForLoanProduct(office, lossesWrittenOffAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single Debit to fund source and multiple credits if applicable
|
||||
* (loan portfolio for principal repayment, Interest on loans for interest
|
||||
* repayments, Income from fees for fees payment and Income from penalties
|
||||
* for penalty payment)
|
||||
*
|
||||
* In case the loan transaction is a contra, all debits are turned into
|
||||
* credits and vice versa
|
||||
*/
|
||||
private void createJournalEntriesForRepaymentOrContraUsingCashRules(final Office office, final Long loanProductId,
|
||||
final LoanTransactionDTO loanTransactionDTO, final Date transactionDate, String transactionId, final Long loanId) {
|
||||
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final boolean isContraTransaction = loanTransactionDTO.isContra();
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
|
||||
final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||
if (isContraTransaction) {
|
||||
createDebitJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate, principalAmount);
|
||||
} else {
|
||||
createCreditJournalEntryForLoanProduct(office, loanPortfolioAccount, loanId, transactionId, transactionDate,
|
||||
principalAmount);
|
||||
}
|
||||
}
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
|
||||
final GLAccount interestAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS);
|
||||
if (isContraTransaction) {
|
||||
createDebitJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate, interestAmount);
|
||||
} else {
|
||||
createCreditJournalEntryForLoanProduct(office, interestAccount, loanId, transactionId, transactionDate, interestAmount);
|
||||
}
|
||||
}
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
final GLAccount incomeFromFeesAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES);
|
||||
if (isContraTransaction) {
|
||||
createDebitJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate, feesAmount);
|
||||
} else {
|
||||
createCreditJournalEntryForLoanProduct(office, incomeFromFeesAccount, loanId, transactionId, transactionDate, feesAmount);
|
||||
}
|
||||
}
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
|
||||
final GLAccount incomeFromPenaltiesAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES);
|
||||
if (isContraTransaction) {
|
||||
createDebitJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
} else {
|
||||
createCreditJournalEntryForLoanProduct(office, incomeFromPenaltiesAccount, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount);
|
||||
}
|
||||
}
|
||||
final GLAccount fundSourceAccount = getLinkedFinAccountForLoanProduct(loanProductId, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE);
|
||||
if (isContraTransaction) {
|
||||
createCreditJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
createDebitJournalEntryForLoanProduct(office, fundSourceAccount, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private GLAccount getLinkedFinAccountForLoanProduct(final Long loanProductId, final CASH_ACCOUNTS_FOR_LOAN finAccountType) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountType(loanProductId, PortfolioProductType.LOAN.getValue(),
|
||||
finAccountType.getValue());
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.CREDIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, account, transactionId, manualEntry, transactionDate,
|
||||
JournalEntryType.DEBIT, amount, null, PortfolioProductType.LOAN.getValue(), loanId);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
||||
/** check if date of Journal entry is valid ***/
|
||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||
@@ -405,13 +222,6 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
}
|
||||
}
|
||||
|
||||
private void handleJournalEntryDataIntegrityIssues(final DataIntegrityViolationException dve) {
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.glJournalEntry.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource Journal Entry: " + realCause.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Need a better implementation with guaranteed uniqueness (but not a
|
||||
* long UUID)...maybe something tied to system clock..
|
||||
@@ -419,4 +229,12 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private String generateTransactionId() {
|
||||
return RandomStringUtils.random(15, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
|
||||
}
|
||||
|
||||
private void handleJournalEntryDataIntegrityIssues(final DataIntegrityViolationException dve) {
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.glJournalEntry.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource Journal Entry: " + realCause.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+29
@@ -41,4 +41,33 @@ public class LoanTransactionEnumData {
|
||||
public Long id() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public boolean isDisbursement() {
|
||||
return this.disbursement;
|
||||
}
|
||||
|
||||
public boolean isRepaymentAtDisbursement() {
|
||||
return this.repaymentAtDisbursement;
|
||||
}
|
||||
|
||||
public boolean isRepayment() {
|
||||
return this.repayment;
|
||||
}
|
||||
|
||||
public boolean isWaiveInterest() {
|
||||
return this.waiveInterest;
|
||||
}
|
||||
|
||||
public boolean isWaiveCharges() {
|
||||
return this.waiveCharges;
|
||||
}
|
||||
|
||||
public boolean isWriteOff() {
|
||||
return this.writeOff;
|
||||
}
|
||||
|
||||
public boolean isRecoveryRepayment() {
|
||||
return this.recoveryRepayment;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -2067,6 +2067,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
accountingBridgeData.put("loanId", this.getId());
|
||||
accountingBridgeData.put("loanProductId", this.productId());
|
||||
accountingBridgeData.put("officeId", this.getOfficeId());
|
||||
accountingBridgeData.put("calculatedInterest", this.summary.getTotalInterestCharged());
|
||||
accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnLoanProduct());
|
||||
accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnLoanProduct());
|
||||
|
||||
|
||||
+4
@@ -130,6 +130,10 @@ public final class LoanSummary {
|
||||
public boolean isRepaidInFull(final MonetaryCurrency currency) {
|
||||
return getTotalOutstanding(currency).isZero();
|
||||
}
|
||||
|
||||
public BigDecimal getTotalInterestCharged() {
|
||||
return this.totalInterestCharged;
|
||||
}
|
||||
|
||||
/**
|
||||
* All fields but <code>totalFeeChargesDueAtDisbursement</code> should be
|
||||
|
||||
+2
-10
@@ -208,7 +208,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
private boolean isRecoveryRepayment() {
|
||||
public boolean isRecoveryRepayment() {
|
||||
return LoanTransactionType.RECOVERY_REPAYMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
@@ -285,15 +285,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
thisTransactionData.put("id", this.getId());
|
||||
thisTransactionData.put("type", transactionType);
|
||||
thisTransactionData.put("disbursement", Boolean.valueOf(this.isDisbursement()));
|
||||
thisTransactionData.put("repaymentAtDisbursement", Boolean.valueOf(this.isRepaymentAtDisbursement()));
|
||||
thisTransactionData.put("repayment", Boolean.valueOf(this.isRepayment()));
|
||||
thisTransactionData.put("recoveryRepayment", Boolean.valueOf(this.isRecoveryRepayment()));
|
||||
thisTransactionData.put("contra", Boolean.valueOf(this.isReversed()));
|
||||
thisTransactionData.put("waiveInterest", Boolean.valueOf(this.isInterestWaiver()));
|
||||
thisTransactionData.put("waiveCharges", Boolean.valueOf(this.isChargesWaiver()));
|
||||
thisTransactionData.put("writeOff", Boolean.valueOf(this.isWriteOff()));
|
||||
|
||||
thisTransactionData.put("reversed", Boolean.valueOf(this.isReversed()));
|
||||
thisTransactionData.put("date", this.getTransactionDate());
|
||||
thisTransactionData.put("currency", currencyData);
|
||||
thisTransactionData.put("amount", this.amount);
|
||||
|
||||
Reference in New Issue
Block a user