MIFOSX-1517 : corrected recalculation for tranche loans
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ CREATE TABLE `m_loan_transaction_temp` (
|
|||||||
INSERT INTO m_loan_transaction_temp(`id`,`loan_id`,`transaction_date`,`amount`) select lt.id, lt.loan_id,lt.transaction_date,if(lt.transaction_type_enum = 1 , IFNULL(lt.amount,0),IFNULL(-lt.principal_portion_derived,0)) from m_loan_transaction lt where lt.is_reversed=0;
|
INSERT INTO m_loan_transaction_temp(`id`,`loan_id`,`transaction_date`,`amount`) select lt.id, lt.loan_id,lt.transaction_date,if(lt.transaction_type_enum = 1 , IFNULL(lt.amount,0),IFNULL(-lt.principal_portion_derived,0)) from m_loan_transaction lt where lt.is_reversed=0;
|
||||||
|
|
||||||
|
|
||||||
UPDATE m_loan_transaction lt SET lt.outstanding_loan_balance_derived = (select sum(ltt.amount) from m_loan_transaction_temp ltt where ltt.id <= lt.id and ltt.transaction_date <= lt.transaction_date and ltt.loan_id = lt.loan_id) where lt.transaction_type_enum != 10 and lt.is_reversed = 0;
|
UPDATE m_loan_transaction lt SET lt.outstanding_loan_balance_derived = (select sum(ltt.amount) from m_loan_transaction_temp ltt where ((ltt.transaction_date = lt.transaction_date and ltt.id <= lt.id) or ltt.transaction_date < lt.transaction_date) and ltt.loan_id = lt.loan_id) where lt.transaction_type_enum != 10 and lt.is_reversed = 0;
|
||||||
|
|
||||||
DROP TABLE `m_loan_transaction_temp`;
|
DROP TABLE `m_loan_transaction_temp`;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -354,9 +354,9 @@ public class LoansApiResource {
|
|||||||
|
|
||||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
|
||||||
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData,
|
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData,
|
||||||
disbursementData);
|
disbursementData, loanBasicDetails.isInterestRecalculationEnabled());
|
||||||
|
|
||||||
if (associationParameters.contains("futureSchedule")) {
|
if (associationParameters.contains("futureSchedule") && loanBasicDetails.isInterestRecalculationEnabled()) {
|
||||||
mandatoryResponseParameters.add("futureSchedule");
|
mandatoryResponseParameters.add("futureSchedule");
|
||||||
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
|
this.calculationPlatformService.updateFutureSchedule(repaymentSchedule, loanId);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -1817,7 +1817,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||||
}
|
}
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|
||||||
&& fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now())) {
|
&& (fetchRepaymentScheduleInstallment(1).getDueDate().isBefore(LocalDate.now()) || isDisbursementMissed())) {
|
||||||
LocalDate recalculateFrom = null;
|
LocalDate recalculateFrom = null;
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
regenerateRepaymentScheduleWithInterestRecalculation(loanScheduleFactory, currency, calculatedRepaymentsStartingFromDate,
|
||||||
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
isHolidayEnabled, holidays, workingDays, calendarInstanceForInterestRecalculation, recalculateFrom);
|
||||||
@@ -1960,6 +1960,18 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDisbursementMissed() {
|
||||||
|
boolean isDisbursementMissed = false;
|
||||||
|
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
|
||||||
|
if (disbursementDetail.actualDisbursementDate() == null
|
||||||
|
&& LocalDate.now().isAfter(disbursementDetail.expectedDisbursementDateAsLocalDate())) {
|
||||||
|
isDisbursementMissed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isDisbursementMissed;
|
||||||
|
}
|
||||||
|
|
||||||
private BigDecimal getDisbursedAmount() {
|
private BigDecimal getDisbursedAmount() {
|
||||||
BigDecimal principal = BigDecimal.ZERO;
|
BigDecimal principal = BigDecimal.ZERO;
|
||||||
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
|
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
|
||||||
|
|||||||
+12
-7
@@ -24,6 +24,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
|||||||
@Table(name = "m_loan_disbursement_detail")
|
@Table(name = "m_loan_disbursement_detail")
|
||||||
public class LoanDisbursementDetails extends AbstractPersistable<Long> {
|
public class LoanDisbursementDetails extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "loan_id", nullable = false)
|
@JoinColumn(name = "loan_id", nullable = false)
|
||||||
private Loan loan;
|
private Loan loan;
|
||||||
@@ -77,6 +78,14 @@ public class LoanDisbursementDetails extends AbstractPersistable<Long> {
|
|||||||
return this.expectedDisbursementDate;
|
return this.expectedDisbursementDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocalDate expectedDisbursementDateAsLocalDate() {
|
||||||
|
LocalDate expectedDisburseDate = null;
|
||||||
|
if (this.expectedDisbursementDate != null) {
|
||||||
|
expectedDisburseDate = new LocalDate(this.expectedDisbursementDate);
|
||||||
|
}
|
||||||
|
return expectedDisburseDate;
|
||||||
|
}
|
||||||
|
|
||||||
public Date actualDisbursementDate() {
|
public Date actualDisbursementDate() {
|
||||||
return this.actualDisbursementDate;
|
return this.actualDisbursementDate;
|
||||||
}
|
}
|
||||||
@@ -102,14 +111,10 @@ public class LoanDisbursementDetails extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DisbursementData toData() {
|
public DisbursementData toData() {
|
||||||
LocalDate expectedDisburseDate = null;
|
LocalDate expectedDisburseDate = expectedDisbursementDateAsLocalDate();
|
||||||
LocalDate actualDisburseDate = null;
|
LocalDate actualDisburseDate = null;
|
||||||
if (this.expectedDisbursementDate != null) {
|
if (this.actualDisbursementDate != null) {
|
||||||
expectedDisburseDate = new LocalDate(this.expectedDisbursementDate);
|
actualDisburseDate = new LocalDate(this.actualDisbursementDate);
|
||||||
actualDisburseDate = expectedDisburseDate;
|
|
||||||
}
|
|
||||||
if (getDisbursementDate() != null) {
|
|
||||||
actualDisburseDate = new LocalDate(getDisbursementDate());
|
|
||||||
}
|
}
|
||||||
return new DisbursementData(getId(), expectedDisburseDate, actualDisburseDate, this.principal, this.approvedPrincipal);
|
return new DisbursementData(getId(), expectedDisburseDate, actualDisburseDate, this.principal, this.approvedPrincipal);
|
||||||
}
|
}
|
||||||
|
|||||||
+172
-67
@@ -158,20 +158,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int daysInPeriod = Days.daysBetween(periodStartDate, scheduledDueDate).getDays();
|
final int daysInPeriod = Days.daysBetween(periodStartDate, scheduledDueDate).getDays();
|
||||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
|
||||||
loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate);
|
|
||||||
BigDecimal disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, scheduledDueDate, periods,
|
|
||||||
BigDecimal.ZERO);
|
|
||||||
principalDisbursed = principalDisbursed.plus(disburseAmt);
|
|
||||||
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseAmt));
|
|
||||||
outstandingBalance = outstandingBalance.plus(disburseAmt);
|
|
||||||
if (loanApplicationTerms.getMaxOutstandingBalance() != null
|
|
||||||
&& outstandingBalance.isGreaterThan(loanApplicationTerms.getMaxOutstandingBalance())) {
|
|
||||||
String errorMsg = "Outstanding balance must not exceed the amount: " + loanApplicationTerms.getMaxOutstandingBalance();
|
|
||||||
throw new MultiDisbursementOutstandingAmoutException(errorMsg, loanApplicationTerms.getMaxOutstandingBalance()
|
|
||||||
.getAmount(), disburseAmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int daysInPeriodApplicableForInterest = daysInPeriod;
|
int daysInPeriodApplicableForInterest = daysInPeriod;
|
||||||
|
|
||||||
if (periodStartDate.isBefore(idealDisbursementDate)) {
|
if (periodStartDate.isBefore(idealDisbursementDate)) {
|
||||||
@@ -203,8 +189,37 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest,
|
.calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest,
|
||||||
scheduledDueDateAsPerFrequency, loanApplicationTerms.getInterestChargedFromLocalDate(),
|
scheduledDueDateAsPerFrequency, loanApplicationTerms.getInterestChargedFromLocalDate(),
|
||||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
||||||
|
BigDecimal interestToBeAdded = BigDecimal.ZERO;
|
||||||
|
BigDecimal disburseAmt = BigDecimal.ZERO;
|
||||||
|
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||||
|
loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate);
|
||||||
|
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||||
|
disburseAmt = disbursementForPeriod(loanApplicationTerms, periodStartDate, scheduledDueDate, disbursementDatas,
|
||||||
|
diffAmt != null);
|
||||||
|
principalDisbursed = principalDisbursed.plus(disburseAmt);
|
||||||
|
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseAmt));
|
||||||
|
outstandingBalance = outstandingBalance.plus(disburseAmt);
|
||||||
|
if (loanApplicationTerms.getMaxOutstandingBalance() != null
|
||||||
|
&& outstandingBalance.isGreaterThan(loanApplicationTerms.getMaxOutstandingBalance())) {
|
||||||
|
String errorMsg = "Outstanding balance must not exceed the amount: " + loanApplicationTerms.getMaxOutstandingBalance();
|
||||||
|
throw new MultiDisbursementOutstandingAmoutException(errorMsg, loanApplicationTerms.getMaxOutstandingBalance()
|
||||||
|
.getAmount(), disburseAmt);
|
||||||
|
}
|
||||||
|
for (DisbursementData disbursementData : disbursementDatas) {
|
||||||
|
Money disbursedAmt = Money.of(currency, disbursementData.amount());
|
||||||
|
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod.disbursement(
|
||||||
|
disbursementData.disbursementDate(), disbursedAmt, chargesDueAtTimeOfDisbursement);
|
||||||
|
periods.add(disbursementPeriod);
|
||||||
|
if (disbursementData.disbursementDate().isAfter(periodStartDateApplicableForInterest)) {
|
||||||
|
interestToBeAdded = interestToBeAdded.add(calculateInterestForSpecificDays(mc, loanApplicationTerms, periodNumber,
|
||||||
|
totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableInFullInstallment,
|
||||||
|
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, disbursementData.disbursementDate(),
|
||||||
|
scheduledDueDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Money balanceForcalculation = outstandingBalance;
|
Money balanceForcalculation = outstandingBalance.minus(disburseAmt);
|
||||||
// reduce principal is the early payment, will processed as per the
|
// reduce principal is the early payment, will processed as per the
|
||||||
// reschedule strategy
|
// reschedule strategy
|
||||||
if (reducePrincipal.isGreaterThanZero()) {
|
if (reducePrincipal.isGreaterThanZero()) {
|
||||||
@@ -249,53 +264,36 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
// update cumulative fields for principal & interest
|
// update cumulative fields for principal & interest
|
||||||
Money interestForThisinstallment = principalInterestForThisPeriod.interest();
|
Money interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||||
|
|
||||||
if (daysCalcForInstallmentNumber == periodNumber) {
|
if (daysCalcForInstallmentNumber == periodNumber) {
|
||||||
interestForThisinstallment = interestForThisinstallment.zero().plus(
|
interestForThisinstallment = interestForThisinstallment.zero().plus(
|
||||||
calculateInterestForDays(daysInPeriodApplicableInFullInstallment, interestForThisinstallment.getAmount(),
|
calculateInterestForDays(daysInPeriodApplicableInFullInstallment, interestForThisinstallment.getAmount(),
|
||||||
daysInPeriodApplicableForInterest));
|
daysInPeriodApplicableForInterest));
|
||||||
}
|
}
|
||||||
Money principalForThisPeriod = principalDisbursed.zero();
|
|
||||||
Money outstandingForThePeriod = outstandingBalance;
|
|
||||||
// Exclude principal portion for interest only installments
|
|
||||||
if (!recalculatedInterestComponent) {
|
|
||||||
principalForThisPeriod = principalInterestForThisPeriod.principal();
|
|
||||||
if (daysCalcForInstallmentNumber == periodNumber && loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
|
|
||||||
principalForThisPeriod = principalForThisPeriod.plus(principalInterestForThisPeriod.interest()).minus(
|
|
||||||
interestForThisinstallment);
|
|
||||||
}
|
|
||||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(principalForThisPeriod);
|
|
||||||
|
|
||||||
// 6. update outstandingLoanBlance using correct 'principalDue'
|
|
||||||
outstandingBalance = outstandingBalance.minus(principalForThisPeriod);
|
|
||||||
}
|
|
||||||
|
|
||||||
totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment);
|
|
||||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||||
|
|
||||||
Money actualOutstandingbalance = outstandingBalance;
|
if (interestForThisinstallment.isGreaterThanZero()) {
|
||||||
|
interestForThisinstallment = interestForThisinstallment.plus(interestToBeAdded);
|
||||||
|
} else if (principalInterestForThisPeriod.interestPaymentDueToGrace().isGreaterThanZero()) {
|
||||||
|
totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace.minus(interestToBeAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
Money principalForThisPeriod = principalDisbursed.zero();
|
||||||
|
Money outstandingForThePeriod = outstandingBalance;
|
||||||
|
Money reducePrincipalForCurrentInstallment = reducePrincipal;
|
||||||
|
|
||||||
|
totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment);
|
||||||
|
|
||||||
Money feeChargesForInstallment = principalDisbursed.zero();
|
Money feeChargesForInstallment = principalDisbursed.zero();
|
||||||
Money penaltyChargesForInstallment = principalDisbursed.zero();
|
Money penaltyChargesForInstallment = principalDisbursed.zero();
|
||||||
|
|
||||||
if (principalForThisPeriod.isGreaterThan(reducePrincipal)) {
|
|
||||||
principalForThisPeriod = principalForThisPeriod.minus(reducePrincipal);
|
|
||||||
reducePrincipal = reducePrincipal.zero();
|
|
||||||
} else {
|
|
||||||
reducePrincipal = reducePrincipal.minus(principalForThisPeriod);
|
|
||||||
principalForThisPeriod = principalForThisPeriod.zero();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (periodNumber == 1) {
|
|
||||||
fixedEmiAmount = principalForThisPeriod.plus(interestForThisinstallment);
|
|
||||||
}
|
|
||||||
|
|
||||||
Money extraPrincipal = reducePrincipal.zero();
|
Money extraPrincipal = reducePrincipal.zero();
|
||||||
|
Money canBeReducedFromReducePrincipal = reducePrincipal.zero();
|
||||||
// this block is to identify interest based on late/early payment
|
// this block is to identify interest based on late/early payment
|
||||||
if (diffAmt != null && !diffAmt.isEmpty()) {
|
if (diffAmt != null && !diffAmt.isEmpty()) {
|
||||||
BigDecimal interestDueToLatePayment = BigDecimal.ZERO;
|
BigDecimal interestDueToLatePayment = BigDecimal.ZERO;
|
||||||
BigDecimal interestReducedDueToEarlyPayment = BigDecimal.ZERO;
|
BigDecimal interestReducedDueToEarlyPayment = BigDecimal.ZERO;
|
||||||
|
|
||||||
boolean isperiodPrincipalReduced = false;
|
|
||||||
for (RecalculationDetail detail : diffAmt) {
|
for (RecalculationDetail detail : diffAmt) {
|
||||||
if (!detail.isInterestompound()) {
|
if (!detail.isInterestompound()) {
|
||||||
// will increase the principal portion and reduces
|
// will increase the principal portion and reduces
|
||||||
@@ -307,9 +305,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
reducePrincipal = reducePrincipal.plus(detail.getAmount());
|
reducePrincipal = reducePrincipal.plus(detail.getAmount());
|
||||||
extraPrincipal = extraPrincipal.plus(detail.getAmount());
|
extraPrincipal = extraPrincipal.plus(detail.getAmount());
|
||||||
int diffDays = Days.daysBetween(detail.getStartDate(), scheduledDueDate).getDays();
|
int diffDays = Days.daysBetween(detail.getStartDate(), scheduledDueDate).getDays();
|
||||||
if (diffDays > 0 && !isperiodPrincipalReduced) {
|
if (diffDays > 0) {
|
||||||
reducePrincipal = reducePrincipal.minus(principalForThisPeriod);
|
canBeReducedFromReducePrincipal = canBeReducedFromReducePrincipal.plus(detail.getAmount());
|
||||||
isperiodPrincipalReduced = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDate startDate = detail.getStartDate();
|
LocalDate startDate = detail.getStartDate();
|
||||||
@@ -363,16 +360,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reducePrincipal.isLessThanZero()) {
|
|
||||||
reducePrincipal = reducePrincipal.zero();
|
|
||||||
} else {
|
|
||||||
Money actualOutstanding = outstandingBalance.minus(reducePrincipal);
|
|
||||||
principalForThisPeriod = reducePrincipal.plus(principalForThisPeriod);
|
|
||||||
if (actualOutstanding.isLessThanZero()) {
|
|
||||||
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalOutstandingInterestPaymentDueToGrace.isGreaterThanZero()) {
|
if (totalOutstandingInterestPaymentDueToGrace.isGreaterThanZero()) {
|
||||||
totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace.plus(interestDueToLatePayment)
|
totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace.plus(interestDueToLatePayment)
|
||||||
.minus(interestReducedDueToEarlyPayment);
|
.minus(interestReducedDueToEarlyPayment);
|
||||||
@@ -384,7 +371,60 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exclude principal portion for interest only installments
|
||||||
|
if (!recalculatedInterestComponent) {
|
||||||
|
principalForThisPeriod = principalInterestForThisPeriod.principal();
|
||||||
|
if (/* daysCalcForInstallmentNumber == periodNumber && */loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
|
||||||
|
principalForThisPeriod = principalForThisPeriod.plus(principalInterestForThisPeriod.interest()).minus(
|
||||||
|
interestForThisinstallment);
|
||||||
|
principalForThisPeriod = loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisPeriod,
|
||||||
|
totalCumulativePrincipal.plus(principalForThisPeriod), periodNumber);
|
||||||
|
}
|
||||||
|
totalCumulativePrincipal = totalCumulativePrincipal.plus(principalForThisPeriod);
|
||||||
|
|
||||||
|
// 6. update outstandingLoanBlance using correct 'principalDue'
|
||||||
|
outstandingBalance = outstandingBalance.minus(principalForThisPeriod);
|
||||||
|
if (outstandingBalance.isLessThanZero()) {
|
||||||
|
principalForThisPeriod = principalForThisPeriod.plus(outstandingBalance);
|
||||||
|
outstandingBalance = outstandingBalance.zero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Money actualOutstandingbalance = outstandingBalance;
|
||||||
|
if (diffAmt != null && !diffAmt.isEmpty()) {
|
||||||
|
reducePrincipal = reducePrincipal.minus(canBeReducedFromReducePrincipal);
|
||||||
|
Money pricipalAfterCurrentPrincipal = canBeReducedFromReducePrincipal.minus(principalForThisPeriod);
|
||||||
|
if (pricipalAfterCurrentPrincipal.isGreaterThanZero()) {
|
||||||
|
reducePrincipal = reducePrincipal.plus(pricipalAfterCurrentPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reducePrincipal.isLessThanZero()) {
|
||||||
|
reducePrincipal = reducePrincipal.zero();
|
||||||
|
} else {
|
||||||
|
Money actualOutstanding = outstandingBalance.minus(reducePrincipal);
|
||||||
|
principalForThisPeriod = reducePrincipal.plus(principalForThisPeriod);
|
||||||
|
if (actualOutstanding.isLessThanZero()) {
|
||||||
|
principalForThisPeriod = principalForThisPeriod.plus(actualOutstanding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (principalForThisPeriod.isGreaterThan(reducePrincipalForCurrentInstallment)) {
|
||||||
|
principalForThisPeriod = principalForThisPeriod.minus(reducePrincipalForCurrentInstallment);
|
||||||
|
reducePrincipal = reducePrincipal.minus(reducePrincipalForCurrentInstallment);
|
||||||
|
} else {
|
||||||
|
reducePrincipal = reducePrincipal.minus(principalForThisPeriod);
|
||||||
|
principalForThisPeriod = principalForThisPeriod.zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (periodNumber == 1) {
|
||||||
|
fixedEmiAmount = principalForThisPeriod.plus(interestForThisinstallment);
|
||||||
|
}
|
||||||
|
|
||||||
actualOutstandingbalance = actualOutstandingbalance.minus(reducePrincipal);
|
actualOutstandingbalance = actualOutstandingbalance.minus(reducePrincipal);
|
||||||
|
if (actualOutstandingbalance.isLessThanZero()) {
|
||||||
|
actualOutstandingbalance = actualOutstandingbalance.zero();
|
||||||
|
}
|
||||||
|
|
||||||
// 8. sum up real totalInstallmentDue from components
|
// 8. sum up real totalInstallmentDue from components
|
||||||
final Money totalInstallmentDue = principalForThisPeriod//
|
final Money totalInstallmentDue = principalForThisPeriod//
|
||||||
@@ -415,7 +455,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
instalmentNumber++;
|
instalmentNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (principalDisbursed.isNotEqualTo(expectedPrincipalDisburse)) {
|
if (principalDisbursed.isNotEqualTo(expectedPrincipalDisburse) && diffAmt == null) {
|
||||||
final String errorMsg = "One of the Disbursement date is not falling on Loan Schedule";
|
final String errorMsg = "One of the Disbursement date is not falling on Loan Schedule";
|
||||||
throw new MultiDisbursementDisbursementDateException(errorMsg);
|
throw new MultiDisbursementDisbursementDateException(errorMsg);
|
||||||
}
|
}
|
||||||
@@ -870,17 +910,31 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal disbursementForPeriod(final LoanApplicationTerms loanApplicationTerms, LocalDate startDate, LocalDate endDate,
|
private BigDecimal disbursementForPeriod(final LoanApplicationTerms loanApplicationTerms, LocalDate startDate, LocalDate endDate,
|
||||||
final Collection<LoanScheduleModelPeriod> periods, final BigDecimal chargesDueAtTimeOfDisbursement) {
|
final Collection<DisbursementData> disbursementDatas, boolean excludePastUndisbursed) {
|
||||||
BigDecimal principal = BigDecimal.ZERO;
|
BigDecimal principal = BigDecimal.ZERO;
|
||||||
MonetaryCurrency currency = loanApplicationTerms.getPrincipal().getCurrency();
|
|
||||||
for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
|
for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
|
||||||
if (disbursementData.isDueForDisbursement(startDate, endDate)) {
|
if (!excludePastUndisbursed
|
||||||
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod.disbursement(
|
|| (excludePastUndisbursed && (disbursementData.isDisbursed() || !disbursementData.disbursementDate().isBefore(
|
||||||
disbursementData.disbursementDate(), Money.of(currency, disbursementData.amount()), chargesDueAtTimeOfDisbursement);
|
LocalDate.now())))) {
|
||||||
periods.add(disbursementPeriod);
|
if (disbursementData.isDueForDisbursement(startDate, endDate)) {
|
||||||
|
disbursementDatas.add(disbursementData);
|
||||||
|
principal = principal.add(disbursementData.amount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal disbursementAfterPeriod(final LoanApplicationTerms loanApplicationTerms, LocalDate endDate,
|
||||||
|
LocalDate lastinstallmentDueDate) {
|
||||||
|
BigDecimal principal = BigDecimal.ZERO;
|
||||||
|
for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
|
||||||
|
|
||||||
|
if (disbursementData.disbursementDate().isAfter(endDate) && lastinstallmentDueDate.isAfter(disbursementData.disbursementDate())) {
|
||||||
principal = principal.add(disbursementData.amount());
|
principal = principal.add(disbursementData.amount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return principal;
|
return principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1413,6 +1467,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
Money inerestForCurrentInstallment = Money.zero(currency);
|
Money inerestForCurrentInstallment = Money.zero(currency);
|
||||||
Money principalOutstanding = Money.zero(currency);
|
Money principalOutstanding = Money.zero(currency);
|
||||||
Integer periodNumber = 0;
|
Integer periodNumber = 0;
|
||||||
|
LocalDate lastDueDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||||
if (currentInstallment.isNotFullyPaidOff()) {
|
if (currentInstallment.isNotFullyPaidOff()) {
|
||||||
if (!currentInstallment.getDueDate().isAfter(onDate)) {
|
if (!currentInstallment.getDueDate().isAfter(onDate)) {
|
||||||
@@ -1443,6 +1498,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!currentInstallment.isRecalculatedInterestComponent() && currentInstallment.getDueDate().isAfter(lastDueDate)) {
|
||||||
|
lastDueDate = currentInstallment.getDueDate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (interestChargedFromLocalDate != null && calculateInterestFrom.isBefore(interestChargedFromLocalDate)) {
|
if (interestChargedFromLocalDate != null && calculateInterestFrom.isBefore(interestChargedFromLocalDate)) {
|
||||||
calculateInterestFrom = interestChargedFromLocalDate;
|
calculateInterestFrom = interestChargedFromLocalDate;
|
||||||
@@ -1463,6 +1521,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
if (useDailyInterest) {
|
if (useDailyInterest) {
|
||||||
interestForInstallment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
interestForInstallment = loanApplicationTerms.interestRateFor(this.paymentPeriodsInOneYearCalculator, mc,
|
||||||
principalOutstanding, calculateInterestFrom, repaymentDueDate);
|
principalOutstanding, calculateInterestFrom, repaymentDueDate);
|
||||||
|
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment));
|
||||||
|
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, interestForInstallment, days));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
||||||
@@ -1485,13 +1545,58 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
loanApplicationTerms.getInterestChargedFromLocalDate(),
|
loanApplicationTerms.getInterestChargedFromLocalDate(),
|
||||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
|
||||||
|
|
||||||
|
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||||
|
BigDecimal reducePrincipal = disbursementAfterPeriod(loanApplicationTerms, repaymentDueDate, lastDueDate);
|
||||||
|
principalOutstanding = principalOutstanding.minus(reducePrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
PrincipalInterest principalInterest = loanApplicationTerms.calculateTotalInterestForPeriod(
|
PrincipalInterest principalInterest = loanApplicationTerms.calculateTotalInterestForPeriod(
|
||||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc,
|
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc,
|
||||||
totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, principalOutstanding);
|
totalOutstandingInterestPaymentDueToGrace.zero(), daysInPeriodApplicableForInterest, principalOutstanding);
|
||||||
interestForInstallment = principalInterest.interest().getAmount();
|
interestForInstallment = principalInterest.interest().getAmount();
|
||||||
|
Money alteredPrincipal = principalOutstanding;
|
||||||
|
Money reducePricipal = principalOutstanding.zero();
|
||||||
|
BigDecimal interestToBeReduced = BigDecimal.ZERO;
|
||||||
|
BigDecimal interestForExtraPrincipal = BigDecimal.ZERO;
|
||||||
|
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||||
|
final Collection<DisbursementData> disbursementDatas = new ArrayList<>();
|
||||||
|
BigDecimal addedPrincipal = disbursementForPeriod(loanApplicationTerms, calculateInterestFrom, repaymentDueDate,
|
||||||
|
disbursementDatas, true);
|
||||||
|
alteredPrincipal = alteredPrincipal.minus(addedPrincipal);
|
||||||
|
for (DisbursementData disbursementData : disbursementDatas) {
|
||||||
|
Money disbursedAmt = Money.of(currency, disbursementData.amount());
|
||||||
|
if (disbursementData.disbursementDate().isAfter(calculateInterestFrom)) {
|
||||||
|
LocalDate calculateTill = disbursementData.disbursementDate();
|
||||||
|
interestToBeReduced = interestToBeReduced.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
|
||||||
|
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||||
|
interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt, calculateInterestFrom, calculateTill));
|
||||||
|
|
||||||
|
if (onDate.isAfter(calculateTill)) {
|
||||||
|
interestForExtraPrincipal = interestForExtraPrincipal.add(calculateInterestForSpecificDays(mc,
|
||||||
|
loanApplicationTerms, periodNumber, totalOutstandingInterestPaymentDueToGrace,
|
||||||
|
daysInPeriodApplicableForInterest, interestCalculationGraceOnRepaymentPeriodFraction, disbursedAmt,
|
||||||
|
calculateTill, onDate));
|
||||||
|
} else {
|
||||||
|
reducePricipal = reducePricipal.plus(disbursedAmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment).plus(interestToBeReduced));
|
||||||
|
BigDecimal interestForCloseDate = BigDecimal.ZERO;
|
||||||
|
if (alteredPrincipal.isNotEqualTo(principalOutstanding)) {
|
||||||
|
interestForCloseDate = interestForExtraPrincipal;
|
||||||
|
interestForCloseDate = interestForCloseDate.add(calculateInterestForSpecificDays(mc, loanApplicationTerms,
|
||||||
|
periodNumber, totalOutstandingInterestPaymentDueToGrace, daysInPeriodApplicableForInterest,
|
||||||
|
interestCalculationGraceOnRepaymentPeriodFraction, alteredPrincipal, calculateInterestFrom, onDate));
|
||||||
|
} else {
|
||||||
|
interestForCloseDate = interestForCloseDate.add(BigDecimal.valueOf(calculateInterestForDays(
|
||||||
|
daysInPeriodApplicableForInterest, interestForInstallment, days)));
|
||||||
|
}
|
||||||
|
interest = interest.plus(interestForCloseDate);
|
||||||
|
principalOutstanding = principalOutstanding.minus(reducePricipal);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
interest = interest.plus(inerestForCurrentInstallment.minus(interestForInstallment));
|
|
||||||
interest = interest.plus(calculateInterestForDays(daysInPeriodApplicableForInterest, interestForInstallment, days));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -397,7 +397,7 @@ public class LoanScheduleAssembler {
|
|||||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
|
|
||||||
CalendarInstance calendarInstance = loanApplicationTerms.getRestCalendarInstance();
|
CalendarInstance calendarInstance = loanApplicationTerms.getRestCalendarInstance();
|
||||||
LocalDate nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), onDate);
|
LocalDate nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), onDate.minusDays(1));
|
||||||
if (loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) {
|
if (loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) {
|
||||||
nextScheduleDate = scheduledDateGenerator.adjustRepaymentDate(nextScheduleDate, loanApplicationTerms, isHolidayEnabled,
|
nextScheduleDate = scheduledDateGenerator.adjustRepaymentDate(nextScheduleDate, loanApplicationTerms, isHolidayEnabled,
|
||||||
holidays, workingDays);
|
holidays, workingDays);
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ public interface LoanReadPlatformService {
|
|||||||
LoanAccountData retrieveOne(Long loanId);
|
LoanAccountData retrieveOne(Long loanId);
|
||||||
|
|
||||||
LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData,
|
LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData,
|
||||||
Collection<DisbursementData> disbursementData);
|
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled);
|
||||||
|
|
||||||
Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
|
Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
|
||||||
|
|
||||||
|
|||||||
+26
-13
@@ -177,13 +177,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
|
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
|
||||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData) {
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection<DisbursementData> disbursementData,
|
||||||
|
boolean isInterestRecalculationEnabled) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor(
|
||||||
repaymentScheduleRelatedLoanData, disbursementData);
|
repaymentScheduleRelatedLoanData, disbursementData, isInterestRecalculationEnabled);
|
||||||
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment";
|
||||||
|
|
||||||
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, fullResultsetExtractor, new Object[] { loanId });
|
||||||
@@ -862,15 +863,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private final Collection<DisbursementData> disbursementData;
|
private final Collection<DisbursementData> disbursementData;
|
||||||
private LocalDate lastDueDate;
|
private LocalDate lastDueDate;
|
||||||
private BigDecimal outstandingLoanPrincipalBalance;
|
private BigDecimal outstandingLoanPrincipalBalance;
|
||||||
|
private boolean excludePastUndisbursed;
|
||||||
|
|
||||||
public LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
public LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
|
||||||
Collection<DisbursementData> disbursementData) {
|
Collection<DisbursementData> disbursementData, boolean isInterestRecalculationEnabled) {
|
||||||
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
this.currency = repaymentScheduleRelatedLoanData.getCurrency();
|
||||||
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
this.disbursement = repaymentScheduleRelatedLoanData.disbursementData();
|
||||||
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement();
|
||||||
this.lastDueDate = this.disbursement.disbursementDate();
|
this.lastDueDate = this.disbursement.disbursementDate();
|
||||||
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
this.outstandingLoanPrincipalBalance = this.disbursement.amount();
|
||||||
this.disbursementData = disbursementData;
|
this.disbursementData = disbursementData;
|
||||||
|
this.excludePastUndisbursed = isInterestRecalculationEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
@@ -899,6 +902,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
periods.add(disbursementPeriod);
|
periods.add(disbursementPeriod);
|
||||||
totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.amount()).getAmount();
|
totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.amount()).getAmount();
|
||||||
} else {
|
} else {
|
||||||
|
if (!this.disbursement.isDisbursed()) {
|
||||||
|
excludePastUndisbursed = false;
|
||||||
|
}
|
||||||
this.outstandingLoanPrincipalBalance = BigDecimal.ZERO;
|
this.outstandingLoanPrincipalBalance = BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,7 +936,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||||
final LocalDate obligationsMetOnDate = JdbcSupport.getLocalDate(rs, "obligationsMetOnDate");
|
final LocalDate obligationsMetOnDate = JdbcSupport.getLocalDate(rs, "obligationsMetOnDate");
|
||||||
final boolean complete = rs.getBoolean("complete");
|
final boolean complete = rs.getBoolean("complete");
|
||||||
|
|
||||||
if (disbursementData != null) {
|
if (disbursementData != null) {
|
||||||
BigDecimal principal = BigDecimal.ZERO;
|
BigDecimal principal = BigDecimal.ZERO;
|
||||||
for (DisbursementData data : disbursementData) {
|
for (DisbursementData data : disbursementData) {
|
||||||
@@ -939,14 +944,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
|
data.disbursementDate(), data.amount(), this.totalFeeChargesDueAtDisbursement, data.isDisbursed());
|
||||||
periods.add(periodData);
|
periods.add(periodData);
|
||||||
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
principal = principal.add(data.amount());
|
} else if (data.isDueForDisbursement(fromDate, dueDate)
|
||||||
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
&& this.outstandingLoanPrincipalBalance.compareTo(BigDecimal.ZERO) == 1) {
|
||||||
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
if (!excludePastUndisbursed
|
||||||
periods.add(periodData);
|
|| (excludePastUndisbursed && (data.isDisbursed() || !data.disbursementDate().isBefore(LocalDate.now())))) {
|
||||||
|
principal = principal.add(data.amount());
|
||||||
|
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.disbursementOnlyPeriod(
|
||||||
|
data.disbursementDate(), data.amount(), BigDecimal.ZERO, data.isDisbursed());
|
||||||
|
periods.add(periodData);
|
||||||
|
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(principal);
|
|
||||||
totalPrincipalDisbursed = totalPrincipalDisbursed.add(principal);
|
totalPrincipalDisbursed = totalPrincipalDisbursed.add(principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1588,15 +1598,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
StringBuilder sqlBuilder = new StringBuilder();
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
|
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
|
||||||
sqlBuilder.append(" INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
|
sqlBuilder.append(" INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id ");
|
||||||
|
sqlBuilder.append(" LEFT JOIN m_loan_disbursement_detail dd on dd.loan_id=ml.id and dd.disbursedon_date is null ");
|
||||||
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
|
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
|
||||||
sqlBuilder.append(" and ml.interest_recalculation_enabled = 1 ");
|
sqlBuilder.append(" and ml.interest_recalculation_enabled = 1 ");
|
||||||
sqlBuilder.append(" and ml.is_npa = 0 ");
|
sqlBuilder.append(" and ml.is_npa = 0 ");
|
||||||
sqlBuilder.append(" and mr.completed_derived is false ");
|
sqlBuilder.append(" and ((");
|
||||||
sqlBuilder.append(" and mr.duedate < ? ");
|
sqlBuilder.append(" mr.completed_derived is false ");
|
||||||
|
sqlBuilder.append(" and mr.duedate < ? )");
|
||||||
|
sqlBuilder.append(" or dd.expected_disburse_date < ? ) ");
|
||||||
sqlBuilder.append(" group by ml.id");
|
sqlBuilder.append(" group by ml.id");
|
||||||
try {
|
try {
|
||||||
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
|
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
|
||||||
new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()) });
|
new Object[] { LoanStatus.ACTIVE.getValue(), formatter.print(LocalDate.now()),formatter.print(LocalDate.now()) });
|
||||||
} catch (final EmptyResultDataAccessException e) {
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -46,6 +46,6 @@ public enum AmortizationMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEqualInstallment() {
|
public boolean isEqualInstallment() {
|
||||||
return this.value.equals(AmortizationMethod.EQUAL_INSTALLMENTS);
|
return this.value.equals(AmortizationMethod.EQUAL_INSTALLMENTS.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user