diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanDTO.java index 6345d14c5..421066a9b 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanDTO.java @@ -5,7 +5,6 @@ */ package org.mifosplatform.accounting.journalentry.data; -import java.math.BigDecimal; import java.util.List; public class LoanDTO { @@ -13,18 +12,15 @@ public class LoanDTO { private Long loanId; private Long loanProductId; private Long officeId; - private BigDecimal calculatedInterest; private boolean cashBasedAccountingEnabled; private boolean accrualBasedAccountingEnabled; private List newLoanTransactions; - public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final BigDecimal calculatedInterest, - final boolean cashBasedAccountingEnabled, final boolean accrualBasedAccountingEnabled, - final List newLoanTransactions) { + public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final boolean cashBasedAccountingEnabled, + final boolean accrualBasedAccountingEnabled, final List newLoanTransactions) { this.loanId = loanId; this.loanProductId = loanProductId; this.officeId = officeId; - this.calculatedInterest = calculatedInterest; this.cashBasedAccountingEnabled = cashBasedAccountingEnabled; this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled; this.newLoanTransactions = newLoanTransactions; @@ -78,11 +74,4 @@ public class LoanDTO { this.newLoanTransactions = newLoanTransactions; } - public BigDecimal getCalculatedInterest() { - return this.calculatedInterest; - } - - public void setCalculatedInterest(BigDecimal calculatedInterest) { - this.calculatedInterest = calculatedInterest; - } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java index dcbca5553..92aeb228b 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java @@ -56,8 +56,6 @@ public class AccountingProcessorHelper { 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 newLoanTransactions = new ArrayList(); @SuppressWarnings("unchecked") @@ -81,8 +79,7 @@ public class AccountingProcessorHelper { } - return new LoanDTO(loanId, loanProductId, officeId, calculatedInterest, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, - newLoanTransactions); + return new LoanDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newLoanTransactions); } /** diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index dc88c592a..084d661f0 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -34,6 +34,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess createJournalEntriesForDisbursements(loanDTO, loanTransactionDTO, office); } + /*** Handle Interest Postings ***/ + if (loanTransactionDTO.getTransactionType().isApplyInterest()) { + createJournalEntriesForInterestPostings(loanDTO, loanTransactionDTO, office); + } + /*** Handle Apply charges ***/ else if (loanTransactionDTO.getTransactionType().isApplyCharges()) { createJournalEntriesForApplyCharges(loanDTO, loanTransactionDTO, office); @@ -58,9 +63,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess } /** - * Debit loan Portfolio and credit Fund source for Disbursement. Also - * recognise the receivable interest (Debit "Interest Receivable" and credit - * "Income from Interest") + * Debit loan Portfolio and credit Fund source for Disbursement. * * @param loanDTO * @param loanTransactionDTO @@ -84,12 +87,33 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, isReversed); + } + + /** + * Recognise the receivable interest
+ * 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) - BigDecimal interestApplied = loanDTO.getCalculatedInterest(); - if (interestApplied != null && !(interestApplied.compareTo(BigDecimal.ZERO) == 0)) { + if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) { helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, - ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, - isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, transactionId, transactionDate, amount, isReversed); } } @@ -237,8 +261,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess // create journal entries for the penalties application (or reversal) else if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, loanId, transactionId, transactionDate, feesAmount, - isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, loanId, transactionId, transactionDate, + penaltiesAmount, isReversed); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java index 95e6c20d5..f11e63f18 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java @@ -19,6 +19,7 @@ public class LoanTransactionEnumData { private final boolean repaymentAtDisbursement; private final boolean repayment; private final boolean contra; + private final boolean applyInterest; private final boolean waiveInterest; private final boolean waiveCharges; private final boolean applyCharges; @@ -36,6 +37,7 @@ public class LoanTransactionEnumData { this.waiveInterest = Long.valueOf(4).equals(this.id); this.waiveCharges = Long.valueOf(9).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.recoveryRepayment = Long.valueOf(8).equals(this.id); } @@ -76,4 +78,8 @@ public class LoanTransactionEnumData { return this.applyCharges; } + public boolean isApplyInterest() { + return this.applyInterest; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index e32121b01..127cdf2ac 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -411,6 +411,11 @@ public class Loan extends AbstractPersistable { final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory .determineProcessor(this.transactionProcessingStrategy); + // store Id's of existing loan transactions and existing reversed loan + // transactions + existingTransactionIds.addAll(findExistingTransactionIds()); + existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); + if (!loanCharge.isDueAtDisbursement()) { final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement(); changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), @@ -426,16 +431,13 @@ public class Loan extends AbstractPersistable { } updateLoanSummaryDerivedFields(); - - existingTransactionIds.addAll(findExistingTransactionIds()); - existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); - return changedTransactionDetail; } /** * Creates a loanTransaction for "Apply Charge Event" with transaction date - * set to "suppliedTransactionDate" + * set to "suppliedTransactionDate". The newly created transaction is also + * added to the Loan on which this method is called. * * If "suppliedTransactionDate" is not passed Id, the transaction date is * set to the loans due date if the due date is lesser than todays date. If @@ -445,7 +447,7 @@ public class Loan extends AbstractPersistable { * @param suppliedTransactionDate * @return */ - public LoanTransaction getChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) { + public LoanTransaction handleChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) { final Money chargeAmount = loanCharge.getAmount(getCurrency()); Money feeCharges = chargeAmount; Money penaltyCharges = Money.zero(loanCurrency()); @@ -471,6 +473,7 @@ public class Loan extends AbstractPersistable { final LoanTransaction applyLoanChargeTransaction = LoanTransaction.applyLoanCharge(this, chargeAmount, transactionDate, feeCharges, penaltyCharges); + this.loanTransactions.add(applyLoanChargeTransaction); return applyLoanChargeTransaction; } @@ -629,6 +632,7 @@ public class Loan extends AbstractPersistable { final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, amountWaived, transactionDate, feeChargesWaived, penaltyChargesWaived); + this.loanTransactions.add(waiveLoanChargeTransaction); // Waive of charges whose due date falls after latest 'repayment' // transaction dont require entire loan schedule to be reprocessed. @@ -1211,6 +1215,11 @@ public class Loan extends AbstractPersistable { private void disburse(final LocalDate expectedDisbursedOnLocalDate) { this.actualDisbursementDate = expectedDisbursedOnLocalDate.toDate(); 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); } @@ -1271,6 +1280,17 @@ public class Loan extends AbstractPersistable { } else { 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; @@ -1338,8 +1358,7 @@ public class Loan extends AbstractPersistable { if (charge.isDueAtDisbursement()) { charge.markAsFullyPaid(); } else { - LoanTransaction loanChargeAppliedTransaction = getChargeAppliedTransaction(charge, disbursedOn); - this.loanTransactions.add(loanChargeAppliedTransaction); + handleChargeAppliedTransaction(charge, disbursedOn); } } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java index 698f2b273..c828e8c7e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java @@ -86,6 +86,10 @@ public final class LoanTransaction extends AbstractPersistable { 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) { return new LoanTransaction(loanTransaction.loan, loanTransaction.typeOf, loanTransaction.dateOf, loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion, loanTransaction.feeChargesPortion, @@ -96,7 +100,6 @@ public final class LoanTransaction extends AbstractPersistable { final Money penaltyCharges) { LoanTransaction applyCharge = new LoanTransaction(loan, LoanTransactionType.APPLY_CHARGES, amount.getAmount(), applyDate); applyCharge.updateChargesComponents(feeCharges, penaltyCharges); - return applyCharge; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java index 1343fa6f7..5d2f6f2d0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java @@ -21,7 +21,8 @@ public enum LoanTransactionType { */ RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), // 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 String code; @@ -75,6 +76,9 @@ public enum LoanTransactionType { case 10: loanTransactionType = LoanTransactionType.APPLY_CHARGES; break; + case 11: + loanTransactionType = LoanTransactionType.APPLY_INTEREST; + break; default: loanTransactionType = LoanTransactionType.INVALID; break; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 3bf6e86d5..89d614e97 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -552,7 +552,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingReversedTransactionIds = new ArrayList(); this.loanChargeRepository.save(loanCharge); - final LoanTransaction applyLoanChargeTransaction = loan.getChargeAppliedTransaction(loanCharge, null); + final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null); final ChangedTransactionDetail changedTransactionDetail = loan.addLoanCharge(loanCharge, existingTransactionIds, existingReversedTransactionIds); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index 2215708c5..fccf55e52 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -248,6 +248,10 @@ public class LoanEnumerations { optionData = new LoanTransactionEnumData(LoanTransactionType.APPLY_CHARGES.getValue().longValue(), LoanTransactionType.APPLY_CHARGES.getCode(), "Apply Charge"); break; + case APPLY_INTEREST: + optionData = new LoanTransactionEnumData(LoanTransactionType.APPLY_INTEREST.getValue().longValue(), + LoanTransactionType.APPLY_INTEREST.getCode(), "Apply Interest"); + break; } return optionData; }