diff --git a/mifosng-db/patches/patch-0005-add-total-charges-due-at-disbursement-derived-column-as-big-decimal.sql b/mifosng-db/patches/patch-0005-add-total-charges-due-at-disbursement-derived-column-as-big-decimal.sql new file mode 100644 index 000000000..df8533b86 --- /dev/null +++ b/mifosng-db/patches/patch-0005-add-total-charges-due-at-disbursement-derived-column-as-big-decimal.sql @@ -0,0 +1,3 @@ +ALTER TABLE `m_loan` +DROP COLUMN `total_charges_due_at_disbursement_derived`, +ADD COLUMN `total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL AFTER `interest_rebate_amount`; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java index 4cb63a6e7..45cca82b3 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java @@ -199,13 +199,15 @@ public class LoansApiResource { loanRepayments = currentLoanRepayments; loanRepaymentsCount = loanRepayments.size(); } + DisbursementData singleDisbursement = loanBasicDetails.toDisburementData(); - repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(), singleDisbursement); + repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(), + singleDisbursement, loanBasicDetails.getTotalDisbursementCharges(), loanBasicDetails.getInArrearsTolerance()); MoneyData tolerance = MoneyData.of(loanBasicDetails.getCurrency(), loanBasicDetails.getInArrearsTolerance()); MoneyData totalOutstandingMoney = MoneyData.of(loanBasicDetails.getCurrency(), repaymentSchedule.totalOutstanding()); boolean isWaiveAllowed = totalOutstandingMoney.isGreaterThanZero() && (tolerance.isGreaterThan(totalOutstandingMoney) || tolerance.isEqualTo(totalOutstandingMoney)); - + permissions = this.loanReadPlatformService.retrieveLoanPermissions(loanBasicDetails, isWaiveAllowed, loanRepaymentsCount); convenienceDataRequired = true; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanBasicDetailsData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanBasicDetailsData.java index 55faf57b4..e4728bc23 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanBasicDetailsData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanBasicDetailsData.java @@ -54,6 +54,7 @@ public class LoanBasicDetailsData { private final LocalDate expectedMaturityDate; private final LocalDate lifeCycleStatusDate; + private final BigDecimal totalDisbursementCharges; private final Collection charges; public static LoanBasicDetailsData populateForNewLoanCreation(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate, @@ -146,6 +147,7 @@ public class LoanBasicDetailsData { this.lifeCycleStatusDate = null; this.charges = charges; + this.totalDisbursementCharges = BigDecimal.ZERO; } private LoanBasicDetailsData(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate, final Long clientOfficeId) { @@ -191,6 +193,7 @@ public class LoanBasicDetailsData { this.interestChargedFromDate = null; this.charges = null; + this.totalDisbursementCharges = BigDecimal.ZERO; } public LoanBasicDetailsData( @@ -227,7 +230,8 @@ public class LoanBasicDetailsData { final EnumOptionData termPeriodFrequencyType, final Integer transactionStrategyId, final Collection charges, - final Long loanOfficerId, String loanOfficerName) { + final Long loanOfficerId, String loanOfficerName, + final BigDecimal totalDisbursementCharges) { this.id = id; this.externalId = externalId; this.clientId = clientId; @@ -266,6 +270,7 @@ public class LoanBasicDetailsData { this.termPeriodFrequencyType = termPeriodFrequencyType; this.transactionStrategyId = transactionStrategyId; this.charges = charges; + this.totalDisbursementCharges = totalDisbursementCharges; } public int getMaxSubmittedOnOffsetFromToday() { @@ -509,6 +514,10 @@ public class LoanBasicDetailsData { return loanOfficerName; } + public BigDecimal getTotalDisbursementCharges() { + return totalDisbursementCharges; + } + public DisbursementData toDisburementData() { return new DisbursementData(this.expectedDisbursementDate, this.actualDisbursementDate, this.principal); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java index aac0b5699..47dd80435 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/LoanSchedulePeriodData.java @@ -38,6 +38,7 @@ public class LoanSchedulePeriodData { private final BigDecimal totalPaidForPeriod; private final BigDecimal totalWaivedForPeriod; private final BigDecimal totalOutstandingForPeriod; + private final BigDecimal totalOverdue; public static LoanSchedulePeriodData disbursementOnlyPeriod( final LocalDate disbursementDate, @@ -118,7 +119,12 @@ public class LoanSchedulePeriodData { this.totalDueForPeriod = chargesDueAtTimeOfDisbursement; this.totalPaidForPeriod = BigDecimal.ZERO; this.totalWaivedForPeriod = null; - this.totalOutstandingForPeriod = null; + this.totalOutstandingForPeriod = chargesDueAtTimeOfDisbursement; + if (dueDate.isBefore(new LocalDate())) { + this.totalOverdue = this.totalOutstandingForPeriod; + } else { + this.totalOverdue = null; + } } private LoanSchedulePeriodData( @@ -159,6 +165,11 @@ public class LoanSchedulePeriodData { this.totalPaidForPeriod = BigDecimal.ZERO; this.totalWaivedForPeriod = null; this.totalOutstandingForPeriod = totalDueForPeriod; + if (dueDate.isBefore(new LocalDate())) { + this.totalOverdue = this.totalOutstandingForPeriod; + } else { + this.totalOverdue = null; + } } /* @@ -204,6 +215,12 @@ public class LoanSchedulePeriodData { this.totalPaidForPeriod = BigDecimal.ZERO; this.totalWaivedForPeriod = BigDecimal.ZERO; this.totalOutstandingForPeriod = totalDueForPeriod; + + if (dueDate.isBefore(new LocalDate())) { + this.totalOverdue = this.totalOutstandingForPeriod; + } else { + this.totalOverdue = null; + } } private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) { @@ -230,6 +247,10 @@ public class LoanSchedulePeriodData { return this.dueDate; } + public Integer daysInPeriod() { + return this.daysInPeriod; + } + public BigDecimal principalDisbursed() { return defaultToZeroIfNull(this.principalDisbursed); } @@ -273,4 +294,8 @@ public class LoanSchedulePeriodData { public BigDecimal chargesOutstanding() { return defaultToZeroIfNull(this.chargesOutstanding); } + + public BigDecimal totalOverdue() { + return defaultToZeroIfNull(this.totalOverdue); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformService.java index 5c6c17f2e..11ebd2777 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformService.java @@ -1,5 +1,6 @@ package org.mifosng.platform.loan.service; +import java.math.BigDecimal; import java.util.Collection; import org.mifosng.platform.api.LoanScheduleNewData; @@ -14,7 +15,7 @@ public interface LoanReadPlatformService { LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId); - LoanScheduleNewData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement); + LoanScheduleNewData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement, BigDecimal totalChargesAtDisbursement, BigDecimal inArrearsTolerance); Collection retrieveLoanPayments(Long loanId); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java index f06bc24e0..eec141397 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanReadPlatformServiceImpl.java @@ -91,7 +91,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { } @Override - public LoanScheduleNewData retrieveRepaymentSchedule(final Long loanId, final CurrencyData currency, final DisbursementData disbursement) { + public LoanScheduleNewData retrieveRepaymentSchedule(final Long loanId, + final CurrencyData currency, + final DisbursementData disbursement, + final BigDecimal totalChargesAtDisbursement, + final BigDecimal inArrearsTolerance) { try { context.authenticatedUser(); @@ -99,8 +103,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement); final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment"; - // FIXME - KW - pass through total chargesDueAtTimeOfDisbursementFigure - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursement.disbursementDate(), disbursement.amount(), BigDecimal.ZERO); + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursement.disbursementDate(), disbursement.amount(), totalChargesAtDisbursement); final Collection repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); @@ -110,7 +113,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { LoanSchedulePeriodDataWrapper wrapper = new LoanSchedulePeriodDataWrapper(periods); - final Integer loanTermInDays = null; + final Integer loanTermInDays = wrapper.deriveCumulativeLoanTermInDays(); final BigDecimal cumulativePrincipalDisbursed = wrapper.deriveCumulativePrincipalDisbursed(); final BigDecimal cumulativePrincipalDue = wrapper.deriveCumulativePrincipalDue(); final BigDecimal cumulativePrincipalPaid = wrapper.deriveCumulativePrincipalPaid(); @@ -128,7 +131,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal totalPaidToDate = cumulativePrincipalPaid.add(cumulativeInterestPaid).add(cumulativeChargesPaid); final BigDecimal totalWaivedToDate = cumulativeInterestWaived; final BigDecimal totalOutstanding = cumulativePrincipalOutstanding.add(cumulativeInterestOutstanding).add(cumulativeChargesOutstanding); - final BigDecimal totalInArrears = null; + + final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue(); + + MoneyData tolerance = MoneyData.of(currency, inArrearsTolerance); + MoneyData totalOverdueMoney = MoneyData.of(currency, totalOverdue); + boolean isWaiveAllowed = totalOverdueMoney.isGreaterThanZero() && (tolerance.isGreaterThan(totalOverdueMoney) || tolerance.isEqualTo(totalOverdueMoney)); + + BigDecimal totalInArrears = null; + if (!isWaiveAllowed) { + totalInArrears = totalOverdueMoney.getAmount(); + } return new LoanScheduleNewData(currency, periods, loanTermInDays, cumulativePrincipalDisbursed, cumulativePrincipalDue, cumulativePrincipalPaid, cumulativePrincipalOutstanding, @@ -335,6 +348,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { return "l.id as id, l.external_id as externalId, l.fund_id as fundId, f.name as fundName, " + " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription, c.id as clientId, c.display_name as clientName, " + " c.office_id as clientOfficeId,l.submittedon_date as submittedOnDate," + + " l.total_charges_due_at_disbursement_derived as totalDisbursementCharges," + " l.approvedon_date as approvedOnDate, l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate," + " l.interest_calculated_from_date as interestChargedFromDate, l.closedon_date as closedOnDate, l.expected_maturedon_date as expectedMaturityDate, " + " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery," @@ -398,6 +412,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { BigDecimal principal = rs.getBigDecimal("principal"); BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance"); + BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges"); Integer numberOfRepayments = JdbcSupport.getInteger(rs,"numberOfRepayments"); Integer repaymentEvery = JdbcSupport.getInteger(rs,"repaymentEvery"); @@ -454,7 +469,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { interestCalculationPeriodType, status, lifeCycleStatusDate, termFrequency, termPeriodFrequencyType, transactionStrategyId, charges, - loanOfficerId, loanOfficerName); + loanOfficerId, loanOfficerName, totalDisbursementCharges); } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanSchedulePeriodDataWrapper.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanSchedulePeriodDataWrapper.java index 92d38e482..113812148 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanSchedulePeriodDataWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanSchedulePeriodDataWrapper.java @@ -100,4 +100,22 @@ public class LoanSchedulePeriodDataWrapper { } return cumulativeValue; } + + public Integer deriveCumulativeLoanTermInDays() { + Integer cumulativeValue = Integer.valueOf(0); + for (LoanSchedulePeriodData period : this.periods) { + if (period.daysInPeriod() != null) { + cumulativeValue += period.daysInPeriod(); + } + } + return cumulativeValue; + } + + public BigDecimal deriveCumulativeTotalOverdue() { + BigDecimal cumulativeValue = BigDecimal.ZERO; + for (LoanSchedulePeriodData period : this.periods) { + cumulativeValue = cumulativeValue.add(period.totalOverdue()); + } + return cumulativeValue; + } } \ No newline at end of file