From d8468865085a7e922656ff866008026d68beacff Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Thu, 4 Sep 2014 13:41:03 +0530 Subject: [PATCH] MIFOSX-1522 : added outstanding running balance for transactions --- ...d_loan_running_balance_to_transactions.sql | 2 ++ .../core/data/DataValidatorBuilder.java | 2 +- .../loanaccount/data/LoanTransactionData.java | 12 ++++--- .../portfolio/loanaccount/domain/Loan.java | 31 +++++++++++++++++-- .../loanaccount/domain/LoanTransaction.java | 10 +++++- ...RepaymentScheduleTransactionProcessor.java | 2 +- .../service/LoanReadPlatformServiceImpl.java | 31 ++++++++++++------- 7 files changed, 69 insertions(+), 21 deletions(-) create mode 100755 mifosng-db/migrations/core_db/V196__added_loan_running_balance_to_transactions.sql diff --git a/mifosng-db/migrations/core_db/V196__added_loan_running_balance_to_transactions.sql b/mifosng-db/migrations/core_db/V196__added_loan_running_balance_to_transactions.sql new file mode 100755 index 000000000..d271abe39 --- /dev/null +++ b/mifosng-db/migrations/core_db/V196__added_loan_running_balance_to_transactions.sql @@ -0,0 +1,2 @@ +ALTER TABLE `m_loan_transaction` + ADD COLUMN `outstanding_loan_balance_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `overpayment_portion_derived`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java index ff76fb418..cec01f0b3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java @@ -827,7 +827,7 @@ public class DataValidatorBuilder { if (this.value != null && date != null) { final LocalDate dateVal = (LocalDate) this.value; - if (!date.isAfter(dateVal)) { + if (dateVal.isAfter(date)) { final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".") .append(this.parameter).append(".is.greater.than.date"); final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java index bcfad68e6..89eaccede 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java @@ -39,6 +39,7 @@ public class LoanTransactionData { private final String externalId; private final AccountTransferData transfer; private final BigDecimal fixedEmiAmount; + private final BigDecimal outstandingLoanBalance; // templates final Collection paymentTypeOptions; @@ -49,16 +50,18 @@ public class LoanTransactionData { loanTransactionData.type, loanTransactionData.paymentDetailData, loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion, loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, loanTransactionData.overpaymentPortion, - paymentTypeOptions, loanTransactionData.externalId, loanTransactionData.transfer, loanTransactionData.fixedEmiAmount); + paymentTypeOptions, loanTransactionData.externalId, loanTransactionData.transfer, loanTransactionData.fixedEmiAmount, + loanTransactionData.outstandingLoanBalance); } public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion, final String externalId, - final AccountTransferData transfer, BigDecimal fixedEmiAmount) { + final AccountTransferData transfer, BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance) { this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, principalPortion, interestPortion, - feeChargesPortion, penaltyChargesPortion, overpaymentPortion, null, externalId, transfer, fixedEmiAmount); + feeChargesPortion, penaltyChargesPortion, overpaymentPortion, null, externalId, transfer, fixedEmiAmount, + outstandingLoanBalance); } public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType, @@ -66,7 +69,7 @@ public class LoanTransactionData { final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion, final Collection paymentTypeOptions, final String externalId, final AccountTransferData transfer, - final BigDecimal fixedEmiAmount) { + final BigDecimal fixedEmiAmount, BigDecimal outstandingLoanBalance) { this.id = id; this.officeId = officeId; this.officeName = officeName; @@ -84,6 +87,7 @@ public class LoanTransactionData { this.transfer = transfer; this.overpaymentPortion = overpaymentPortion; this.fixedEmiAmount = fixedEmiAmount; + this.outstandingLoanBalance = outstandingLoanBalance; } public LocalDate dateOf() { 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 5cc4d8fe4..66be050e7 100755 --- 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 @@ -1044,6 +1044,7 @@ public class Loan extends AbstractPersistable { if (this.summaryArrearsAging.isNotInArrears(loanCurrency())) { this.summaryArrearsAging = null; } + updateLoanOutstandingBalaces(); } } @@ -2504,6 +2505,18 @@ public class Loan extends AbstractPersistable { return repaymentsOrWaivers; } + private List retreiveListOfTransactionsExcludeAccruals() { + final List repaymentsOrWaivers = new ArrayList<>(); + for (final LoanTransaction transaction : this.loanTransactions) { + if (transaction.isNotReversed() && !transaction.isAccrual()) { + repaymentsOrWaivers.add(transaction); + } + } + final LoanTransactionComparator transactionComparator = new LoanTransactionComparator(); + Collections.sort(repaymentsOrWaivers, transactionComparator); + return repaymentsOrWaivers; + } + private void doPostLoanTransactionChecks(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) { if (isOverPaid()) { @@ -4169,9 +4182,6 @@ public class Loan extends AbstractPersistable { final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod(); final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod); - final RoundingMode roundingMode = RoundingMode.HALF_EVEN; - final MathContext mc = new MathContext(8, roundingMode); - final Integer loanTermFrequency = this.termFrequency; final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType); final List disbursementData = new ArrayList<>(); @@ -4233,4 +4243,19 @@ public class Loan extends AbstractPersistable { } return accruedTill; } + + private void updateLoanOutstandingBalaces() { + Money outstanding = Money.zero(getCurrency()); + List loanTransactions = retreiveListOfTransactionsExcludeAccruals(); + for (LoanTransaction loanTransaction : loanTransactions) { + if (loanTransaction.isDisbursement()) { + outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency())); + loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount()); + } else { + outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency())); + loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount()); + } + } + } + } \ No newline at end of file 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 49635cf81..d4fda7770 100755 --- 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 @@ -95,6 +95,9 @@ public final class LoanTransaction extends AbstractPersistable { @OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true) private Set loanChargesPaid = new HashSet<>(); + @Column(name = "outstanding_loan_balance_derived", scale = 6, precision = 19, nullable = true) + private BigDecimal outstandingLoanBalance; + protected LoanTransaction() { this.loan = null; this.dateOf = null; @@ -264,6 +267,7 @@ public final class LoanTransaction extends AbstractPersistable { this.feeChargesPortion = null; this.penaltyChargesPortion = null; this.overPaymentPortion = null; + this.outstandingLoanBalance = null; } public void updateLoan(final Loan loan) { @@ -462,7 +466,7 @@ public final class LoanTransaction extends AbstractPersistable { } return new LoanTransactionData(getId(), this.office.getId(), this.office.getName(), transactionType, paymentDetailData, currencyData, getTransactionDate(), this.amount, this.principalPortion, this.interestPortion, this.feeChargesPortion, - this.penaltyChargesPortion, this.overPaymentPortion, this.externalId, transfer, null); + this.penaltyChargesPortion, this.overPaymentPortion, this.externalId, transfer, null, outstandingLoanBalance); } public Map toMapData(final CurrencyData currencyData) { @@ -532,4 +536,8 @@ public final class LoanTransaction extends AbstractPersistable { return LoanTransactionType.ACCRUAL.equals(getTypeOf()) && isNotReversed(); } + public void updateOutstandingLoanBalance(BigDecimal outstandingLoanBalance) { + this.outstandingLoanBalance = outstandingLoanBalance; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java index ac473f109..415522881 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java @@ -123,7 +123,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen transactionstoBeProcessed.add(loanTransaction); } } - + for (final LoanTransaction loanTransaction : transactionstoBeProcessed) { if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 991e828ed..64e8bf19d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -361,11 +361,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); final Collection paymentOptions = this.codeValueReadPlatformService .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); + final BigDecimal outstandingLoanBalance = null; return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment .getPrincipalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment.getInterestOutstanding(currency) .getAmount(), loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(), - loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, paymentOptions, null, null, null); + loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, paymentOptions, null, null, + null, outstandingLoanBalance); } @Override @@ -387,11 +389,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); final Collection paymentOptions = this.codeValueReadPlatformService .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); + final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount(); return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment .getPrincipalOutstanding(currency).getAmount(), loanRepaymentScheduleInstallment.getInterestOutstanding(currency) .getAmount(), loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency).getAmount(), - loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, paymentOptions, null, null, null); + loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).getAmount(), null, paymentOptions, null, null, + null, outstandingLoanBalance); } @Override @@ -414,18 +418,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST); final BigDecimal amount = waiveOfInterest.getAmount(currency).getAmount(); + final BigDecimal outstandingLoanBalance = null; return new LoanTransactionData(null, null, null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount, - null, null, null, null, null, null, null, null); + null, null, null, null, null, null, null, null, outstandingLoanBalance); } @Override public LoanTransactionData retrieveNewClosureDetails() { this.context.authenticatedUser(); - + final BigDecimal outstandingLoanBalance = null; final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); return new LoanTransactionData(null, null, null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null, - null, null, null, null, null, null); + null, null, null, null, null, null, outstandingLoanBalance); } @Override @@ -437,8 +442,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { if (paymentDetailsRequired) { paymentOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); } + final BigDecimal outstandingLoanBalance = null; return new LoanTransactionData(null, null, null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDateForTemplate(), - loan.getDisburseAmountForTemplate(), null, null, null, null, null, paymentOptions, null, null, loan.retriveLastEmiAmount()); + loan.getDisburseAmountForTemplate(), null, null, null, null, null, paymentOptions, null, null, loan.retriveLastEmiAmount(), + outstandingLoanBalance); } @Override @@ -1047,7 +1054,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, " + " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, " + " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, " - + " tr.overpayment_portion_derived as overpayment, " + + " tr.overpayment_portion_derived as overpayment, tr.outstanding_loan_balance_derived as outstandingLoanBalance, " + " pd.payment_type_cv_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, " + " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, " + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, " @@ -1108,6 +1115,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal feeChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "fees"); final BigDecimal penaltyChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penalties"); final BigDecimal overPaymentPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "overpayment"); + final BigDecimal outstandingLoanBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "outstandingLoanBalance"); final String externalId = rs.getString("externalId"); AccountTransferData transfer = null; @@ -1133,7 +1141,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { return new LoanTransactionData(id, officeId, officeName, transactionType, paymentDetailData, currencyData, date, totalAmount, principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overPaymentPortion, externalId, transfer, - null); + null, outstandingLoanBalance); } } @@ -1559,8 +1567,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.RECOVERY_REPAYMENT); final Collection paymentOptions = this.codeValueReadPlatformService .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); + BigDecimal outstandingLoanBalance = null; return new LoanTransactionData(null, null, null, transactionType, null, null, null, loan.getTotalWrittenOff(), null, null, null, - null, null, paymentOptions, null, null, null); + null, null, paymentOptions, null, null, null, outstandingLoanBalance); } @@ -1568,10 +1577,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { public LoanTransactionData retrieveLoanWriteoffTemplate(final Long loanId) { final LoanAccountData loan = this.retrieveOne(loanId); - + final BigDecimal outstandingLoanBalance = null; final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); return new LoanTransactionData(null, null, null, transactionType, null, loan.currency(), DateUtils.getLocalDateOfTenant(), - loan.getTotalOutstandingAmount(), null, null, null, null, null, null, null, null); + loan.getTotalOutstandingAmount(), null, null, null, null, null, null, null, null, outstandingLoanBalance); } @Override