diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanScheduleAccrualData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanScheduleAccrualData.java index 7c6273931..7d53d34a2 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanScheduleAccrualData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanScheduleAccrualData.java @@ -34,13 +34,15 @@ public class LoanScheduleAccrualData { private final CurrencyData currencyData; private final BigDecimal dueDateFeeIncome; private final BigDecimal dueDatePenaltyIncome; + private final LocalDate interestCalculatedFrom; public LoanScheduleAccrualData(final Long loanId, final Long officeId, final LocalDate accruedTill, final Integer numberOfDaysInMonth, final Integer numberOfDaysInYear, final PeriodFrequencyType repaymentFrequency, final Integer repayEvery, final LocalDate dueDate, final LocalDate fromDate, final Long repaymentScheduleId, final Long loanProductId, final BigDecimal interestIncome, final BigDecimal feeIncome, final BigDecimal penaltyIncome, final BigDecimal accruedInterestIncome, final BigDecimal accruedFeeIncome, final BigDecimal accruedPenaltyIncome, - final CurrencyData currencyData, final BigDecimal dueDateFeeIncome, final BigDecimal dueDatePenaltyIncome) { + final CurrencyData currencyData, final BigDecimal dueDateFeeIncome, final BigDecimal dueDatePenaltyIncome, + final LocalDate interestCalculatedFrom) { this.loanId = loanId; this.officeId = officeId; this.accruedTill = accruedTill; @@ -61,6 +63,7 @@ public class LoanScheduleAccrualData { this.repayEvery = repayEvery; this.dueDateFeeIncome = dueDateFeeIncome; this.dueDatePenaltyIncome = dueDatePenaltyIncome; + this.interestCalculatedFrom = interestCalculatedFrom; } public Long getLoanId() { @@ -147,4 +150,9 @@ public class LoanScheduleAccrualData { return this.dueDatePenaltyIncome; } + + public LocalDate getInterestCalculatedFrom() { + return this.interestCalculatedFrom; + } + } 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 7a302c240..1dec47747 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 @@ -314,6 +314,10 @@ public class Loan extends AbstractPersistable { @Column(name = "is_npa", nullable = false) private boolean isNpa; + @Temporal(TemporalType.DATE) + @Column(name = "accrued_till") + private Date accruedTill; + public static Loan newIndividualLoanApplication(final String accountNo, final Client client, final Integer loanType, final LoanProduct loanProduct, final Fund fund, final Staff officer, final CodeValue loanPurpose, final LoanTransactionProcessingStrategy transactionProcessingStrategy, @@ -2138,7 +2142,7 @@ public class Loan extends AbstractPersistable { existingTransactionIds.addAll(findExistingTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); - + this.accruedTill = null; reverseExistingTransactions(); updateLoanSummaryDerivedFields(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java index 8707f538c..2180211c8 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java @@ -99,13 +99,14 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat StringBuilder sb = new StringBuilder(); Set loansIds = new HashSet<>(); LocalDate accruredTill = null; + Long lastLoanId = null; for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { try { if (!loansIds.contains(accrualData.getLoanId())) { if (accrualData.getDueDateAsLocaldate().isAfter(tilldate)) { - //if (accruredTill == null) { + if (accruredTill == null || lastLoanId == null || !lastLoanId.equals(accrualData.getLoanId())) { accruredTill = accrualData.getAccruedTill(); - //} + } addAccrualTillSpecificDate(tilldate, accrualData, accruredTill); } else { addAccrualAccounting(accrualData); @@ -121,20 +122,38 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat sb.append("failed to add accural transaction for repayment with id " + accrualData.getRepaymentScheduleId() + " with message " + realCause.getMessage()); } + lastLoanId = accrualData.getLoanId(); } return sb.toString(); } private void addAccrualTillSpecificDate(final LocalDate tilldate, final LoanScheduleAccrualData accrualData, final LocalDate accruredTill) throws Exception { - int totalNumberOfDays = Days.daysBetween(accrualData.getFromDateAsLocaldate(), accrualData.getDueDateAsLocaldate()).getDays(); + LocalDate interestStartDate = accrualData.getFromDateAsLocaldate(); + if (accrualData.getInterestCalculatedFrom() != null + && accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) { + if (accrualData.getInterestCalculatedFrom().isBefore(accrualData.getDueDateAsLocaldate())) { + interestStartDate = accrualData.getInterestCalculatedFrom(); + } else { + interestStartDate = accrualData.getDueDateAsLocaldate(); + } + } + + int totalNumberOfDays = Days.daysBetween(interestStartDate, accrualData.getDueDateAsLocaldate()).getDays(); LocalDate startDate = accruredTill; if (startDate == null) { startDate = accrualData.getFromDateAsLocaldate(); } + if (accrualData.getInterestCalculatedFrom() != null && startDate.isBefore(accrualData.getInterestCalculatedFrom())) { + if (accrualData.getInterestCalculatedFrom().isBefore(tilldate)) { + startDate = accrualData.getInterestCalculatedFrom(); + } else { + startDate = tilldate; + } + } int daysToBeAccrued = Days.daysBetween(startDate, tilldate).getDays(); - if (daysToBeAccrued < 1) { return; } - int daysInSchedule = Days.daysBetween(accrualData.getFromDateAsLocaldate(), tilldate).getDays(); + // if (daysToBeAccrued < 1) { return; } + int daysInSchedule = Days.daysBetween(interestStartDate, tilldate).getDays(); switch (accrualData.getRepaymentFrequency()) { case MONTHS: totalNumberOfDays = calculateTotalNumberOfDaysForMonth(totalNumberOfDays, accrualData); @@ -161,11 +180,19 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat amount = amount.add(interestportion); BigDecimal totalAccInterest = accrualData.getAccruedInterestIncome(); + BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome(); + BigDecimal totalAccFee = accrualData.getAccruedFeeIncome(); + + if (startDate.isEqual(accrualData.getFromDateAsLocaldate())) { + totalAccInterest = null; + totalAccPenalty = null; + totalAccFee = null; + } + if (totalAccInterest == null) { totalAccInterest = BigDecimal.ZERO; } totalAccInterest = totalAccInterest.add(interestportion); - BigDecimal totalAccFee = accrualData.getAccruedFeeIncome(); if (feeportion != null) { if (totalAccFee == null) { @@ -178,19 +205,19 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat feeportion = null; } } - BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome(); + if (penaltyportion != null) { if (totalAccPenalty == null) { totalAccPenalty = BigDecimal.ZERO; } penaltyportion = penaltyportion.subtract(totalAccPenalty); amount = amount.add(penaltyportion); - totalAccPenalty = totalAccFee.add(penaltyportion); + totalAccPenalty = totalAccPenalty.add(penaltyportion); if (penaltyportion.compareTo(BigDecimal.ZERO) == 0) { penaltyportion = null; } } - if (amount.compareTo(BigDecimal.ZERO) != 0) { + if (amount.compareTo(BigDecimal.ZERO) == 1) { addAccrualAccounting(accrualData, amount, interestportion, totalAccInterest, feeportion, totalAccFee, penaltyportion, totalAccPenalty, tilldate); } @@ -252,7 +279,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat feeportion = scheduleAccrualData.getFeeIncome(); totalAccFee = feeportion; if (scheduleAccrualData.getAccruedFeeIncome() != null) { - feeportion.subtract(scheduleAccrualData.getAccruedFeeIncome()); + feeportion = feeportion.subtract(scheduleAccrualData.getAccruedFeeIncome()); } amount = amount.add(feeportion); if (feeportion.compareTo(BigDecimal.ZERO) == 0) { @@ -266,7 +293,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat penaltyportion = scheduleAccrualData.getPenaltyIncome(); totalAccPenalty = penaltyportion; if (scheduleAccrualData.getAccruedPenaltyIncome() != null) { - penaltyportion.subtract(scheduleAccrualData.getAccruedPenaltyIncome()); + penaltyportion = penaltyportion.subtract(scheduleAccrualData.getAccruedPenaltyIncome()); } amount = amount.add(penaltyportion); if (penaltyportion.compareTo(BigDecimal.ZERO) == 0) { 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 9299d808e..794cbc21d 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 @@ -1422,8 +1422,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final StringBuilder sqlBuilder = new StringBuilder(400); sqlBuilder .append("loan.id as loanId ,if(loan.client_id is null,mg.office_id,mc.office_id) as officeId,") - .append("ifnull(loan.accrued_till, ifnull(loan.interest_calculated_from_date, loan.disbursedon_date)) as accruedTill, ") - .append("loan.repayment_period_frequency_enum as frequencyEnum, ") + .append("loan.accrued_till as accruedTill, loan.repayment_period_frequency_enum as frequencyEnum, ") + .append("loan.interest_calculated_from_date as interestCalculatedFrom, ") .append("loan.repay_every as repayEvery,") .append("(select sum(lc.amount) as dueamount from m_loan_charge lc where lc.loan_id = loan.id and lc.is_active = 1 and lc.waived = 0 and lc.is_penalty = 0 and lc.due_for_collection_as_of_date > ls.fromdate and lc.due_for_collection_as_of_date<= if(:tilldate < ls.duedate, :tilldate , ls.duedate)) as feedueIn,") .append("(select sum(lc.amount) as dueamount from m_loan_charge lc where lc.loan_id = loan.id and lc.is_active = 1 and lc.waived = 0 and lc.is_penalty = 1 and lc.due_for_collection_as_of_date > ls.fromdate and lc.due_for_collection_as_of_date<= if(:tilldate < ls.duedate, :tilldate , ls.duedate)) as penalitydueIn,") @@ -1447,6 +1447,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Long loanId = rs.getLong("loanId"); final Long officeId = rs.getLong("officeId"); final LocalDate accruedTill = JdbcSupport.getLocalDate(rs, "accruedTill"); + final LocalDate interestCalculatedFrom = JdbcSupport.getLocalDate(rs, "interestCalculatedFrom"); final Integer numberOfDaysInMonth = 30; final Integer numberOfDaysInYear = 360; final Integer frequencyEnum = JdbcSupport.getInteger(rs, "frequencyEnum"); @@ -1476,7 +1477,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal dueDatePenaltyIncome = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "penalitydueIn"); return new LoanScheduleAccrualData(loanId, officeId, accruedTill, numberOfDaysInMonth, numberOfDaysInYear, frequency, repayEvery, dueDate, fromDate, repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome, - accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeIncome, dueDatePenaltyIncome); + accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeIncome, dueDatePenaltyIncome, + interestCalculatedFrom); } } @@ -1532,9 +1534,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LocalDate fromDate = null; final BigDecimal dueDateFeeincome = null; final BigDecimal dueDatePenaltyIncome = null; + final LocalDate interestCalculatedFrom = null; return new LoanScheduleAccrualData(loanId, officeId, accruedTill, numberOfDaysInMonth, numberOfDaysInYear, frequency, repayEvery, dueDate, fromDate, repaymentScheduleId, loanProductId, interestIncome, feeIncome, penaltyIncome, - accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeincome, dueDatePenaltyIncome); + accruedInterestIncome, accruedFeeIncome, accruedPenaltyIncome, currencyData, dueDateFeeincome, dueDatePenaltyIncome, + interestCalculatedFrom); } } @@ -1572,7 +1576,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { sqlBuilder.append(" and mr.duedate < ? "); sqlBuilder.append(" group by ml.id"); try { - return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()) }); + return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, + new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()) }); } catch (final EmptyResultDataAccessException e) { return null; }