adding Lifecycle event called Interest Applied

This commit is contained in:
Vishwas Babu AJ
2013-03-24 19:05:32 +05:30
parent 29c071d763
commit 28d66e39ec
8 changed files with 69 additions and 26 deletions
@@ -5,7 +5,6 @@
*/ */
package org.mifosplatform.accounting.journalentry.data; package org.mifosplatform.accounting.journalentry.data;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
public class LoanDTO { public class LoanDTO {
@@ -13,18 +12,15 @@ public class LoanDTO {
private Long loanId; private Long loanId;
private Long loanProductId; private Long loanProductId;
private Long officeId; private Long officeId;
private BigDecimal calculatedInterest;
private boolean cashBasedAccountingEnabled; private boolean cashBasedAccountingEnabled;
private boolean accrualBasedAccountingEnabled; private boolean accrualBasedAccountingEnabled;
private List<LoanTransactionDTO> newLoanTransactions; private List<LoanTransactionDTO> newLoanTransactions;
public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final BigDecimal calculatedInterest, public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final boolean cashBasedAccountingEnabled,
final boolean cashBasedAccountingEnabled, final boolean accrualBasedAccountingEnabled, final boolean accrualBasedAccountingEnabled, final List<LoanTransactionDTO> newLoanTransactions) {
final List<LoanTransactionDTO> newLoanTransactions) {
this.loanId = loanId; this.loanId = loanId;
this.loanProductId = loanProductId; this.loanProductId = loanProductId;
this.officeId = officeId; this.officeId = officeId;
this.calculatedInterest = calculatedInterest;
this.cashBasedAccountingEnabled = cashBasedAccountingEnabled; this.cashBasedAccountingEnabled = cashBasedAccountingEnabled;
this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled; this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled;
this.newLoanTransactions = newLoanTransactions; this.newLoanTransactions = newLoanTransactions;
@@ -78,11 +74,4 @@ public class LoanDTO {
this.newLoanTransactions = newLoanTransactions; this.newLoanTransactions = newLoanTransactions;
} }
public BigDecimal getCalculatedInterest() {
return this.calculatedInterest;
}
public void setCalculatedInterest(BigDecimal calculatedInterest) {
this.calculatedInterest = calculatedInterest;
}
} }
@@ -56,8 +56,6 @@ public class AccountingProcessorHelper {
final Long loanId = (Long) accountingBridgeData.get("loanId"); final Long loanId = (Long) accountingBridgeData.get("loanId");
final Long loanProductId = (Long) accountingBridgeData.get("loanProductId"); final Long loanProductId = (Long) accountingBridgeData.get("loanProductId");
final Long officeId = (Long) accountingBridgeData.get("officeId"); final Long officeId = (Long) accountingBridgeData.get("officeId");
final BigDecimal calculatedInterest = (BigDecimal) accountingBridgeData.get("calculatedInterest");
final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<LoanTransactionDTO>(); final List<LoanTransactionDTO> newLoanTransactions = new ArrayList<LoanTransactionDTO>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -81,8 +79,7 @@ public class AccountingProcessorHelper {
} }
return new LoanDTO(loanId, loanProductId, officeId, calculatedInterest, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, return new LoanDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newLoanTransactions);
newLoanTransactions);
} }
/** /**
@@ -34,6 +34,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office); createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office);
} }
/*** Handle Interest Postings ***/
if (loanTransactionDTO.getTransactionType().isApplyInterest()) {
createJournalEntriesForInterestPostings(loanDTO, loanTransactionDTO, office);
}
/*** Handle Apply charges ***/ /*** Handle Apply charges ***/
else if (loanTransactionDTO.getTransactionType().isApplyCharges()) { else if (loanTransactionDTO.getTransactionType().isApplyCharges()) {
createJournalEntriesForApplyCharges(loanDTO, loanTransactionDTO, office); createJournalEntriesForApplyCharges(loanDTO, loanTransactionDTO, office);
@@ -58,9 +63,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
} }
/** /**
* Debit loan Portfolio and credit Fund source for Disbursement. Also * Debit loan Portfolio and credit Fund source for Disbursement.
* recognise the receivable interest (Debit "Interest Receivable" and credit
* "Income from Interest")
* *
* @param loanDTO * @param loanDTO
* @param loanTransactionDTO * @param loanTransactionDTO
@@ -77,7 +80,6 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
final String transactionId = loanTransactionDTO.getTransactionId(); final String transactionId = loanTransactionDTO.getTransactionId();
final Date transactionDate = loanTransactionDTO.getTransactionDate(); final Date transactionDate = loanTransactionDTO.getTransactionDate();
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
final BigDecimal interestAmount = loanDTO.getCalculatedInterest();
final boolean isReversed = loanTransactionDTO.isReversed(); final boolean isReversed = loanTransactionDTO.isReversed();
// create journal entries for the disbursement (or disbursement // create journal entries for the disbursement (or disbursement
@@ -85,12 +87,33 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO,
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, isReversed); ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, isReversed);
}
/**
* Recognise the receivable interest <br/>
* Debit "Interest Receivable" and Credit "Income from Interest"
*
* @param loanDTO
* @param loanTransactionDTO
* @param office
*/
private void createJournalEntriesForInterestPostings(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 amount = loanTransactionDTO.getAmount();
final boolean isReversed = loanTransactionDTO.isReversed();
// create journal entries for recognising interest (or reversal) // create journal entries for recognising interest (or reversal)
BigDecimal interestApplied = loanDTO.getCalculatedInterest(); if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) {
if (interestApplied != null && !(interestApplied.compareTo(BigDecimal.ZERO) == 0)) {
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE,
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, transactionId, transactionDate, interestAmount, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, transactionId, transactionDate, amount, isReversed);
isReversed);
} }
} }
@@ -19,6 +19,7 @@ public class LoanTransactionEnumData {
private final boolean repaymentAtDisbursement; private final boolean repaymentAtDisbursement;
private final boolean repayment; private final boolean repayment;
private final boolean contra; private final boolean contra;
private final boolean applyInterest;
private final boolean waiveInterest; private final boolean waiveInterest;
private final boolean waiveCharges; private final boolean waiveCharges;
private final boolean applyCharges; private final boolean applyCharges;
@@ -36,6 +37,7 @@ public class LoanTransactionEnumData {
this.waiveInterest = Long.valueOf(4).equals(this.id); this.waiveInterest = Long.valueOf(4).equals(this.id);
this.waiveCharges = Long.valueOf(9).equals(this.id); this.waiveCharges = Long.valueOf(9).equals(this.id);
this.applyCharges = Long.valueOf(10).equals(this.id); this.applyCharges = Long.valueOf(10).equals(this.id);
this.applyInterest = Long.valueOf(11).equals(this.id);
this.writeOff = Long.valueOf(6).equals(this.id); this.writeOff = Long.valueOf(6).equals(this.id);
this.recoveryRepayment = Long.valueOf(8).equals(this.id); this.recoveryRepayment = Long.valueOf(8).equals(this.id);
} }
@@ -76,4 +78,8 @@ public class LoanTransactionEnumData {
return this.applyCharges; return this.applyCharges;
} }
public boolean isApplyInterest() {
return this.applyInterest;
}
} }
@@ -1215,6 +1215,11 @@ public class Loan extends AbstractPersistable<Long> {
private void disburse(final LocalDate expectedDisbursedOnLocalDate) { private void disburse(final LocalDate expectedDisbursedOnLocalDate) {
this.actualDisbursementDate = expectedDisbursedOnLocalDate.toDate(); this.actualDisbursementDate = expectedDisbursedOnLocalDate.toDate();
updateLoanScheduleDependentDerivedFields(); updateLoanScheduleDependentDerivedFields();
/****
* Vishwas TODO: Refactor to skip unnecessary creation of Disbursement
* and fees applied transactions (though they are not persisted) on
* modifications to loan application modification
*****/
handleDisbursementTransaction(expectedDisbursedOnLocalDate); handleDisbursementTransaction(expectedDisbursedOnLocalDate);
} }
@@ -1275,6 +1280,17 @@ public class Loan extends AbstractPersistable<Long> {
} else { } else {
updateLoanSummaryDerivedFields(); updateLoanSummaryDerivedFields();
} }
/***
* Adding a temporary Interest applied transaction (applying the
* full Interest as soon as the loan is disbursed), will have to
* re-look into this logic once loans with Interest calculation need
* to be created or more advances accrual accounting support has to
* be provided
***/
Money interestApplied = Money.of(this.getCurrency(), this.summary.getTotalInterestCharged());
final LoanTransaction interestAppliedTransaction = LoanTransaction.applyInterest(this, interestApplied, actualDisbursementDate);
this.loanTransactions.add(interestAppliedTransaction);
} }
return actualChanges; return actualChanges;
@@ -86,6 +86,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate); return new LoanTransaction(loan, LoanTransactionType.WAIVE_INTEREST, waived.getAmount(), waiveDate);
} }
public static LoanTransaction applyInterest(final Loan loan, final Money amount, final LocalDate interestAppliedDate) {
return new LoanTransaction(loan, LoanTransactionType.APPLY_INTEREST, amount.getAmount(), interestAppliedDate);
}
public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) { public static LoanTransaction copyTransactionProperties(LoanTransaction loanTransaction) {
return new LoanTransaction(loanTransaction.loan, loanTransaction.typeOf, loanTransaction.dateOf, loanTransaction.amount, return new LoanTransaction(loanTransaction.loan, loanTransaction.typeOf, loanTransaction.dateOf, loanTransaction.amount,
loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.feeChargesPortion, loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.feeChargesPortion,
@@ -21,7 +21,8 @@ public enum LoanTransactionType {
*/ */
RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), // RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), //
WAIVE_CHARGES(9, "loanTransactionType.waiveCharges"), // WAIVE_CHARGES(9, "loanTransactionType.waiveCharges"), //
APPLY_CHARGES(10, "loanTransactionType.applyCharges"); APPLY_CHARGES(10, "loanTransactionType.applyCharges"), //
APPLY_INTEREST(11, "loanTransactionType.applyInterest");
private final Integer value; private final Integer value;
private final String code; private final String code;
@@ -75,6 +76,9 @@ public enum LoanTransactionType {
case 10: case 10:
loanTransactionType = LoanTransactionType.APPLY_CHARGES; loanTransactionType = LoanTransactionType.APPLY_CHARGES;
break; break;
case 11:
loanTransactionType = LoanTransactionType.APPLY_INTEREST;
break;
default: default:
loanTransactionType = LoanTransactionType.INVALID; loanTransactionType = LoanTransactionType.INVALID;
break; break;
@@ -248,6 +248,10 @@ public class LoanEnumerations {
optionData = new LoanTransactionEnumData(LoanTransactionType.APPLY_CHARGES.getValue().longValue(), optionData = new LoanTransactionEnumData(LoanTransactionType.APPLY_CHARGES.getValue().longValue(),
LoanTransactionType.APPLY_CHARGES.getCode(), "Apply Charge"); LoanTransactionType.APPLY_CHARGES.getCode(), "Apply Charge");
break; break;
case APPLY_INTEREST:
optionData = new LoanTransactionEnumData(LoanTransactionType.APPLY_INTEREST.getValue().longValue(),
LoanTransactionType.APPLY_INTEREST.getCode(), "Apply Interest");
break;
} }
return optionData; return optionData;
} }