Skip to content

Commit 61a0f2b

Browse files
committed
FINERACT-2326: Improve null-safety
1 parent 53d9790 commit 61a0f2b

File tree

4 files changed

+100
-26
lines changed

4 files changed

+100
-26
lines changed

fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/MathUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ public static Money nullToZero(Money value, @NotNull MonetaryCurrency currency)
335335
return nullToDefault(value, Money.zero(currency));
336336
}
337337

338+
public static Money nullToZero(Money value, @NotNull MonetaryCurrency currency, @NotNull MathContext mc) {
339+
return nullToDefault(value, Money.zero(currency, mc));
340+
}
341+
338342
public static Money nullToDefault(Money value, Money def) {
339343
return value == null ? def : value;
340344
}

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ public void addDisbursement(final ProgressiveLoanInterestScheduleModel scheduleM
125125
}
126126

127127
private void addDisbursement(final ProgressiveLoanInterestScheduleModel scheduleModel, final EmiChangeOperation operation) {
128-
scheduleModel.repaymentPeriods().stream().filter(rp -> !operation.getSubmittedOnDate().isAfter(rp.getFromDate())).forEach(
129-
rp -> rp.setTotalDisbursedAmount(MathUtil.nullToZero(rp.getTotalDisbursedAmount()).add(operation.getAmount().getAmount())));
128+
scheduleModel.repaymentPeriods().stream().filter(rp -> !operation.getSubmittedOnDate().isAfter(rp.getFromDate()))
129+
.forEach(rp -> rp.setTotalDisbursedAmount(rp.getTotalDisbursedAmount().add(operation.getAmount().getAmount())));
130130

131131
scheduleModel
132132
.changeOutstandingBalanceAndUpdateInterestPeriods(operation.getSubmittedOnDate(), operation.getAmount(),
@@ -161,9 +161,8 @@ public void addCapitalizedIncome(final ProgressiveLoanInterestScheduleModel sche
161161
}
162162

163163
private void addCapitalizedIncome(final ProgressiveLoanInterestScheduleModel scheduleModel, final EmiChangeOperation operation) {
164-
scheduleModel.repaymentPeriods().stream().filter(rp -> !operation.getSubmittedOnDate().isAfter(rp.getFromDate()))
165-
.forEach(rp -> rp.setTotalCapitalizedIncomeAmount(
166-
MathUtil.nullToZero(rp.getTotalCapitalizedIncomeAmount()).add(operation.getAmount().getAmount())));
164+
scheduleModel.repaymentPeriods().stream().filter(rp -> !operation.getSubmittedOnDate().isAfter(rp.getFromDate())).forEach(
165+
rp -> rp.setTotalCapitalizedIncomeAmount(rp.getTotalCapitalizedIncomeAmount().add(operation.getAmount().getAmount())));
167166

168167
scheduleModel.changeOutstandingBalanceAndUpdateInterestPeriods(operation.getSubmittedOnDate(), scheduleModel.zero(),
169168
scheduleModel.zero(), operation.getAmount()).ifPresent((repaymentPeriod) -> {

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/InterestPeriod.java

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.fineract.infrastructure.core.serialization.gson.JsonExclude;
3333
import org.apache.fineract.infrastructure.core.service.DateUtils;
3434
import org.apache.fineract.infrastructure.core.service.MathUtil;
35+
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
3536
import org.apache.fineract.organisation.monetary.domain.Money;
3637
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
3738

@@ -90,21 +91,21 @@ public static InterestPeriod copy(@NotNull RepaymentPeriod repaymentPeriod, @Not
9091

9192
public static InterestPeriod withEmptyAmounts(@NotNull RepaymentPeriod repaymentPeriod, @NotNull LocalDate fromDate,
9293
LocalDate dueDate) {
93-
final Money zero = repaymentPeriod.getEmi().zero();
94+
final Money zero = repaymentPeriod.getZero();
9495
return new InterestPeriod(repaymentPeriod, fromDate, dueDate, BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, zero, zero, zero,
9596
zero.getMc(), false);
9697
}
9798

9899
public static InterestPeriod withEmptyAmounts(@NotNull RepaymentPeriod repaymentPeriod, @NotNull LocalDate fromDate, LocalDate dueDate,
99100
boolean isPaused) {
100-
final Money zero = repaymentPeriod.getEmi().zero();
101+
final Money zero = repaymentPeriod.getZero();
101102
return new InterestPeriod(repaymentPeriod, fromDate, dueDate, BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, zero, zero, zero,
102103
zero.getMc(), isPaused);
103104
}
104105

105106
public static InterestPeriod withPausedAndEmptyAmounts(@NotNull RepaymentPeriod repaymentPeriod, @NotNull LocalDate fromDate,
106107
LocalDate dueDate) {
107-
final Money zero = repaymentPeriod.getEmi().zero();
108+
final Money zero = repaymentPeriod.getZero();
108109
return new InterestPeriod(repaymentPeriod, fromDate, dueDate, BigDecimal.ZERO, BigDecimal.ZERO, zero, zero, zero, zero, zero, zero,
109110
zero.getMc(), true);
110111
}
@@ -150,7 +151,7 @@ public BigDecimal getCalculatedDueInterest(InterestMethod method, long lengthTil
150151
return BigDecimal.ZERO;
151152
}
152153
BigDecimal baseAmount = switch (method) {
153-
case FLAT -> MathUtil.nullToZero(getRepaymentPeriod().calculateTotalDisbursedAndCapitalizedIncomeAmountTillGivenPeriod(this));
154+
case FLAT -> getRepaymentPeriod().calculateTotalDisbursedAndCapitalizedIncomeAmountTillGivenPeriod(this);
154155
case DECLINING_BALANCE -> getOutstandingLoanBalance().getAmount();
155156
default -> throw new UnsupportedOperationException("Method not implemented: " + method);
156157
};
@@ -200,4 +201,41 @@ public Money getCreditedAmounts() {
200201
public boolean isFirstInterestPeriod() {
201202
return this.equals(getRepaymentPeriod().getFirstInterestPeriod());
202203
}
204+
205+
private MonetaryCurrency getCurrency() {
206+
return getRepaymentPeriod().getCurrency();
207+
}
208+
209+
public Money getCreditedPrincipal() {
210+
return MathUtil.nullToZero(creditedPrincipal, getCurrency(), getMc());
211+
}
212+
213+
public Money getCreditedInterest() {
214+
return MathUtil.nullToZero(creditedInterest, getCurrency(), getMc());
215+
}
216+
217+
public Money getDisbursementAmount() {
218+
return MathUtil.nullToZero(disbursementAmount, getCurrency(), getMc());
219+
}
220+
221+
public Money getBalanceCorrectionAmount() {
222+
return MathUtil.nullToZero(balanceCorrectionAmount, getCurrency(), getMc());
223+
}
224+
225+
public Money getOutstandingLoanBalance() {
226+
return MathUtil.nullToZero(outstandingLoanBalance, getCurrency(), getMc());
227+
}
228+
229+
public Money getCapitalizedIncomePrincipal() {
230+
return MathUtil.nullToZero(capitalizedIncomePrincipal, getCurrency(), getMc());
231+
}
232+
233+
public BigDecimal getRateFactor() {
234+
return MathUtil.nullToZero(rateFactor);
235+
}
236+
237+
public BigDecimal getRateFactorTillPeriodDueDate() {
238+
return MathUtil.nullToZero(rateFactorTillPeriodDueDate);
239+
}
240+
203241
}

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import lombok.ToString;
3434
import org.apache.fineract.infrastructure.core.serialization.gson.JsonExclude;
3535
import org.apache.fineract.infrastructure.core.service.MathUtil;
36+
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
3637
import org.apache.fineract.organisation.monetary.domain.Money;
3738
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
3839
import org.apache.fineract.portfolio.util.Memo;
@@ -52,20 +53,16 @@ public final class RepaymentPeriod {
5253
@Setter
5354
private List<InterestPeriod> interestPeriods;
5455
@Setter
55-
@Getter
5656
private Money emi;
5757
@Setter
58-
@Getter
5958
private Money originalEmi;
60-
@Getter
6159
private Money paidPrincipal;
62-
@Getter
6360
private Money paidInterest;
6461
@Setter
65-
@Getter
6662
private Money futureUnrecognizedInterest;
6763

6864
@JsonExclude
65+
@Getter
6966
private final MathContext mc;
7067

7168
@JsonExclude
@@ -91,6 +88,8 @@ public final class RepaymentPeriod {
9188
@JsonExclude
9289
@Getter
9390
private final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail;
91+
@JsonExclude
92+
private MonetaryCurrency currency;
9493

9594
private RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, List<InterestPeriod> interestPeriods,
9695
Money emi, Money originalEmi, Money paidPrincipal, Money paidInterest, Money futureUnrecognizedInterest, MathContext mc,
@@ -186,7 +185,7 @@ public Money getCalculatedDueInterest() {
186185
}
187186

188187
public Money calculateCalculatedDueInterest() {
189-
Money calculatedDueInterest = getZero(mc);
188+
Money calculatedDueInterest = getZero();
190189
if (!isInterestMoved) {
191190
calculatedDueInterest = Money.of(emi.getCurrencyData(),
192191
getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(BigDecimal.ZERO, BigDecimal::add),
@@ -243,7 +242,7 @@ public Money getCalculatedDuePrincipal() {
243242
public Money getCreditedPrincipal() {
244243
return MathUtil.negativeToZero(interestPeriods.stream() //
245244
.map(InterestPeriod::getCreditedPrincipal) //
246-
.reduce(getZero(mc), (value, previous) -> value.plus(previous, mc)), mc); //
245+
.reduce(getZero(), (value, previous) -> value.plus(previous, mc)), mc); //
247246
}
248247

249248
/**
@@ -254,7 +253,7 @@ public Money getCreditedPrincipal() {
254253
public Money getCreditedInterest() {
255254
return MathUtil.negativeToZero(interestPeriods.stream() //
256255
.map(InterestPeriod::getCreditedInterest) //
257-
.reduce(getZero(mc), (value, previous) -> value.plus(previous, mc)), mc); //
256+
.reduce(getZero(), (value, previous) -> value.plus(previous, mc)), mc); //
258257
}
259258

260259
/**
@@ -265,7 +264,7 @@ public Money getCreditedInterest() {
265264
public Money getCapitalizedIncomePrincipal() {
266265
return MathUtil.negativeToZero(interestPeriods.stream() //
267266
.map(InterestPeriod::getCapitalizedIncomePrincipal) //
268-
.reduce(getZero(mc), (value, previous) -> value.plus(previous, mc)), mc); //
267+
.reduce(getZero(), (value, previous) -> value.plus(previous, mc)), mc); //
269268
}
270269

271270
/**
@@ -313,7 +312,7 @@ public Money getUnrecognizedInterest() {
313312
}
314313

315314
public Money getCreditedAmounts() {
316-
return interestPeriods.stream().map(InterestPeriod::getCreditedAmounts).reduce(getZero(mc), (m1, m2) -> m1.plus(m2, mc));
315+
return interestPeriods.stream().map(InterestPeriod::getCreditedAmounts).reduce(getZero(), (m1, m2) -> m1.plus(m2, mc));
317316
}
318317

319318
public Money getOutstandingLoanBalance() {
@@ -345,20 +344,19 @@ public Money getInitialBalanceForEmiRecalculation() {
345344
if (getPrevious().isPresent()) {
346345
initialBalance = getPrevious().get().getOutstandingLoanBalance();
347346
} else {
348-
initialBalance = getZero(mc);
347+
initialBalance = getZero();
349348
}
350349
Money totalDisbursedAmount = getInterestPeriods().stream() //
351350
.map(InterestPeriod::getDisbursementAmount) //
352-
.reduce(getZero(mc), (m1, m2) -> m1.plus(m2, mc)); //
351+
.reduce(getZero(), (m1, m2) -> m1.plus(m2, mc)); //
353352
Money totalCapitalizedIncomeAmount = getInterestPeriods().stream() //
354353
.map(InterestPeriod::getCapitalizedIncomePrincipal) //
355-
.reduce(getZero(mc), (m1, m2) -> m1.plus(m2, mc)); //
354+
.reduce(getZero(), (m1, m2) -> m1.plus(m2, mc)); //
356355
return initialBalance.add(totalDisbursedAmount, mc).add(totalCapitalizedIncomeAmount, mc);
357356
}
358357

359-
private Money getZero(MathContext mc) {
360-
// EMI is always initiated
361-
return this.emi.zero(mc);
358+
public Money getZero() {
359+
return Money.zero(getCurrency(), getMc());
362360
}
363361

364362
public InterestPeriod getFirstInterestPeriod() {
@@ -405,7 +403,7 @@ public void resetDerivedComponents() {
405403
* @return disbursed and capitalized income amount till interest period.
406404
*/
407405
public BigDecimal calculateTotalDisbursedAndCapitalizedIncomeAmountTillGivenPeriod(InterestPeriod tillPeriod) {
408-
BigDecimal res = MathUtil.nullToZero(getTotalDisbursedAmount()).add(MathUtil.nullToZero(getTotalCapitalizedIncomeAmount()));
406+
BigDecimal res = getTotalDisbursedAmount().add(getTotalCapitalizedIncomeAmount());
409407
for (InterestPeriod interestPeriod : this.interestPeriods) {
410408
if (interestPeriod.equals(tillPeriod)) {
411409
break;
@@ -421,4 +419,39 @@ public BigDecimal calculateTotalDisbursedAndCapitalizedIncomeAmountTillGivenPeri
421419
}
422420
return res;
423421
}
422+
423+
public MonetaryCurrency getCurrency() {
424+
if (currency == null) {
425+
currency = MonetaryCurrency.fromCurrencyData(loanProductRelatedDetail.getCurrencyData());
426+
}
427+
return currency;
428+
}
429+
430+
public Money getEmi() {
431+
return MathUtil.nullToZero(emi, getCurrency(), getMc());
432+
}
433+
434+
public Money getOriginalEmi() {
435+
return MathUtil.nullToZero(originalEmi, getCurrency(), getMc());
436+
}
437+
438+
public Money getPaidPrincipal() {
439+
return MathUtil.nullToZero(paidPrincipal, getCurrency(), getMc());
440+
}
441+
442+
public Money getPaidInterest() {
443+
return MathUtil.nullToZero(paidInterest, getCurrency(), getMc());
444+
}
445+
446+
public Money getFutureUnrecognizedInterest() {
447+
return MathUtil.nullToZero(futureUnrecognizedInterest, getCurrency(), getMc());
448+
}
449+
450+
public BigDecimal getTotalDisbursedAmount() {
451+
return MathUtil.nullToZero(totalDisbursedAmount);
452+
}
453+
454+
public BigDecimal getTotalCapitalizedIncomeAmount() {
455+
return MathUtil.nullToZero(totalCapitalizedIncomeAmount);
456+
}
424457
}

0 commit comments

Comments
 (0)