FINERACT-2081: Refactor - Simplify LoanSchedulePeriodData.java class

This commit is contained in:
Adam Saghy
2024-12-11 19:10:10 +01:00
parent 263866c03a
commit d57906d4fa
12 changed files with 288 additions and 489 deletions
@@ -113,8 +113,12 @@ public final class MathUtil {
* @param notNull * @param notNull
* if true then null parameter is omitted, otherwise returns null * if true then null parameter is omitted, otherwise returns null
*/ */
public static Long min(Long first, Long second, Long third, boolean notNull) { public static Long min(boolean notNull, Long first, Long... amounts) {
return min(min(first, second, notNull), third, notNull); Long result = first;
for (Long amount : amounts) {
result = min(result, amount, notNull);
}
return result;
} }
/** @return sum the two values considering null values */ /** @return sum the two values considering null values */
@@ -123,18 +127,12 @@ public final class MathUtil {
} }
/** @return sum the values considering null values */ /** @return sum the values considering null values */
public static Long add(Long first, Long second, Long third) { public static Long add(Long... amounts) {
return add(add(first, second), third); Long result = null;
} for (Long amount : amounts) {
result = add(result, amount);
/** @return sum the values considering null values */ }
public static Long add(Long first, Long second, Long third, Long fourth) { return result;
return add(add(add(first, second), third), fourth);
}
/** @return sum the values considering null values */
public static Long add(Long first, Long second, Long third, Long fourth, Long fifth) {
return add(add(add(add(first, second), third), fourth), fifth);
} }
/** @return first minus second considering null values, maybe negative */ /** @return first minus second considering null values, maybe negative */
@@ -142,18 +140,24 @@ public final class MathUtil {
return first == null ? null : second == null ? first : Math.subtractExact(first, second); return first == null ? null : second == null ? first : Math.subtractExact(first, second);
} }
/** /** @return first minus second considering null values, maybe negative */
* @return first minus the others considering null values, maybe negative public static Long subtract(Long first, Long... amounts) {
*/ Long result = first;
public static Long subtractToZero(Long first, Long second, Long third) { for (Long amount : amounts) {
return subtractToZero(subtract(first, second), third); result = subtract(result, amount);
}
return result;
} }
/** /**
* @return first minus the others considering null values, maybe negative * @return first minus the others considering null values, maybe negative
*/ */
public static Long subtractToZero(Long first, Long second, Long third, Long fourth) { public static Long subtractToZero(Long first, Long... amounts) {
return subtractToZero(subtract(subtract(first, second), third), fourth); Long result = first;
for (Long amount : amounts) {
result = subtractToZero(result, amount);
}
return result;
} }
/** @return NONE negative first minus second considering null values */ /** @return NONE negative first minus second considering null values */
@@ -241,8 +245,12 @@ public final class MathUtil {
* @param notNull * @param notNull
* if true then null parameter is omitted, otherwise returns null * if true then null parameter is omitted, otherwise returns null
*/ */
public static BigDecimal min(BigDecimal first, BigDecimal second, BigDecimal third, boolean notNull) { public static BigDecimal min(boolean notNull, BigDecimal first, BigDecimal... amounts) {
return min(min(first, second, notNull), third, notNull); BigDecimal result = first;
for (BigDecimal amount : amounts) {
result = min(result, amount, notNull);
}
return result;
} }
/** @return sum the two values considering null values */ /** @return sum the two values considering null values */
@@ -256,44 +264,21 @@ public final class MathUtil {
} }
/** @return sum the values considering null values */ /** @return sum the values considering null values */
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third) { public static BigDecimal add(BigDecimal... amounts) {
return add(first, second, third, MoneyHelper.getMathContext()); BigDecimal result = null;
} for (BigDecimal amount : amounts) {
result = add(result, amount, MoneyHelper.getMathContext());
/** @return sum the values considering null values */ }
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, MathContext mc) { return result;
return add(add(first, second, mc), third, mc);
}
/** @return sum the values considering null values */
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
return add(first, second, third, fourth, MoneyHelper.getMathContext());
}
/** @return sum the values considering null values */
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, MathContext mc) {
return add(add(add(first, second, mc), third, mc), fourth, mc);
}
/** @return sum the values considering null values */
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth) {
return add(first, second, third, fourth, fifth, MoneyHelper.getMathContext());
}
/** @return sum the values considering null values */
public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth,
MathContext mc) {
return add(add(add(add(first, second, mc), third, mc), fourth, mc), fifth, mc);
} }
/** @return first minus second considering null values, maybe negative */ /** @return first minus second considering null values, maybe negative */
public static BigDecimal subtract(BigDecimal first, BigDecimal second) { public static BigDecimal subtract(BigDecimal first, BigDecimal... amounts) {
return subtract(first, second, MoneyHelper.getMathContext()); BigDecimal result = first;
} for (BigDecimal amount : amounts) {
result = subtract(result, amount, MoneyHelper.getMathContext());
/** @return first minus the others considering null values, maybe negative */ }
public static BigDecimal subtract(BigDecimal first, BigDecimal second, BigDecimal third) { return result;
return subtract(subtract(first, second), third);
} }
/** @return first minus second considering null values, maybe negative */ /** @return first minus second considering null values, maybe negative */
@@ -302,22 +287,9 @@ public final class MathUtil {
} }
/** @return NONE negative first minus second considering null values */ /** @return NONE negative first minus second considering null values */
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second) { public static BigDecimal subtractToZero(BigDecimal first, BigDecimal... amounts) {
return negativeToZero(subtract(first, second)); BigDecimal result = subtract(first, amounts);
} return negativeToZero(result);
/**
* @return first minus the others considering null values, maybe negative
*/
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third) {
return subtractToZero(subtract(first, second), third);
}
/**
* @return first minus the others considering null values, maybe negative
*/
public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
return subtractToZero(subtract(subtract(first, second), third), fourth);
} }
/** /**
@@ -409,39 +381,39 @@ public final class MathUtil {
return first == null ? second : second == null ? first : first.plus(second, mc); return first == null ? second : second == null ? first : first.plus(second, mc);
} }
public static Money plus(Money first, Money second, Money third) { public static Money plus(Money... multipleAmounts) {
return plus(plus(first, second), third); Money result = null;
for (Money amount : multipleAmounts) {
result = plus(result, amount);
}
return result;
} }
public static Money plus(Money first, Money second, Money third, MathContext mc) { public static Money plus(MathContext mc, Money... multipleAmounts) {
return plus(plus(first, second), third, mc); Money result = null;
} for (Money amount : multipleAmounts) {
result = plus(result, amount, mc);
public static Money plus(Money first, Money second, Money third, Money fourth) { }
return plus(plus(plus(first, second), third), fourth); return result;
} }
public static Money minus(Money first, Money second) { public static Money minus(Money first, Money second) {
return first == null ? null : second == null ? first : first.minus(second); return first == null ? null : second == null ? first : first.minus(second);
} }
/** public static Money minus(Money first, Money... multipleAmounts) {
* @return first minus the others considering null values, maybe negative Money result = first;
*/ for (Money amount : multipleAmounts) {
public static Money minusToZero(Money first, Money second, Money third) { result = minus(result, amount);
return minusToZero(minus(first, second), third); }
return result;
} }
/** /**
* @return first minus the others considering null values, maybe negative * @return first minus the others considering null values, maybe negative
*/ */
public static Money minusToZero(Money first, Money second, Money third, Money fourth) { public static Money minusToZero(Money first, Money... multipleAmounts) {
return minusToZero(minus(minus(first, second), third), fourth); return negativeToZero(minus(first, multipleAmounts));
}
/** @return NONE negative first minus second considering null values */
public static Money minusToZero(Money first, Money second) {
return negativeToZero(minus(first, second));
} }
/** /**
@@ -459,8 +431,12 @@ public final class MathUtil {
* @param notNull * @param notNull
* if true then null parameter is omitted, otherwise returns null * if true then null parameter is omitted, otherwise returns null
*/ */
public static Money min(Money first, Money second, Money third, boolean notNull) { public static Money min(boolean notNull, Money first, Money... amounts) {
return min(min(first, second, notNull), third, notNull); Money result = first;
for (Money amount : amounts) {
result = min(result, amount, notNull);
}
return result;
} }
/** @return Money null safe negate */ /** @return Money null safe negate */
@@ -227,7 +227,8 @@ public class LoanArrearsAgeingUpdateHandler {
LoanOriginalScheduleExtractor(DatabaseSpecificSQLGenerator sqlGenerator) { LoanOriginalScheduleExtractor(DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder scheduleDetail = new StringBuilder(); final StringBuilder scheduleDetail = new StringBuilder();
scheduleDetail.append("select ml.id as loanId, mr.duedate as dueDate, mr.principal_amount as principalAmount, "); scheduleDetail.append(
"select ml.id as loanId, mr.installment as installmentNumber, mr.fromdate as fromDate, mr.duedate as dueDate, mr.principal_amount as principalAmount, ");
scheduleDetail.append( scheduleDetail.append(
"mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount "); "mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount ");
scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id "); scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id ");
@@ -253,19 +254,15 @@ public class LoanArrearsAgeingUpdateHandler {
} }
private LoanSchedulePeriodData fetchLoanSchedulePeriodData(ResultSet rs) throws SQLException { private LoanSchedulePeriodData fetchLoanSchedulePeriodData(ResultSet rs) throws SQLException {
final Integer installmentNumber = JdbcSupport.getInteger(rs, "installmentNumber");
final LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate"); final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalAmount"); final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalAmount");
final BigDecimal interestDueOnPrincipalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestAmount"); final BigDecimal interestDueOnPrincipalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestAmount");
final BigDecimal totalInstallmentAmount = principalDue.add(interestDueOnPrincipalOutstanding);
final BigDecimal feeChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeAmount"); final BigDecimal feeChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeAmount");
final BigDecimal penaltyChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyAmount"); final BigDecimal penaltyChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyAmount");
final Integer periodNumber = null; return LoanSchedulePeriodData.repaymentOnlyPeriod(installmentNumber, fromDate, dueDate, principalDue, null,
final LocalDate fromDate = null; interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod);
final BigDecimal principalOutstanding = null;
final BigDecimal totalDueForPeriod = null;
return LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, fromDate, dueDate, principalDue, principalOutstanding,
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod,
totalInstallmentAmount);
} }
} }
@@ -31,7 +31,7 @@ public final class LoanScheduleModelDownPaymentPeriod implements LoanScheduleMod
private final int periodNumber; private final int periodNumber;
private final LocalDate periodDate; private final LocalDate periodDate;
private Money principalDue; private final Money principalDue;
private final Money outstandingLoanBalance; private final Money outstandingLoanBalance;
public static LoanScheduleModelDownPaymentPeriod downPayment(final int periodNumber, final LocalDate periodDate, public static LoanScheduleModelDownPaymentPeriod downPayment(final int periodNumber, final LocalDate periodDate,
@@ -20,14 +20,17 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
/** /**
* Immutable data object that represents a period of a loan schedule. * Immutable data object that represents a period of a loan schedule.
* *
*/ */
@Getter @Getter
@Builder
public final class LoanSchedulePeriodData { public final class LoanSchedulePeriodData {
private final Integer period; private final Integer period;
@@ -72,434 +75,275 @@ public final class LoanSchedulePeriodData {
private final BigDecimal totalInstallmentAmountForPeriod; private final BigDecimal totalInstallmentAmountForPeriod;
private final BigDecimal totalCredits; private final BigDecimal totalCredits;
private final BigDecimal totalAccruedInterest; private final BigDecimal totalAccruedInterest;
private final Boolean downPaymentPeriod; private final boolean downPaymentPeriod;
public static LoanSchedulePeriodData disbursementOnlyPeriod(final LocalDate disbursementDate, final BigDecimal principalDisbursed, public static LoanSchedulePeriodData disbursementOnlyPeriod(final LocalDate disbursementDate, final BigDecimal principalDisbursed,
final BigDecimal feeChargesDueAtTimeOfDisbursement, final boolean isDisbursed) { final BigDecimal feeChargesDueAtTimeOfDisbursement, final boolean isDisbursed) {
final Integer periodNumber = null; return builder().dueDate(disbursementDate) //
final LocalDate from = null; .principalDisbursed(principalDisbursed) //
return new LoanSchedulePeriodData(periodNumber, from, disbursementDate, principalDisbursed, feeChargesDueAtTimeOfDisbursement, .principalLoanBalanceOutstanding(principalDisbursed) //
isDisbursed); .feeChargesDue(feeChargesDueAtTimeOfDisbursement) //
.feeChargesPaid(isDisbursed ? feeChargesDueAtTimeOfDisbursement : null) //
.feeChargesOutstanding(isDisbursed ? null : feeChargesDueAtTimeOfDisbursement) //
.totalOriginalDueForPeriod(feeChargesDueAtTimeOfDisbursement) //
.totalDueForPeriod(feeChargesDueAtTimeOfDisbursement) //
.totalPaidForPeriod(isDisbursed ? feeChargesDueAtTimeOfDisbursement : null) //
.totalOutstandingForPeriod(isDisbursed ? null : feeChargesDueAtTimeOfDisbursement) //
.totalActualCostOfLoanForPeriod(feeChargesDueAtTimeOfDisbursement) //
.totalOverdue(DateUtils.isBeforeBusinessDate(disbursementDate) && !isDisbursed ? feeChargesDueAtTimeOfDisbursement : null) //
.build();
} }
public static LoanSchedulePeriodData repaymentOnlyPeriod(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate, public static LoanSchedulePeriodData repaymentOnlyPeriod(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
final BigDecimal principalDue, final BigDecimal principalOutstanding, final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal principalDue, final BigDecimal outstandingLoanBalance, final BigDecimal interestDue, final BigDecimal feeDue,
final BigDecimal feeChargesDueForPeriod, final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod, final BigDecimal penaltyDue) {
final BigDecimal totalInstallmentAmountForPeriod) {
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, principalDue, principalOutstanding, BigDecimal totalDue = MathUtil.add(principalDue, interestDue, feeDue, penaltyDue);
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod, BigDecimal totalActualCostOfLoanForPeriod = MathUtil.add(interestDue, feeDue, penaltyDue);
totalInstallmentAmountForPeriod); BigDecimal totalInstallmentAmount = MathUtil.add(principalDue, interestDue);
return builder().period(periodNumber) //
.fromDate(fromDate) //
.dueDate(dueDate) //
.daysInPeriod(DateUtils.getExactDifferenceInDays(fromDate, dueDate)) //
.principalDue(principalDue) //
.principalOriginalDue(principalDue) //
.principalOutstanding(principalDue) //
.principalLoanBalanceOutstanding(outstandingLoanBalance) //
.interestDue(interestDue) //
.interestOriginalDue(interestDue) //
.interestOutstanding(interestDue) //
.feeChargesDue(feeDue) //
.feeChargesOutstanding(feeDue) //
.penaltyChargesDue(penaltyDue) //
.penaltyChargesOutstanding(penaltyDue) //
.totalOriginalDueForPeriod(totalDue) //
.totalDueForPeriod(totalDue) //
.totalOutstandingForPeriod(totalDue) //
.totalActualCostOfLoanForPeriod(totalActualCostOfLoanForPeriod) //
.totalInstallmentAmountForPeriod(totalInstallmentAmount) //
.totalOverdue(DateUtils.isBeforeBusinessDate(dueDate) ? totalDue : null) //
.build();
} }
public static LoanSchedulePeriodData downPaymentOnlyPeriod(final Integer periodNumber, final LocalDate periodDate, public static LoanSchedulePeriodData downPaymentOnlyPeriod(final Integer periodNumber, final LocalDate periodDate,
final BigDecimal principalDue, final BigDecimal principalOutstanding) { final BigDecimal principalDue, final BigDecimal outstandingLoanBalance) {
return new LoanSchedulePeriodData(periodNumber, periodDate, periodDate, principalDue, principalOutstanding); return builder().period(periodNumber) //
.fromDate(periodDate) //
.dueDate(periodDate) //
.principalOriginalDue(principalDue) //
.principalDue(principalDue) //
.principalOutstanding(principalDue) //
.principalLoanBalanceOutstanding(outstandingLoanBalance) //
.totalOriginalDueForPeriod(principalDue) //
.totalDueForPeriod(principalDue) //
.totalOutstandingForPeriod(principalDue) //
.totalInstallmentAmountForPeriod(principalDue) //
.downPaymentPeriod(true) //
.totalOverdue(DateUtils.isBeforeBusinessDate(periodDate) ? principalDue : null) //
.build();
} }
public static LoanSchedulePeriodData periodWithPayments(@SuppressWarnings("unused") final Long loanId, final Integer periodNumber, public static LoanSchedulePeriodData periodWithPayments(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
final LocalDate fromDate, final LocalDate dueDate, final LocalDate obligationsMetOnDate, final boolean complete, final LocalDate obligationsMetOnDate, final boolean complete, final BigDecimal principalOriginalDue,
final BigDecimal principalOriginalDue, final BigDecimal principalPaid, final BigDecimal principalWrittenOff, final BigDecimal principalPaid, final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding,
final BigDecimal principalOutstanding, final BigDecimal outstandingPrincipalBalanceOfLoan, final BigDecimal outstandingPrincipalBalanceOfLoan, final BigDecimal interestDue, final BigDecimal interestPaid,
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWaived, final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding,
final BigDecimal interestWrittenOff, final BigDecimal interestOutstanding, final BigDecimal feeChargesDue, final BigDecimal feeChargesDue, final BigDecimal feeChargesPaid, final BigDecimal feeChargesWaived,
final BigDecimal feeChargesPaid, final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesOutstanding, final BigDecimal penaltyChargesDue,
final BigDecimal feeChargesOutstanding, final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid, final BigDecimal penaltyChargesPaid, final BigDecimal penaltyChargesWaived, final BigDecimal penaltyChargesWrittenOff,
final BigDecimal penaltyChargesWaived, final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding, final BigDecimal penaltyChargesOutstanding, final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod,
final BigDecimal totalDueForPeriod, final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod,
final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalPaidLateForPeriod, final BigDecimal totalWaived, final BigDecimal totalWrittenOff,
final BigDecimal totalOutstanding, final BigDecimal totalActualCostOfLoanForPeriod, final BigDecimal totalCredits, final boolean isDownPayment, final BigDecimal totalAccruedInterest) {
final BigDecimal totalInstallmentAmountForPeriod, final BigDecimal totalCredits, final boolean isDownPayment,
final BigDecimal totalAccruedInterest) {
return new LoanSchedulePeriodData(periodNumber, fromDate, dueDate, obligationsMetOnDate, complete, principalOriginalDue, BigDecimal totalDue = MathUtil.add(principalOriginalDue, interestDue, feeChargesDue, penaltyChargesDue);
principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, BigDecimal totalOutstanding = MathUtil.add(principalOutstanding, interestOutstanding, feeChargesOutstanding,
interestDueOnPrincipalOutstanding, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesDue, penaltyChargesOutstanding);
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesDue, penaltyChargesPaid, BigDecimal totalActualCostOfLoanForPeriod = MathUtil.add(interestDue, feeChargesDue, penaltyChargesDue);
penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, totalPaid, BigDecimal totalInstallmentAmount = MathUtil.add(principalOriginalDue, interestDue);
totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaived, totalWrittenOff, totalOutstanding,
totalActualCostOfLoanForPeriod, totalInstallmentAmountForPeriod, totalCredits, isDownPayment, totalAccruedInterest); return builder().period(periodNumber) //
.fromDate(fromDate) //
.dueDate(dueDate) //
.obligationsMetOnDate(obligationsMetOnDate) //
.complete(complete) //
.daysInPeriod(DateUtils.getExactDifferenceInDays(fromDate, dueDate)) //
.principalDue(principalOriginalDue) //
.principalOriginalDue(principalOriginalDue) //
.principalPaid(principalPaid) //
.principalWrittenOff(principalWrittenOff) //
.principalOutstanding(principalOutstanding) //
.principalLoanBalanceOutstanding(outstandingPrincipalBalanceOfLoan) //
.interestDue(interestDue) //
.interestOriginalDue(interestDue) //
.interestPaid(interestPaid) //
.interestWaived(interestWaived) //
.interestWrittenOff(interestWrittenOff) //
.interestOutstanding(interestOutstanding) //
.feeChargesDue(feeChargesDue) //
.feeChargesPaid(feeChargesPaid) //
.feeChargesWaived(feeChargesWaived) //
.feeChargesWrittenOff(feeChargesWrittenOff) //
.feeChargesOutstanding(feeChargesOutstanding) //
.penaltyChargesDue(penaltyChargesDue) //
.penaltyChargesPaid(penaltyChargesPaid) //
.penaltyChargesWaived(penaltyChargesWaived) //
.penaltyChargesWrittenOff(penaltyChargesWrittenOff) //
.penaltyChargesOutstanding(penaltyChargesOutstanding) //
.totalOriginalDueForPeriod(totalDue) //
.totalDueForPeriod(totalDue) //
.totalPaidForPeriod(totalPaid) //
.totalPaidInAdvanceForPeriod(totalPaidInAdvanceForPeriod) //
.totalPaidLateForPeriod(totalPaidLateForPeriod) //
.totalWaivedForPeriod(totalWaived) //
.totalWrittenOffForPeriod(totalWrittenOff) //
.totalOutstandingForPeriod(totalOutstanding) //
.totalActualCostOfLoanForPeriod(totalActualCostOfLoanForPeriod) //
.totalInstallmentAmountForPeriod(totalInstallmentAmount) //
.totalOverdue(DateUtils.isBeforeBusinessDate(dueDate) ? totalOutstanding : null) //
.totalCredits(totalCredits) //
.downPaymentPeriod(isDownPayment) //
.totalAccruedInterest(totalAccruedInterest) //
.build();
} }
public static LoanSchedulePeriodData withPaidDetail(final LoanSchedulePeriodData loanSchedulePeriodData, final boolean complete, public static LoanSchedulePeriodData withPaidDetail(final LoanSchedulePeriodData loanSchedulePeriodData, final boolean complete,
final BigDecimal principalPaid, final BigDecimal interestPaid, final BigDecimal feeChargesPaid, final BigDecimal principalPaid, final BigDecimal interestPaid, final BigDecimal feeChargesPaid,
final BigDecimal penaltyChargesPaid) { final BigDecimal penaltyChargesPaid) {
BigDecimal totalOutstanding = MathUtil.subtract(loanSchedulePeriodData.totalDueForPeriod, principalPaid, interestPaid,
feeChargesPaid, penaltyChargesPaid);
return new LoanSchedulePeriodData(loanSchedulePeriodData.period, loanSchedulePeriodData.fromDate, loanSchedulePeriodData.dueDate, return builder().period(loanSchedulePeriodData.period) //
loanSchedulePeriodData.obligationsMetOnDate, complete, loanSchedulePeriodData.principalOriginalDue, principalPaid, .fromDate(loanSchedulePeriodData.fromDate) //
loanSchedulePeriodData.principalWrittenOff, loanSchedulePeriodData.principalOutstanding, .dueDate(loanSchedulePeriodData.dueDate) //
loanSchedulePeriodData.principalLoanBalanceOutstanding, loanSchedulePeriodData.interestDue, interestPaid, .obligationsMetOnDate(loanSchedulePeriodData.obligationsMetOnDate) //
loanSchedulePeriodData.interestWaived, loanSchedulePeriodData.interestWrittenOff, .complete(complete) //
loanSchedulePeriodData.interestOutstanding, loanSchedulePeriodData.feeChargesDue, feeChargesPaid, .daysInPeriod(DateUtils.getExactDifferenceInDays(loanSchedulePeriodData.fromDate, loanSchedulePeriodData.dueDate)) //
loanSchedulePeriodData.feeChargesWaived, loanSchedulePeriodData.feeChargesWrittenOff, .principalDue(loanSchedulePeriodData.principalOriginalDue) //
loanSchedulePeriodData.feeChargesOutstanding, loanSchedulePeriodData.penaltyChargesDue, penaltyChargesPaid, .principalOriginalDue(loanSchedulePeriodData.principalOriginalDue) //
loanSchedulePeriodData.penaltyChargesWaived, loanSchedulePeriodData.penaltyChargesWrittenOff, .principalPaid(principalPaid) //
loanSchedulePeriodData.penaltyChargesOutstanding, loanSchedulePeriodData.totalDueForPeriod, .principalWrittenOff(loanSchedulePeriodData.principalWrittenOff) //
loanSchedulePeriodData.totalPaidForPeriod, loanSchedulePeriodData.totalPaidInAdvanceForPeriod, .principalOutstanding(MathUtil.subtract(loanSchedulePeriodData.principalOriginalDue, principalPaid)) //
loanSchedulePeriodData.totalPaidLateForPeriod, loanSchedulePeriodData.totalWaivedForPeriod, .principalLoanBalanceOutstanding(loanSchedulePeriodData.principalLoanBalanceOutstanding) //
loanSchedulePeriodData.totalWrittenOffForPeriod, loanSchedulePeriodData.totalOutstandingForPeriod, .interestDue(loanSchedulePeriodData.interestDue) //
loanSchedulePeriodData.totalActualCostOfLoanForPeriod, loanSchedulePeriodData.totalInstallmentAmountForPeriod, .interestOriginalDue(loanSchedulePeriodData.interestDue) //
loanSchedulePeriodData.totalCredits, loanSchedulePeriodData.getDownPaymentPeriod(), .interestPaid(interestPaid) //
loanSchedulePeriodData.totalAccruedInterest); .interestWaived(loanSchedulePeriodData.interestWaived) //
} .interestWrittenOff(loanSchedulePeriodData.interestWrittenOff) //
.interestOutstanding(MathUtil.subtract(loanSchedulePeriodData.interestDue, interestPaid)) //
/* .feeChargesDue(loanSchedulePeriodData.feeChargesDue) //
* constructor used for creating period on loan schedule that is only a disbursement (typically first period) .feeChargesPaid(feeChargesPaid) //
*/ .feeChargesWaived(loanSchedulePeriodData.feeChargesWaived) //
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate, .feeChargesWrittenOff(loanSchedulePeriodData.feeChargesWrittenOff) //
final BigDecimal principalDisbursed, final BigDecimal chargesDueAtTimeOfDisbursement, final boolean isDisbursed) { .feeChargesOutstanding(MathUtil.subtract(loanSchedulePeriodData.feeChargesDue, feeChargesPaid)) //
this.period = periodNumber; .penaltyChargesDue(loanSchedulePeriodData.penaltyChargesDue) //
this.fromDate = fromDate; .penaltyChargesPaid(penaltyChargesPaid) //
this.dueDate = dueDate; .penaltyChargesWaived(loanSchedulePeriodData.penaltyChargesWaived) //
this.obligationsMetOnDate = null; .penaltyChargesWrittenOff(loanSchedulePeriodData.penaltyChargesWrittenOff) //
this.complete = null; .penaltyChargesOutstanding(MathUtil.subtract(loanSchedulePeriodData.penaltyChargesDue, penaltyChargesPaid)) //
if (fromDate != null) { .totalOriginalDueForPeriod(loanSchedulePeriodData.totalDueForPeriod) //
this.daysInPeriod = DateUtils.getExactDifferenceInDays(this.fromDate, this.dueDate); .totalDueForPeriod(loanSchedulePeriodData.totalDueForPeriod) //
} else { .totalPaidForPeriod(MathUtil.add(principalPaid, interestPaid, feeChargesPaid, penaltyChargesPaid)) //
this.daysInPeriod = null; .totalPaidInAdvanceForPeriod(loanSchedulePeriodData.totalPaidInAdvanceForPeriod) //
} .totalPaidLateForPeriod(loanSchedulePeriodData.totalPaidLateForPeriod) //
this.principalDisbursed = principalDisbursed; .totalWaivedForPeriod(loanSchedulePeriodData.totalWaivedForPeriod) //
this.principalOriginalDue = null; .totalWrittenOffForPeriod(loanSchedulePeriodData.totalWrittenOffForPeriod) //
this.principalDue = null; .totalOutstandingForPeriod(totalOutstanding) //
this.principalPaid = null; .totalActualCostOfLoanForPeriod(loanSchedulePeriodData.totalActualCostOfLoanForPeriod) //
this.principalWrittenOff = null; .totalInstallmentAmountForPeriod(loanSchedulePeriodData.totalInstallmentAmountForPeriod) //
this.principalOutstanding = null; .totalOverdue(DateUtils.isBeforeBusinessDate(loanSchedulePeriodData.dueDate) ? totalOutstanding : null) //
this.principalLoanBalanceOutstanding = principalDisbursed; .totalCredits(loanSchedulePeriodData.totalCredits) //
.downPaymentPeriod(loanSchedulePeriodData.isDownPaymentPeriod()) //
this.interestOriginalDue = null; .totalAccruedInterest(loanSchedulePeriodData.totalAccruedInterest) //
this.interestDue = null; .build();
this.interestPaid = null;
this.interestWaived = null;
this.interestWrittenOff = null;
this.interestOutstanding = null;
this.feeChargesDue = chargesDueAtTimeOfDisbursement;
if (isDisbursed) {
this.feeChargesPaid = chargesDueAtTimeOfDisbursement;
this.feeChargesWaived = null;
this.feeChargesWrittenOff = null;
this.feeChargesOutstanding = null;
} else {
this.feeChargesPaid = null;
this.feeChargesWaived = null;
this.feeChargesWrittenOff = null;
this.feeChargesOutstanding = chargesDueAtTimeOfDisbursement;
}
this.penaltyChargesDue = null;
this.penaltyChargesPaid = null;
this.penaltyChargesWaived = null;
this.penaltyChargesWrittenOff = null;
this.penaltyChargesOutstanding = null;
this.totalOriginalDueForPeriod = chargesDueAtTimeOfDisbursement;
this.totalDueForPeriod = chargesDueAtTimeOfDisbursement;
this.totalPaidForPeriod = this.feeChargesPaid;
this.totalPaidInAdvanceForPeriod = null;
this.totalPaidLateForPeriod = null;
this.totalWaivedForPeriod = null;
this.totalWrittenOffForPeriod = null;
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
this.totalInstallmentAmountForPeriod = null;
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.totalAccruedInterest = BigDecimal.ZERO;
this.downPaymentPeriod = false;
}
/*
* used for repayment only period when creating an empty loan schedule for preview etc
*/
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
final BigDecimal principalOriginalDue, final BigDecimal principalOutstanding,
final BigDecimal interestDueOnPrincipalOutstanding, final BigDecimal feeChargesDueForPeriod,
final BigDecimal penaltyChargesDueForPeriod, final BigDecimal totalDueForPeriod, BigDecimal totalInstallmentAmountForPeriod) {
this.period = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
this.obligationsMetOnDate = null;
this.complete = null;
if (fromDate != null) {
this.daysInPeriod = DateUtils.getExactDifferenceInDays(this.fromDate, this.dueDate);
} else {
this.daysInPeriod = null;
}
this.principalDisbursed = null;
this.principalOriginalDue = principalOriginalDue;
this.principalDue = principalOriginalDue;
this.principalPaid = null;
this.principalWrittenOff = null;
this.principalOutstanding = principalOriginalDue;
this.principalLoanBalanceOutstanding = principalOutstanding;
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
this.interestDue = interestDueOnPrincipalOutstanding;
this.interestPaid = null;
this.interestWaived = null;
this.interestWrittenOff = null;
this.interestOutstanding = interestDueOnPrincipalOutstanding;
this.feeChargesDue = feeChargesDueForPeriod;
this.feeChargesPaid = null;
this.feeChargesWaived = null;
this.feeChargesWrittenOff = null;
this.feeChargesOutstanding = null;
this.penaltyChargesDue = penaltyChargesDueForPeriod;
this.penaltyChargesPaid = null;
this.penaltyChargesWaived = null;
this.penaltyChargesWrittenOff = null;
this.penaltyChargesOutstanding = null;
this.totalOriginalDueForPeriod = totalDueForPeriod;
this.totalDueForPeriod = totalDueForPeriod;
this.totalPaidForPeriod = BigDecimal.ZERO;
this.totalPaidInAdvanceForPeriod = null;
this.totalPaidLateForPeriod = null;
this.totalWaivedForPeriod = null;
this.totalWrittenOffForPeriod = null;
this.totalOutstandingForPeriod = totalDueForPeriod;
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.totalAccruedInterest = BigDecimal.ZERO;
this.downPaymentPeriod = false;
}
// TODO refactor the class to builder pattern
/*
* used for down payment only period when creating an empty loan schedule for preview etc
*/
private LoanSchedulePeriodData(Integer periodNumber, LocalDate fromDate, LocalDate dueDate, BigDecimal principalDue,
BigDecimal principalOutstanding) {
this.period = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
this.obligationsMetOnDate = null;
this.complete = null;
this.daysInPeriod = 1; // TODO: check this may should be 0 or somewhere else should be 1?
this.principalDisbursed = null;
this.principalOriginalDue = principalDue;
this.principalDue = principalOriginalDue;
this.principalPaid = null;
this.principalWrittenOff = null;
this.principalOutstanding = principalOriginalDue;
this.principalLoanBalanceOutstanding = principalOutstanding;
this.interestOriginalDue = null;
this.interestDue = null;
this.interestPaid = null;
this.interestWaived = null;
this.interestWrittenOff = null;
this.interestOutstanding = null;
this.feeChargesDue = null;
this.feeChargesPaid = null;
this.feeChargesWaived = null;
this.feeChargesWrittenOff = null;
this.feeChargesOutstanding = null;
this.penaltyChargesDue = null;
this.penaltyChargesPaid = null;
this.penaltyChargesWaived = null;
this.penaltyChargesWrittenOff = null;
this.penaltyChargesOutstanding = null;
this.totalOriginalDueForPeriod = principalDue;
this.totalDueForPeriod = principalDue;
this.totalPaidForPeriod = BigDecimal.ZERO;
this.totalPaidInAdvanceForPeriod = null;
this.totalPaidLateForPeriod = null;
this.totalWaivedForPeriod = null;
this.totalWrittenOffForPeriod = null;
this.totalOutstandingForPeriod = totalDueForPeriod;
this.totalActualCostOfLoanForPeriod = null;
this.totalInstallmentAmountForPeriod = totalDueForPeriod;
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.downPaymentPeriod = true;
this.totalAccruedInterest = BigDecimal.ZERO;
}
/*
* Used for creating loan schedule periods with full information on expected principal, interest & charges along
* with what portion of each is paid.
*/
private LoanSchedulePeriodData(final Integer periodNumber, final LocalDate fromDate, final LocalDate dueDate,
final LocalDate obligationsMetOnDate, final boolean complete, final BigDecimal principalOriginalDue,
final BigDecimal principalPaid, final BigDecimal principalWrittenOff, final BigDecimal principalOutstanding,
final BigDecimal principalLoanBalanceOutstanding, final BigDecimal interestDueOnPrincipalOutstanding,
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestWrittenOff,
final BigDecimal interestOutstanding, final BigDecimal feeChargesDue, final BigDecimal feeChargesPaid,
final BigDecimal feeChargesWaived, final BigDecimal feeChargesWrittenOff, final BigDecimal feeChargesOutstanding,
final BigDecimal penaltyChargesDue, final BigDecimal penaltyChargesPaid, final BigDecimal penaltyChargesWaived,
final BigDecimal penaltyChargesWrittenOff, final BigDecimal penaltyChargesOutstanding, final BigDecimal totalDueForPeriod,
final BigDecimal totalPaid, final BigDecimal totalPaidInAdvanceForPeriod, final BigDecimal totalPaidLateForPeriod,
final BigDecimal totalWaived, final BigDecimal totalWrittenOff, final BigDecimal totalOutstanding,
final BigDecimal totalActualCostOfLoanForPeriod, final BigDecimal totalInstallmentAmountForPeriod,
final BigDecimal totalCredits, final boolean isDownPayment, final BigDecimal totalAccruedInterest) {
this.period = periodNumber;
this.fromDate = fromDate;
this.dueDate = dueDate;
this.obligationsMetOnDate = obligationsMetOnDate;
this.complete = complete;
if (fromDate != null) {
this.daysInPeriod = DateUtils.getExactDifferenceInDays(this.fromDate, this.dueDate);
} else {
this.daysInPeriod = null;
}
this.principalDisbursed = null;
this.principalOriginalDue = principalOriginalDue;
this.principalDue = principalOriginalDue;
this.principalPaid = principalPaid;
this.principalWrittenOff = principalWrittenOff;
this.principalOutstanding = principalOutstanding;
this.principalLoanBalanceOutstanding = principalLoanBalanceOutstanding;
this.interestOriginalDue = interestDueOnPrincipalOutstanding;
this.interestDue = interestDueOnPrincipalOutstanding;
this.interestPaid = interestPaid;
this.interestWaived = interestWaived;
this.interestWrittenOff = interestWrittenOff;
this.interestOutstanding = interestOutstanding;
this.feeChargesDue = feeChargesDue;
this.feeChargesPaid = feeChargesPaid;
this.feeChargesWaived = feeChargesWaived;
this.feeChargesWrittenOff = feeChargesWrittenOff;
this.feeChargesOutstanding = feeChargesOutstanding;
this.penaltyChargesDue = penaltyChargesDue;
this.penaltyChargesPaid = penaltyChargesPaid;
this.penaltyChargesWaived = penaltyChargesWaived;
this.penaltyChargesWrittenOff = penaltyChargesWrittenOff;
this.penaltyChargesOutstanding = penaltyChargesOutstanding;
this.totalOriginalDueForPeriod = totalDueForPeriod;
this.totalDueForPeriod = totalDueForPeriod;
this.totalPaidForPeriod = totalPaid;
this.totalPaidInAdvanceForPeriod = totalPaidInAdvanceForPeriod;
this.totalPaidLateForPeriod = totalPaidLateForPeriod;
this.totalWaivedForPeriod = totalWaived;
this.totalWrittenOffForPeriod = totalWrittenOff;
this.totalOutstandingForPeriod = totalOutstanding;
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = totalCredits;
this.downPaymentPeriod = isDownPayment;
this.totalAccruedInterest = totalAccruedInterest;
}
private BigDecimal defaultToZeroIfNull(final BigDecimal possibleNullValue) {
BigDecimal value = BigDecimal.ZERO;
if (possibleNullValue != null) {
value = possibleNullValue;
}
return value;
}
public boolean isActualPeriodForNotDuePayableCalculation(final LocalDate businessDate) {
boolean actualPeriod = false;
if (getPeriod() != null) {
if (getPeriod() == 1) {
actualPeriod = ((businessDate.compareTo(getFromDate()) >= 0) && businessDate.compareTo(getDueDate()) < 0);
} else {
actualPeriod = ((businessDate.compareTo(getFromDate()) >= 0) && businessDate.compareTo(getDueDate()) < 0);
}
}
return actualPeriod;
} }
public BigDecimal getPrincipalDisbursed() { public BigDecimal getPrincipalDisbursed() {
return defaultToZeroIfNull(this.principalDisbursed); return MathUtil.nullToDefault(this.principalDisbursed, BigDecimal.ZERO);
} }
public BigDecimal getPrincipalDue() { public BigDecimal getPrincipalDue() {
return defaultToZeroIfNull(this.principalDue); return MathUtil.nullToDefault(this.principalDue, BigDecimal.ZERO);
} }
public BigDecimal getPrincipalPaid() { public BigDecimal getPrincipalPaid() {
return defaultToZeroIfNull(this.principalPaid); return MathUtil.nullToDefault(this.principalPaid, BigDecimal.ZERO);
} }
public BigDecimal getPrincipalWrittenOff() { public BigDecimal getPrincipalWrittenOff() {
return defaultToZeroIfNull(this.principalWrittenOff); return MathUtil.nullToDefault(this.principalWrittenOff, BigDecimal.ZERO);
} }
public BigDecimal getPrincipalOutstanding() { public BigDecimal getPrincipalOutstanding() {
return defaultToZeroIfNull(this.principalOutstanding); return MathUtil.nullToDefault(this.principalOutstanding, BigDecimal.ZERO);
} }
public BigDecimal getInterestDue() { public BigDecimal getInterestDue() {
return defaultToZeroIfNull(this.interestDue); return MathUtil.nullToDefault(this.interestDue, BigDecimal.ZERO);
} }
public BigDecimal getInterestPaid() { public BigDecimal getInterestPaid() {
return defaultToZeroIfNull(this.interestPaid); return MathUtil.nullToDefault(this.interestPaid, BigDecimal.ZERO);
} }
public BigDecimal getInterestWaived() { public BigDecimal getInterestWaived() {
return defaultToZeroIfNull(this.interestWaived); return MathUtil.nullToDefault(this.interestWaived, BigDecimal.ZERO);
} }
public BigDecimal getInterestWrittenOff() { public BigDecimal getInterestWrittenOff() {
return defaultToZeroIfNull(this.interestWrittenOff); return MathUtil.nullToDefault(this.interestWrittenOff, BigDecimal.ZERO);
} }
public BigDecimal getInterestOutstanding() { public BigDecimal getInterestOutstanding() {
return defaultToZeroIfNull(this.interestOutstanding); return MathUtil.nullToDefault(this.interestOutstanding, BigDecimal.ZERO);
} }
public BigDecimal getFeeChargesDue() { public BigDecimal getFeeChargesDue() {
return defaultToZeroIfNull(this.feeChargesDue); return MathUtil.nullToDefault(this.feeChargesDue, BigDecimal.ZERO);
} }
public BigDecimal getFeeChargesWaived() { public BigDecimal getFeeChargesWaived() {
return defaultToZeroIfNull(this.feeChargesWaived); return MathUtil.nullToDefault(this.feeChargesWaived, BigDecimal.ZERO);
} }
public BigDecimal getFeeChargesWrittenOff() { public BigDecimal getFeeChargesWrittenOff() {
return defaultToZeroIfNull(this.feeChargesWrittenOff); return MathUtil.nullToDefault(this.feeChargesWrittenOff, BigDecimal.ZERO);
} }
public BigDecimal getFeeChargesPaid() { public BigDecimal getFeeChargesPaid() {
return defaultToZeroIfNull(this.feeChargesPaid); return MathUtil.nullToDefault(this.feeChargesPaid, BigDecimal.ZERO);
} }
public BigDecimal getFeeChargesOutstanding() { public BigDecimal getFeeChargesOutstanding() {
return defaultToZeroIfNull(this.feeChargesOutstanding); return MathUtil.nullToDefault(this.feeChargesOutstanding, BigDecimal.ZERO);
} }
public BigDecimal getPenaltyChargesDue() { public BigDecimal getPenaltyChargesDue() {
return defaultToZeroIfNull(this.penaltyChargesDue); return MathUtil.nullToDefault(this.penaltyChargesDue, BigDecimal.ZERO);
} }
public BigDecimal getPenaltyChargesWaived() { public BigDecimal getPenaltyChargesWaived() {
return defaultToZeroIfNull(this.penaltyChargesWaived); return MathUtil.nullToDefault(this.penaltyChargesWaived, BigDecimal.ZERO);
} }
public BigDecimal getPenaltyChargesWrittenOff() { public BigDecimal getPenaltyChargesWrittenOff() {
return defaultToZeroIfNull(this.penaltyChargesWrittenOff); return MathUtil.nullToDefault(this.penaltyChargesWrittenOff, BigDecimal.ZERO);
} }
public BigDecimal getPenaltyChargesPaid() { public BigDecimal getPenaltyChargesPaid() {
return defaultToZeroIfNull(this.penaltyChargesPaid); return MathUtil.nullToDefault(this.penaltyChargesPaid, BigDecimal.ZERO);
} }
public BigDecimal getPenaltyChargesOutstanding() { public BigDecimal getPenaltyChargesOutstanding() {
return defaultToZeroIfNull(this.penaltyChargesOutstanding); return MathUtil.nullToDefault(this.penaltyChargesOutstanding, BigDecimal.ZERO);
} }
public BigDecimal getTotalOverdue() { public BigDecimal getTotalOverdue() {
return defaultToZeroIfNull(this.totalOverdue); return MathUtil.nullToDefault(this.totalOverdue, BigDecimal.ZERO);
} }
public BigDecimal totalOutstandingForPeriod() { public BigDecimal totalOutstandingForPeriod() {
return defaultToZeroIfNull(this.totalOutstandingForPeriod); return MathUtil.nullToDefault(this.totalOutstandingForPeriod, BigDecimal.ZERO);
} }
} }
@@ -78,7 +78,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
public LoanSchedulePeriodData toData() { public LoanSchedulePeriodData toData() {
return LoanSchedulePeriodData.repaymentOnlyPeriod(this.periodNumber, this.fromDate, this.dueDate, this.principalDue.getAmount(), return LoanSchedulePeriodData.repaymentOnlyPeriod(this.periodNumber, this.fromDate, this.dueDate, this.principalDue.getAmount(),
this.outstandingLoanBalance.getAmount(), this.interestDue.getAmount(), this.feeChargesDue.getAmount(), this.outstandingLoanBalance.getAmount(), this.interestDue.getAmount(), this.feeChargesDue.getAmount(),
this.penaltyChargesDue.getAmount(), this.totalDue.getAmount(), this.principalDue.plus(this.interestDue).getAmount()); this.penaltyChargesDue.getAmount());
} }
@Override @Override
@@ -65,7 +65,7 @@ public final class LoanRescheduleModelRepaymentPeriod implements LoanRescheduleM
public LoanSchedulePeriodData toData() { public LoanSchedulePeriodData toData() {
return LoanSchedulePeriodData.repaymentOnlyPeriod(this.periodNumber, this.fromDate, this.dueDate, this.principalDue.getAmount(), return LoanSchedulePeriodData.repaymentOnlyPeriod(this.periodNumber, this.fromDate, this.dueDate, this.principalDue.getAmount(),
this.outstandingLoanBalance.getAmount(), this.interestDue.getAmount(), this.feeChargesDue.getAmount(), this.outstandingLoanBalance.getAmount(), this.interestDue.getAmount(), this.feeChargesDue.getAmount(),
this.penaltyChargesDue.getAmount(), this.totalDue.getAmount(), this.principalDue.plus(this.interestDue).getAmount()); this.penaltyChargesDue.getAmount());
} }
@Override @Override
@@ -341,7 +341,8 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
OriginalScheduleExtractor(final String loanIdsAsString, DatabaseSpecificSQLGenerator sqlGenerator) { OriginalScheduleExtractor(final String loanIdsAsString, DatabaseSpecificSQLGenerator sqlGenerator) {
final StringBuilder scheduleDetail = new StringBuilder(); final StringBuilder scheduleDetail = new StringBuilder();
scheduleDetail.append("select ml.id as loanId, mr.duedate as dueDate, mr.principal_amount as principalAmount, "); scheduleDetail.append(
"select ml.id as loanId, mr.installment as installmentNumber, mr.fromdate as fromDate, mr.duedate as dueDate, mr.principal_amount as principalAmount, ");
scheduleDetail.append( scheduleDetail.append(
"mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount "); "mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount ");
scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id "); scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id ");
@@ -369,19 +370,16 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
} }
private LoanSchedulePeriodData fetchLoanSchedulePeriodData(ResultSet rs) throws SQLException { private LoanSchedulePeriodData fetchLoanSchedulePeriodData(ResultSet rs) throws SQLException {
final Integer installmentNumber = JdbcSupport.getInteger(rs, "installmentNumber");
final LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate");
final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate"); final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalAmount"); final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalAmount");
final BigDecimal interestDueOnPrincipalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestAmount"); final BigDecimal interestDueOnPrincipalOutstanding = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestAmount");
final BigDecimal totalInstallmentAmount = principalDue.add(interestDueOnPrincipalOutstanding);
final BigDecimal feeChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeAmount"); final BigDecimal feeChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeAmount");
final BigDecimal penaltyChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyAmount"); final BigDecimal penaltyChargesDueForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyAmount");
final Integer periodNumber = null;
final LocalDate fromDate = null; return LoanSchedulePeriodData.repaymentOnlyPeriod(installmentNumber, fromDate, dueDate, principalDue, null,
final BigDecimal principalOutstanding = null; interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod);
final BigDecimal totalDueForPeriod = null;
return LoanSchedulePeriodData.repaymentOnlyPeriod(periodNumber, fromDate, dueDate, principalDue, principalOutstanding,
interestDueOnPrincipalOutstanding, feeChargesDueForPeriod, penaltyChargesDueForPeriod, totalDueForPeriod,
totalInstallmentAmount);
} }
} }
@@ -122,13 +122,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
outstandingAmountsDTO.principal().getAmount(), outstandingAmountsDTO.interest().getAmount(), outstandingAmountsDTO.principal().getAmount(), outstandingAmountsDTO.interest().getAmount(),
outstandingAmountsDTO.feeCharges().getAmount(), outstandingAmountsDTO.penaltyCharges().getAmount(), false, null); outstandingAmountsDTO.feeCharges().getAmount(), outstandingAmountsDTO.penaltyCharges().getAmount(), false, null);
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)) Money interestDue = loanRepaymentScheduleInstallment.getInterestOutstanding(currency);
.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
Money interestDue = Money.zero(currency);
if (loanRepaymentScheduleInstallment.isInterestDue(currency)) {
interestDue = loanRepaymentScheduleInstallment.getInterestOutstanding(currency);
totalAmount = totalAmount.plus(interestDue);
}
boolean isNewPaymentRequired = loanRepaymentScheduleInstallment.isInterestDue(currency) || totalPrincipal.isGreaterThanZero(); boolean isNewPaymentRequired = loanRepaymentScheduleInstallment.isInterestDue(currency) || totalPrincipal.isGreaterThanZero();
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(), LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
@@ -141,14 +135,12 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
periodData.getFromDate(), periodData.getDueDate(), totalPrincipal.getAmount(), periodData.getFromDate(), periodData.getDueDate(), totalPrincipal.getAmount(),
periodData.getPrincipalLoanBalanceOutstanding(), interestDue.getAmount(), periodData.getPrincipalLoanBalanceOutstanding(), interestDue.getAmount(),
loanRepaymentScheduleInstallment.getFeeChargesCharged(currency).getAmount(), loanRepaymentScheduleInstallment.getFeeChargesCharged(currency).getAmount(),
loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount(), totalAmount.getAmount(), loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount());
totalPrincipal.plus(interestDue).getAmount());
futureInstallments.add(loanSchedulePeriodData); futureInstallments.add(loanSchedulePeriodData);
isNewPaymentRequired = false; isNewPaymentRequired = false;
} else if (DateUtils.isAfter(periodData.getDueDate(), today)) { } else if (DateUtils.isAfter(periodData.getDueDate(), today)) {
futureInstallments.add(periodData); futureInstallments.add(periodData);
} }
} }
loanScheduleData.updateFuturePeriods(futureInstallments); loanScheduleData.updateFuturePeriods(futureInstallments);
} }
@@ -198,8 +190,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
LoanSchedulePeriodData loanSchedulePeriodData = LoanSchedulePeriodData.repaymentOnlyPeriod(installment.getInstallmentNumber(), LoanSchedulePeriodData loanSchedulePeriodData = LoanSchedulePeriodData.repaymentOnlyPeriod(installment.getInstallmentNumber(),
installment.getFromDate(), installment.getDueDate(), installment.getPrincipal(currency).getAmount(), installment.getFromDate(), installment.getDueDate(), installment.getPrincipal(currency).getAmount(),
outstanding.getAmount(), installment.getInterestCharged(currency).getAmount(), outstanding.getAmount(), installment.getInterestCharged(currency).getAmount(),
installment.getFeeChargesCharged(currency).getAmount(), installment.getPenaltyChargesCharged(currency).getAmount(), installment.getFeeChargesCharged(currency).getAmount(), installment.getPenaltyChargesCharged(currency).getAmount());
installment.getDue(currency).getAmount(), installment.getTotalPrincipalAndInterest(currency).getAmount());
installmentData.add(loanSchedulePeriodData); installmentData.add(loanSchedulePeriodData);
totalInterest = totalInterest.plus(installment.getInterestCharged(currency)); totalInterest = totalInterest.plus(installment.getInterestCharged(currency));
totalCharge = totalCharge.plus(installment.getFeeChargesCharged(currency)); totalCharge = totalCharge.plus(installment.getFeeChargesCharged(currency));
@@ -191,9 +191,6 @@ public class LoanScheduleHistoryReadPlatformServiceImpl implements LoanScheduleH
final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue"); final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue");
totalInterestCharged = totalInterestCharged.plus(interestExpectedDue); totalInterestCharged = totalInterestCharged.plus(interestExpectedDue);
final BigDecimal totalInstallmentAmount = totalPrincipalExpected.zero().plus(principalDue).plus(interestExpectedDue)
.getAmount();
final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue"); final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue");
totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue); totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue);
@@ -218,7 +215,7 @@ public class LoanScheduleHistoryReadPlatformServiceImpl implements LoanScheduleH
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentOnlyPeriod(period, fromDate, dueDate, final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentOnlyPeriod(period, fromDate, dueDate,
principalDue, outstandingPrincipalBalanceOfLoan, interestExpectedDue, feeChargesExpectedDue, principalDue, outstandingPrincipalBalanceOfLoan, interestExpectedDue, feeChargesExpectedDue,
penaltyChargesExpectedDue, totalDueForPeriod, totalInstallmentAmount); penaltyChargesExpectedDue);
periods.add(periodData); periods.add(periodData);
} }
@@ -159,15 +159,12 @@ public abstract class CommonLoanSummaryDataProvider implements LoanSummaryDataPr
@Override @Override
public BigDecimal computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> periods, final LocalDate businessDate) { public BigDecimal computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> periods, final LocalDate businessDate) {
return periods.stream().filter(period -> !period.getDownPaymentPeriod() && businessDate.compareTo(period.getDueDate()) >= 0) return periods.stream().filter(period -> !period.isDownPaymentPeriod() && !businessDate.isBefore(period.getDueDate()))
.map(LoanSchedulePeriodData::getInterestOutstanding).reduce(BigDecimal.ZERO, BigDecimal::add); .map(LoanSchedulePeriodData::getInterestOutstanding).reduce(BigDecimal.ZERO, BigDecimal::add);
} }
@Override @Override
public LoanSummaryData withOnlyCurrencyData(CurrencyData currencyData) { public LoanSummaryData withOnlyCurrencyData(CurrencyData currencyData) {
{ return LoanSummaryData.builder().currency(currencyData).build();
return LoanSummaryData.builder().currency(currencyData).build();
}
} }
} }
@@ -46,8 +46,10 @@ public class CumulativeLoanSummaryDataProvider extends CommonLoanSummaryDataProv
public BigDecimal computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan, public BigDecimal computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final Loan loan,
final Collection<LoanSchedulePeriodData> periods, final LocalDate businessDate, final CurrencyData currency) { final Collection<LoanSchedulePeriodData> periods, final LocalDate businessDate, final CurrencyData currency) {
// Find the current Period (If exists one) based on the Business date // Find the current Period (If exists one) based on the Business date
final Optional<LoanSchedulePeriodData> optCurrentPeriod = periods.stream() final Optional<LoanSchedulePeriodData> optCurrentPeriod = periods.stream().filter(period -> !period.isDownPaymentPeriod() //
.filter(period -> !period.getDownPaymentPeriod() && period.isActualPeriodForNotDuePayableCalculation(businessDate)) && period.getPeriod() != null //
&& !businessDate.isBefore(period.getFromDate()) //
&& businessDate.isBefore(period.getDueDate())) //
.findFirst(); .findFirst();
if (optCurrentPeriod.isPresent()) { if (optCurrentPeriod.isPresent()) {
@@ -1263,8 +1263,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid"); final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid");
final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived"); final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived");
final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff"); final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff");
final BigDecimal totalInstallmentAmount = totalPrincipalPaid.zero().plus(principalDue).plus(interestExpectedDue)
.getAmount();
final BigDecimal accrualInterest = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accrualInterest"); final BigDecimal accrualInterest = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accrualInterest");
final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff); final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff);
@@ -1330,14 +1328,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
LoanSchedulePeriodData periodData; LoanSchedulePeriodData periodData;
periodData = LoanSchedulePeriodData.periodWithPayments(loanId, period, fromDate, dueDate, obligationsMetOnDate, complete, periodData = LoanSchedulePeriodData.periodWithPayments(period, fromDate, dueDate, obligationsMetOnDate, complete,
principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue, interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue,
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue, feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue,
penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod, penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalPaidForPeriod,
totalPaidForPeriod, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod, credits,
totalWrittenOffForPeriod, totalOutstandingForPeriod, totalActualCostOfLoanForPeriod, totalInstallmentAmount, isDownPayment, accrualInterest);
credits, isDownPayment, accrualInterest);
periods.add(periodData); periods.add(periodData);
} }