FINERACT-2090: refactor and cleanup Loan entity

This commit is contained in:
Kristof Jozsa
2024-06-12 16:29:50 +02:00
committed by Adam Saghy
parent 369b809700
commit c9f0799a06
5 changed files with 1514 additions and 2196 deletions
File diff suppressed because it is too large Load Diff
@@ -140,103 +140,39 @@ public class LoanSummary {
this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement; this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement;
} }
public void updateTotalFeeChargesDueAtDisbursement(final BigDecimal totalFeeChargesDueAtDisbursement) {
this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement;
}
public Money getTotalFeeChargesDueAtDisbursement(final MonetaryCurrency currency) {
return Money.of(currency, this.totalFeeChargesDueAtDisbursement);
}
public Money getTotalOutstanding(final MonetaryCurrency currency) {
return Money.of(currency, this.totalOutstanding);
}
public void updateFeeChargeOutstanding(final BigDecimal totalFeeChargesOutstanding) {
this.totalFeeChargesOutstanding = totalFeeChargesOutstanding;
}
public void updatePenaltyChargeOutstanding(final BigDecimal totalPenaltyChargesOutstanding) {
this.totalPenaltyChargesOutstanding = totalPenaltyChargesOutstanding;
}
public void updateFeeChargesWaived(final BigDecimal totalFeeChargesWaived) {
this.totalFeeChargesWaived = totalFeeChargesWaived;
}
public void updatePenaltyChargesWaived(final BigDecimal totalPenaltyChargesWaived) {
this.totalPenaltyChargesWaived = totalPenaltyChargesWaived;
}
public boolean isRepaidInFull(final MonetaryCurrency currency) {
return getTotalOutstanding(currency).isZero();
}
public BigDecimal getTotalInterestCharged() {
return this.totalInterestCharged;
}
public BigDecimal getTotalPrincipalOutstanding() {
return this.totalPrincipalOutstanding;
}
public BigDecimal getTotalInterestOutstanding() {
return this.totalInterestOutstanding;
}
public BigDecimal getTotalFeeChargesOutstanding() {
return this.totalFeeChargesOutstanding;
}
public BigDecimal getTotalPenaltyChargesOutstanding() {
return this.totalPenaltyChargesOutstanding;
}
public BigDecimal getTotalOutstanding() {
return this.totalOutstanding;
}
public void updateTotalOutstanding(final BigDecimal newTotalOutstanding) {
this.totalOutstanding = newTotalOutstanding;
}
public void updateTotalWaived(final BigDecimal totalWaived) {
this.totalWaived = totalWaived;
}
/** /**
* All fields but <code>totalFeeChargesDueAtDisbursement</code> should be reset. * All fields but <code>totalFeeChargesDueAtDisbursement</code> should be reset.
*/ */
public void zeroFields() { public void zeroFields() {
this.totalPrincipalDisbursed = BigDecimal.ZERO; this.totalCostOfLoan = BigDecimal.ZERO;
this.totalPrincipalAdjustments = BigDecimal.ZERO; this.totalExpectedCostOfLoan = BigDecimal.ZERO;
this.totalExpectedRepayment = BigDecimal.ZERO;
this.totalFeeAdjustments = BigDecimal.ZERO; this.totalFeeAdjustments = BigDecimal.ZERO;
this.totalPenaltyAdjustments = BigDecimal.ZERO;
this.totalPrincipalRepaid = BigDecimal.ZERO;
this.totalPrincipalWrittenOff = BigDecimal.ZERO;
this.totalPrincipalOutstanding = BigDecimal.ZERO;
this.totalInterestCharged = BigDecimal.ZERO;
this.totalInterestRepaid = BigDecimal.ZERO;
this.totalInterestWaived = BigDecimal.ZERO;
this.totalInterestWrittenOff = BigDecimal.ZERO;
this.totalInterestOutstanding = BigDecimal.ZERO;
this.totalFeeChargesCharged = BigDecimal.ZERO; this.totalFeeChargesCharged = BigDecimal.ZERO;
this.totalFeeChargesOutstanding = BigDecimal.ZERO;
this.totalFeeChargesRepaid = BigDecimal.ZERO; this.totalFeeChargesRepaid = BigDecimal.ZERO;
this.totalFeeChargesWaived = BigDecimal.ZERO; this.totalFeeChargesWaived = BigDecimal.ZERO;
this.totalFeeChargesWrittenOff = BigDecimal.ZERO; this.totalFeeChargesWrittenOff = BigDecimal.ZERO;
this.totalFeeChargesOutstanding = BigDecimal.ZERO; this.totalInterestCharged = BigDecimal.ZERO;
this.totalInterestOutstanding = BigDecimal.ZERO;
this.totalInterestRepaid = BigDecimal.ZERO;
this.totalInterestWaived = BigDecimal.ZERO;
this.totalInterestWrittenOff = BigDecimal.ZERO;
this.totalOutstanding = BigDecimal.ZERO;
this.totalPenaltyAdjustments = BigDecimal.ZERO;
this.totalPenaltyChargesCharged = BigDecimal.ZERO; this.totalPenaltyChargesCharged = BigDecimal.ZERO;
this.totalPenaltyChargesOutstanding = BigDecimal.ZERO;
this.totalPenaltyChargesRepaid = BigDecimal.ZERO; this.totalPenaltyChargesRepaid = BigDecimal.ZERO;
this.totalPenaltyChargesWaived = BigDecimal.ZERO; this.totalPenaltyChargesWaived = BigDecimal.ZERO;
this.totalPenaltyChargesWrittenOff = BigDecimal.ZERO; this.totalPenaltyChargesWrittenOff = BigDecimal.ZERO;
this.totalPenaltyChargesOutstanding = BigDecimal.ZERO; this.totalPrincipalAdjustments = BigDecimal.ZERO;
this.totalExpectedRepayment = BigDecimal.ZERO; this.totalPrincipalDisbursed = BigDecimal.ZERO;
this.totalPrincipalOutstanding = BigDecimal.ZERO;
this.totalPrincipalRepaid = BigDecimal.ZERO;
this.totalPrincipalWrittenOff = BigDecimal.ZERO;
this.totalRepayment = BigDecimal.ZERO; this.totalRepayment = BigDecimal.ZERO;
this.totalExpectedCostOfLoan = BigDecimal.ZERO;
this.totalCostOfLoan = BigDecimal.ZERO;
this.totalWaived = BigDecimal.ZERO; this.totalWaived = BigDecimal.ZERO;
this.totalWrittenOff = BigDecimal.ZERO; this.totalWrittenOff = BigDecimal.ZERO;
this.totalOutstanding = BigDecimal.ZERO;
} }
public void updateSummary(final MonetaryCurrency currency, final Money principal, public void updateSummary(final MonetaryCurrency currency, final Money principal,
@@ -327,58 +263,43 @@ public class LoanSummary {
this.totalOutstanding = totalOutstanding.getAmount(); this.totalOutstanding = totalOutstanding.getAmount();
} }
public BigDecimal getTotalPrincipalDisbursed() { public void updateTotalFeeChargesDueAtDisbursement(final BigDecimal totalFeeChargesDueAtDisbursement) {
return this.totalPrincipalDisbursed; this.totalFeeChargesDueAtDisbursement = totalFeeChargesDueAtDisbursement;
} }
public BigDecimal getTotalPrincipalRepaid() { public Money getTotalFeeChargesDueAtDisbursement(final MonetaryCurrency currency) {
return this.totalPrincipalRepaid; return Money.of(currency, this.totalFeeChargesDueAtDisbursement);
} }
public BigDecimal getTotalWrittenOff() { public Money getTotalOutstanding(final MonetaryCurrency currency) {
return this.totalWrittenOff; return Money.of(currency, this.totalOutstanding);
} }
/** public void updateFeeChargeOutstanding(final BigDecimal totalFeeChargesOutstanding) {
* @return total interest repaid this.totalFeeChargesOutstanding = totalFeeChargesOutstanding;
**/
public BigDecimal getTotalInterestRepaid() {
return this.totalInterestRepaid;
} }
public BigDecimal getTotalFeeChargesCharged() { public void updatePenaltyChargeOutstanding(final BigDecimal totalPenaltyChargesOutstanding) {
return this.totalFeeChargesCharged; this.totalPenaltyChargesOutstanding = totalPenaltyChargesOutstanding;
} }
public BigDecimal getTotalPenaltyChargesCharged() { public void updateFeeChargesWaived(final BigDecimal totalFeeChargesWaived) {
return this.totalPenaltyChargesCharged; this.totalFeeChargesWaived = totalFeeChargesWaived;
} }
public BigDecimal getTotalPrincipalWrittenOff() { public void updatePenaltyChargesWaived(final BigDecimal totalPenaltyChargesWaived) {
return this.totalPrincipalWrittenOff; this.totalPenaltyChargesWaived = totalPenaltyChargesWaived;
} }
public BigDecimal getTotalInterestWaived() { public boolean isRepaidInFull(final MonetaryCurrency currency) {
return this.totalInterestWaived; return getTotalOutstanding(currency).isZero();
} }
public BigDecimal getTotalFeeChargesRepaid() { public void updateTotalOutstanding(final BigDecimal newTotalOutstanding) {
return this.totalFeeChargesRepaid; this.totalOutstanding = newTotalOutstanding;
} }
public BigDecimal getTotalFeeChargesWaived() { public void updateTotalWaived(final BigDecimal totalWaived) {
return this.totalFeeChargesWaived; this.totalWaived = totalWaived;
}
public BigDecimal getTotalPenaltyChargesRepaid() {
return this.totalPenaltyChargesRepaid;
}
public BigDecimal getTotalPenaltyChargesWaived() {
return this.totalPenaltyChargesWaived;
}
public BigDecimal getTotalExpectedRepayment() {
return this.totalExpectedRepayment;
} }
} }
@@ -18,6 +18,8 @@
*/ */
package org.apache.fineract.portfolio.loanaccount.service; package org.apache.fineract.portfolio.loanaccount.service;
import static org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType.SAME_AS_REPAYMENT_PERIOD;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@@ -236,28 +238,21 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private void createCalendar(final Loan loan, LocalDate calendarStartDate, Integer recalculationFrequencyNthDay, private void createCalendar(final Loan loan, LocalDate calendarStartDate, Integer recalculationFrequencyNthDay,
final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency, final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency,
CalendarEntityType calendarEntityType, final String title) { CalendarEntityType calendarEntityType, final String title) {
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
Integer updatedRepeatsOnDay = repeatsOnDay; Integer updatedRepeatsOnDay = repeatsOnDay;
switch (recalculationFrequencyType) { final CalendarFrequencyType calendarFrequencyType = switch (recalculationFrequencyType) {
case DAILY: case DAILY -> CalendarFrequencyType.DAILY;
calendarFrequencyType = CalendarFrequencyType.DAILY; case WEEKLY -> CalendarFrequencyType.WEEKLY;
break; case MONTHLY -> CalendarFrequencyType.MONTHLY;
case MONTHLY: case SAME_AS_REPAYMENT_PERIOD -> CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType());
calendarFrequencyType = CalendarFrequencyType.MONTHLY; case INVALID -> CalendarFrequencyType.INVALID;
break; };
case SAME_AS_REPAYMENT_PERIOD:
frequency = loan.repaymentScheduleDetail().getRepayEvery(); if (recalculationFrequencyType == SAME_AS_REPAYMENT_PERIOD) {
calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType()); frequency = loan.repaymentScheduleDetail().getRepayEvery();
calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
if (updatedRepeatsOnDay == null) { if (updatedRepeatsOnDay == null) {
updatedRepeatsOnDay = calendarStartDate.get(ChronoField.DAY_OF_WEEK); updatedRepeatsOnDay = calendarStartDate.get(ChronoField.DAY_OF_WEEK);
} }
break;
case WEEKLY:
calendarFrequencyType = CalendarFrequencyType.WEEKLY;
break;
default:
break;
} }
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(), final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
@@ -971,11 +971,15 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
final String defaultUserMessage = "Installment charge cannot be added to the loan."; final String defaultUserMessage = "Installment charge cannot be added to the loan.";
throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null, throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null,
chargeDefinition.getName()); chargeDefinition.getName());
} else if (loanCharge.getDueLocalDate() != null } else if (loanCharge.getDueLocalDate() != null) {
&& DateUtils.isBefore(loanCharge.getDueLocalDate(), loan.getLastUserTransactionForChargeCalc())) { // TODO: Review, error message seems not valid if interest recalculation is not enabled.
final String defaultUserMessage = "charge with date before last transaction date can not be added to loan."; LocalDate validationDate = loan.repaymentScheduleDetail().isInterestRecalculationEnabled() ? loan.getLastUserTransactionDate()
throw new LoanChargeCannotBeAddedException("loanCharge", "date.is.before.last.transaction.date", defaultUserMessage, null, : loan.getDisbursementDate();
chargeDefinition.getName()); if (DateUtils.isBefore(loanCharge.getDueLocalDate(), validationDate)) {
final String defaultUserMessage = "charge with date before last transaction date can not be added to loan.";
throw new LoanChargeCannotBeAddedException("loanCharge", "date.is.before.last.transaction.date", defaultUserMessage, null,
chargeDefinition.getName());
}
} else if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { } else if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
if (loanCharge.isInstalmentFee() && loan.getStatus().isActive()) { if (loanCharge.isInstalmentFee() && loan.getStatus().isActive()) {
final String defaultUserMessage = "installment charge addition not allowed after disbursement"; final String defaultUserMessage = "installment charge addition not allowed after disbursement";