This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 88105c3cac FINERACT-2273: Make sure the setters of Loan repayment 
installment entity balances maintain the scaling of 6 and set null in case the 
value is zero
88105c3cac is described below

commit 88105c3caca0fcc05bbf718cb5737417bddf17ba
Author: mariiaKraievska <[email protected]>
AuthorDate: Thu May 22 15:06:43 2025 +0300

    FINERACT-2273: Make sure the setters of Loan repayment installment entity 
balances maintain the scaling of 6 and set null in case the value is zero
---
 .../domain/LoanRepaymentScheduleInstallment.java   | 352 ++++++++++++---------
 .../LoanRepaymentScheduleInstallmentTest.java      | 209 ++++++++++++
 ...cyWritePlatformServiceRangeChangeEventTest.java |  18 ++
 .../ClientLoanIntegrationTest.java                 |  20 +-
 ...LoanSpecificDueDateChargeAfterMaturityTest.java |  16 +-
 .../integrationtests/SchedulerJobsTestResults.java |   6 +-
 6 files changed, 454 insertions(+), 167 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index ed0c14e90b..94d6dd3151 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -40,6 +40,7 @@ import 
org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
 import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
 import 
org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
@@ -196,17 +197,17 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         this.installmentNumber = installmentNumber;
         this.fromDate = fromDate;
         this.dueDate = dueDate;
-        this.principal = defaultToNullIfZero(principal);
-        this.interestCharged = defaultToNullIfZero(interest);
-        this.feeChargesCharged = defaultToNullIfZero(feeCharges);
-        this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
+        setPrincipal(principal);
+        setInterestCharged(interest);
+        setFeeChargesCharged(feeCharges);
+        setPenaltyCharges(penaltyCharges);
         this.obligationsMet = false;
         this.recalculatedInterestComponent = recalculatedInterestComponent;
         if (compoundingDetails != null) {
             compoundingDetails.forEach(cd -> 
cd.setLoanRepaymentScheduleInstallment(this));
         }
         this.loanCompoundingDetails = compoundingDetails;
-        this.rescheduleInterestPortion = rescheduleInterestPortion;
+        setRescheduleInterestPortion(rescheduleInterestPortion);
         this.isDownPayment = isDownPayment;
     }
 
@@ -218,10 +219,10 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         this.installmentNumber = installmentNumber;
         this.fromDate = fromDate;
         this.dueDate = dueDate;
-        this.principal = defaultToNullIfZero(principal);
-        this.interestCharged = defaultToNullIfZero(interest);
-        this.feeChargesCharged = defaultToNullIfZero(feeCharges);
-        this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
+        setPrincipal(principal);
+        setInterestCharged(interest);
+        setFeeChargesCharged(feeCharges);
+        setPenaltyCharges(penaltyCharges);
         this.obligationsMet = false;
         this.recalculatedInterestComponent = recalculatedInterestComponent;
         if (compoundingDetails != null) {
@@ -246,14 +247,14 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         this.installmentNumber = installmentNumber;
         this.fromDate = fromDate;
         this.dueDate = dueDate;
-        this.principal = principal;
-        this.interestCharged = interestCharged;
-        this.feeChargesCharged = feeChargesCharged;
-        this.penaltyCharges = penaltyCharges;
-        this.creditedPrincipal = creditedPrincipal;
-        this.creditedInterest = creditedInterest;
-        this.creditedFee = creditedFee;
-        this.creditedPenalty = creditedPenalty;
+        setPrincipal(principal);
+        setInterestCharged(interestCharged);
+        setFeeChargesCharged(feeChargesCharged);
+        setPenaltyCharges(penaltyCharges);
+        setCreditedPrincipal(creditedPrincipal);
+        setCreditedInterest(creditedInterest);
+        setCreditedFee(creditedFee);
+        setCreditedPenalty(creditedPenalty);
         this.additional = additional;
         this.isDownPayment = isDownPayment;
         this.isReAged = isReAged;
@@ -269,14 +270,6 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         return installments.stream().filter(i -> 
!i.isDownPayment()).reduce((first, second) -> second).orElseThrow();
     }
 
-    private BigDecimal defaultToNullIfZero(final BigDecimal value) {
-        BigDecimal result = value;
-        if (BigDecimal.ZERO.compareTo(value) == 0) {
-            result = null;
-        }
-        return result;
-    }
-
     public Money getCreditedPrincipal(final MonetaryCurrency currency) {
         return Money.of(currency, this.creditedPrincipal);
     }
@@ -393,6 +386,106 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
                 .plus(getPenaltyChargesOutstanding(currency));
     }
 
+    public void setPrincipal(final BigDecimal principal) {
+        this.principal = setScaleAndDefaultToNullIfZero(principal);
+    }
+
+    public void setPrincipalCompleted(final BigDecimal principalCompleted) {
+        this.principalCompleted = 
setScaleAndDefaultToNullIfZero(principalCompleted);
+    }
+
+    public void setPrincipalWrittenOff(final BigDecimal principalWrittenOff) {
+        this.principalWrittenOff = 
setScaleAndDefaultToNullIfZero(principalWrittenOff);
+    }
+
+    public void setInterestCharged(final BigDecimal interestCharged) {
+        this.interestCharged = setScaleAndDefaultToNullIfZero(interestCharged);
+    }
+
+    public void setInterestPaid(final BigDecimal interestPaid) {
+        this.interestPaid = setScaleAndDefaultToNullIfZero(interestPaid);
+    }
+
+    public void setInterestWaived(final BigDecimal interestWaived) {
+        this.interestWaived = setScaleAndDefaultToNullIfZero(interestWaived);
+    }
+
+    public void setInterestWrittenOff(final BigDecimal interestWrittenOff) {
+        this.interestWrittenOff = 
setScaleAndDefaultToNullIfZero(interestWrittenOff);
+    }
+
+    public void setInterestAccrued(final BigDecimal interestAccrued) {
+        this.interestAccrued = setScaleAndDefaultToNullIfZero(interestAccrued);
+    }
+
+    public void setRescheduleInterestPortion(final BigDecimal 
rescheduleInterestPortion) {
+        this.rescheduleInterestPortion = 
setScaleAndDefaultToNullIfZero(rescheduleInterestPortion);
+    }
+
+    public void setFeeChargesCharged(final BigDecimal feeChargesCharged) {
+        this.feeChargesCharged = 
setScaleAndDefaultToNullIfZero(feeChargesCharged);
+    }
+
+    public void setFeeChargesPaid(final BigDecimal feeChargesPaid) {
+        this.feeChargesPaid = setScaleAndDefaultToNullIfZero(feeChargesPaid);
+    }
+
+    public void setFeeChargesWrittenOff(final BigDecimal feeChargesWrittenOff) 
{
+        this.feeChargesWrittenOff = 
setScaleAndDefaultToNullIfZero(feeChargesWrittenOff);
+    }
+
+    public void setFeeChargesWaived(final BigDecimal feeChargesWaived) {
+        this.feeChargesWaived = 
setScaleAndDefaultToNullIfZero(feeChargesWaived);
+    }
+
+    public void setFeeAccrued(final BigDecimal feeAccrued) {
+        this.feeAccrued = setScaleAndDefaultToNullIfZero(feeAccrued);
+    }
+
+    public void setPenaltyCharges(final BigDecimal penaltyCharges) {
+        this.penaltyCharges = setScaleAndDefaultToNullIfZero(penaltyCharges);
+    }
+
+    public void setPenaltyChargesPaid(final BigDecimal penaltyChargesPaid) {
+        this.penaltyChargesPaid = 
setScaleAndDefaultToNullIfZero(penaltyChargesPaid);
+    }
+
+    public void setPenaltyChargesWrittenOff(final BigDecimal 
penaltyChargesWrittenOff) {
+        this.penaltyChargesWrittenOff = 
setScaleAndDefaultToNullIfZero(penaltyChargesWrittenOff);
+    }
+
+    public void setPenaltyChargesWaived(final BigDecimal penaltyChargesWaived) 
{
+        this.penaltyChargesWaived = 
setScaleAndDefaultToNullIfZero(penaltyChargesWaived);
+    }
+
+    public void setPenaltyAccrued(final BigDecimal penaltyAccrued) {
+        this.penaltyAccrued = setScaleAndDefaultToNullIfZero(penaltyAccrued);
+    }
+
+    public void setTotalPaidInAdvance(final BigDecimal totalPaidInAdvance) {
+        this.totalPaidInAdvance = 
setScaleAndDefaultToNullIfZero(totalPaidInAdvance);
+    }
+
+    public void setTotalPaidLate(final BigDecimal totalPaidLate) {
+        this.totalPaidLate = setScaleAndDefaultToNullIfZero(totalPaidLate);
+    }
+
+    public void setCreditedPrincipal(final BigDecimal creditedPrincipal) {
+        this.creditedPrincipal = 
setScaleAndDefaultToNullIfZero(creditedPrincipal);
+    }
+
+    public void setCreditedInterest(final BigDecimal creditedInterest) {
+        this.creditedInterest = 
setScaleAndDefaultToNullIfZero(creditedInterest);
+    }
+
+    public void setCreditedFee(final BigDecimal creditedFee) {
+        this.creditedFee = setScaleAndDefaultToNullIfZero(creditedFee);
+    }
+
+    public void setCreditedPenalty(final BigDecimal creditedPenalty) {
+        this.creditedPenalty = setScaleAndDefaultToNullIfZero(creditedPenalty);
+    }
+
     void updateLoan(final Loan loan) {
         this.loan = loan;
     }
@@ -436,19 +529,19 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         this.obligationsMet = false;
         this.obligationsMetOnDate = null;
         if (this.creditedPrincipal != null) {
-            this.principal = this.principal.subtract(this.creditedPrincipal);
+            setPrincipal(this.principal != null ? 
this.principal.subtract(this.creditedPrincipal) : null);
             this.creditedPrincipal = null;
         }
         if (this.creditedInterest != null) {
-            this.interestCharged = 
this.interestCharged.subtract(this.creditedInterest);
+            setInterestCharged(this.interestCharged != null ? 
this.interestCharged.subtract(this.creditedInterest) : null);
             this.creditedInterest = null;
         }
         if (this.creditedFee != null) {
-            this.feeChargesCharged = 
this.feeChargesCharged.subtract(this.creditedFee);
+            setFeeChargesCharged(this.feeChargesCharged != null ? 
this.feeChargesCharged.subtract(this.creditedFee) : null);
             this.creditedFee = null;
         }
         if (this.creditedPenalty != null) {
-            this.penaltyCharges = 
this.penaltyCharges.subtract(this.creditedPenalty);
+            setPenaltyCharges(this.penaltyCharges != null ? 
this.penaltyCharges.subtract(this.creditedPenalty) : null);
             this.creditedPenalty = null;
         }
     }
@@ -464,6 +557,14 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         this.penaltyCharges = null;
     }
 
+    public void resetInterestDue() {
+        this.interestCharged = null;
+    }
+
+    public void resetPrincipalDue() {
+        this.principal = null;
+    }
+
     public interface PaymentFunction {
 
         Money accept(LocalDate transactionDate, Money 
transactionAmountRemaining);
@@ -483,7 +584,6 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     }
 
     public Money payPenaltyChargesComponent(final LocalDate transactionDate, 
final Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money penaltyPortionOfTransaction = Money.zero(currency);
 
@@ -493,24 +593,20 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
 
         final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency);
         if 
(transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) {
-            this.penaltyChargesPaid = 
getPenaltyChargesPaid(currency).plus(penaltyChargesDue).getAmount();
+            
setPenaltyChargesPaid(getPenaltyChargesPaid(currency).plus(penaltyChargesDue).getAmount());
             penaltyPortionOfTransaction = 
penaltyPortionOfTransaction.plus(penaltyChargesDue);
         } else {
-            this.penaltyChargesPaid = 
getPenaltyChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
+            
setPenaltyChargesPaid(getPenaltyChargesPaid(currency).plus(transactionAmountRemaining).getAmount());
             penaltyPortionOfTransaction = 
penaltyPortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.penaltyChargesPaid = defaultToNullIfZero(this.penaltyChargesPaid);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, 
penaltyPortionOfTransaction);
 
         return penaltyPortionOfTransaction;
     }
 
     public Money payFeeChargesComponent(final LocalDate transactionDate, final 
Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money feePortionOfTransaction = Money.zero(currency);
         if (transactionAmountRemaining.isZero()) {
@@ -518,24 +614,20 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         }
         final Money feeChargesDue = getFeeChargesOutstanding(currency);
         if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) {
-            this.feeChargesPaid = 
getFeeChargesPaid(currency).plus(feeChargesDue).getAmount();
+            
setFeeChargesPaid(getFeeChargesPaid(currency).plus(feeChargesDue).getAmount());
             feePortionOfTransaction = 
feePortionOfTransaction.plus(feeChargesDue);
         } else {
-            this.feeChargesPaid = 
getFeeChargesPaid(currency).plus(transactionAmountRemaining).getAmount();
+            
setFeeChargesPaid(getFeeChargesPaid(currency).plus(transactionAmountRemaining).getAmount());
             feePortionOfTransaction = 
feePortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.feeChargesPaid = defaultToNullIfZero(this.feeChargesPaid);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, 
feePortionOfTransaction);
 
         return feePortionOfTransaction;
     }
 
     public Money payInterestComponent(final LocalDate transactionDate, final 
Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money interestPortionOfTransaction = Money.zero(currency);
         if (transactionAmountRemaining.isZero()) {
@@ -543,24 +635,20 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         }
         final Money interestDue = getInterestOutstanding(currency);
         if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
-            this.interestPaid = 
getInterestPaid(currency).plus(interestDue).getAmount();
+            
setInterestPaid(getInterestPaid(currency).plus(interestDue).getAmount());
             interestPortionOfTransaction = 
interestPortionOfTransaction.plus(interestDue);
         } else {
-            this.interestPaid = 
getInterestPaid(currency).plus(transactionAmountRemaining).getAmount();
+            
setInterestPaid(getInterestPaid(currency).plus(transactionAmountRemaining).getAmount());
             interestPortionOfTransaction = 
interestPortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.interestPaid = defaultToNullIfZero(this.interestPaid);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, 
interestPortionOfTransaction);
 
         return interestPortionOfTransaction;
     }
 
     public Money payPrincipalComponent(final LocalDate transactionDate, final 
Money transactionAmount) {
-
         final MonetaryCurrency currency = transactionAmount.getCurrency();
         Money principalPortionOfTransaction = Money.zero(currency);
         if (transactionAmount.isZero()) {
@@ -568,17 +656,14 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         }
         final Money principalDue = getPrincipalOutstanding(currency);
         if (transactionAmount.isGreaterThanOrEqualTo(principalDue)) {
-            this.principalCompleted = 
getPrincipalCompleted(currency).plus(principalDue).getAmount();
+            
setPrincipalCompleted(getPrincipalCompleted(currency).plus(principalDue).getAmount());
             principalPortionOfTransaction = 
principalPortionOfTransaction.plus(principalDue);
         } else {
-            this.principalCompleted = 
getPrincipalCompleted(currency).plus(transactionAmount).getAmount();
+            
setPrincipalCompleted(getPrincipalCompleted(currency).plus(transactionAmount).getAmount());
             principalPortionOfTransaction = 
principalPortionOfTransaction.plus(transactionAmount);
         }
 
-        this.principalCompleted = defaultToNullIfZero(this.principalCompleted);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         trackAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, currency, 
principalPortionOfTransaction);
 
         return principalPortionOfTransaction;
@@ -592,15 +677,13 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         }
         final Money interestDue = getInterestOutstanding(currency);
         if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
-            this.interestWaived = 
getInterestWaived(currency).plus(interestDue).getAmount();
+            
setInterestWaived(getInterestWaived(currency).plus(interestDue).getAmount());
             waivedInterestPortionOfTransaction = 
waivedInterestPortionOfTransaction.plus(interestDue);
         } else {
-            this.interestWaived = 
getInterestWaived(currency).plus(transactionAmountRemaining).getAmount();
+            
setInterestWaived(getInterestWaived(currency).plus(transactionAmountRemaining).getAmount());
             waivedInterestPortionOfTransaction = 
waivedInterestPortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.interestWaived = defaultToNullIfZero(this.interestWaived);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
 
         return waivedInterestPortionOfTransaction;
@@ -612,17 +695,15 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         if (transactionAmountRemaining.isZero()) {
             return waivedPenaltyChargesPortionOfTransaction;
         }
-        final Money penanltiesDue = getPenaltyChargesOutstanding(currency);
-        if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) {
-            this.penaltyChargesWaived = 
getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount();
-            waivedPenaltyChargesPortionOfTransaction = 
waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue);
+        final Money penaltiesDue = getPenaltyChargesOutstanding(currency);
+        if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltiesDue)) {
+            
setPenaltyChargesWaived(getPenaltyChargesWaived(currency).plus(penaltiesDue).getAmount());
+            waivedPenaltyChargesPortionOfTransaction = 
waivedPenaltyChargesPortionOfTransaction.plus(penaltiesDue);
         } else {
-            this.penaltyChargesWaived = 
getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
+            
setPenaltyChargesWaived(getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount());
             waivedPenaltyChargesPortionOfTransaction = 
waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.penaltyChargesWaived = 
defaultToNullIfZero(this.penaltyChargesWaived);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
 
         return waivedPenaltyChargesPortionOfTransaction;
@@ -636,55 +717,43 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         }
         final Money feesDue = getFeeChargesOutstanding(currency);
         if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
-            this.feeChargesWaived = 
getFeeChargesWaived(currency).plus(feesDue).getAmount();
+            
setFeeChargesWaived(getFeeChargesWaived(currency).plus(feesDue).getAmount());
             waivedFeeChargesPortionOfTransaction = 
waivedFeeChargesPortionOfTransaction.plus(feesDue);
         } else {
-            this.feeChargesWaived = 
getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
+            
setFeeChargesWaived(getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount());
             waivedFeeChargesPortionOfTransaction = 
waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining);
         }
 
-        this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived);
-
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
 
         return waivedFeeChargesPortionOfTransaction;
     }
 
     public Money writeOffOutstandingPrincipal(final LocalDate transactionDate, 
final MonetaryCurrency currency) {
-
         final Money principalDue = getPrincipalOutstanding(currency);
-        this.principalWrittenOff = 
defaultToNullIfZero(principalDue.getAmount());
-
+        setPrincipalWrittenOff(principalDue.getAmount());
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         return principalDue;
     }
 
     public Money writeOffOutstandingInterest(final LocalDate transactionDate, 
final MonetaryCurrency currency) {
-
         final Money interestDue = getInterestOutstanding(currency);
-        this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount());
-
+        setInterestWrittenOff(interestDue.getAmount());
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         return interestDue;
     }
 
     public Money writeOffOutstandingFeeCharges(final LocalDate 
transactionDate, final MonetaryCurrency currency) {
         final Money feeChargesOutstanding = getFeeChargesOutstanding(currency);
-        this.feeChargesWrittenOff = 
defaultToNullIfZero(feeChargesOutstanding.getAmount());
-
+        setFeeChargesWrittenOff(feeChargesOutstanding.getAmount());
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         return feeChargesOutstanding;
     }
 
     public Money writeOffOutstandingPenaltyCharges(final LocalDate 
transactionDate, final MonetaryCurrency currency) {
         final Money penaltyChargesOutstanding = 
getPenaltyChargesOutstanding(currency);
-        this.penaltyChargesWrittenOff = 
defaultToNullIfZero(penaltyChargesOutstanding.getAmount());
-
+        setPenaltyChargesWrittenOff(penaltyChargesOutstanding.getAmount());
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         return penaltyChargesOutstanding;
     }
 
@@ -694,32 +763,29 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
 
     public void updateChargePortion(final Money feeChargesDue, final Money 
feeChargesWaived, final Money feeChargesWrittenOff,
             final Money penaltyChargesDue, final Money penaltyChargesWaived, 
final Money penaltyChargesWrittenOff) {
-        this.feeChargesCharged = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(feeChargesDue));
-        this.feeChargesWaived = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(feeChargesWaived));
-        this.feeChargesWrittenOff = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(feeChargesWrittenOff));
-        this.penaltyCharges = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(penaltyChargesDue));
-        this.penaltyChargesWaived = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(penaltyChargesWaived));
-        this.penaltyChargesWrittenOff = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(penaltyChargesWrittenOff));
+        setFeeChargesCharged(feeChargesDue.getAmount());
+        setFeeChargesWaived(feeChargesWaived.getAmount());
+        setFeeChargesWrittenOff(feeChargesWrittenOff.getAmount());
+        setPenaltyCharges(penaltyChargesDue.getAmount());
+        setPenaltyChargesWaived(penaltyChargesWaived.getAmount());
+        setPenaltyChargesWrittenOff(penaltyChargesWrittenOff.getAmount());
     }
 
     public void addToChargePortion(final Money feeChargesDue, final Money 
feeChargesWaived, final Money feeChargesWrittenOff,
             final Money penaltyChargesDue, final Money penaltyChargesWaived, 
final Money penaltyChargesWrittenOff) {
-        this.feeChargesCharged = 
MathUtil.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(feeChargesDue), 
this.feeChargesCharged));
-        this.feeChargesWaived = 
MathUtil.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(feeChargesWaived), 
this.feeChargesWaived));
-        this.feeChargesWrittenOff = MathUtil
-                
.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(feeChargesWrittenOff), 
this.feeChargesWrittenOff));
-        this.penaltyCharges = 
MathUtil.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(penaltyChargesDue), 
this.penaltyCharges));
-        this.penaltyChargesWaived = MathUtil
-                
.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(penaltyChargesWaived), 
this.penaltyChargesWaived));
-        this.penaltyChargesWrittenOff = MathUtil
-                
.zeroToNull(MathUtil.add(MathUtil.toBigDecimal(penaltyChargesWrittenOff), 
this.penaltyChargesWrittenOff));
+        setFeeChargesCharged(MathUtil.add(feeChargesDue.getAmount(), 
this.feeChargesCharged));
+        setFeeChargesWaived(MathUtil.add(feeChargesWaived.getAmount(), 
this.feeChargesWaived));
+        setFeeChargesWrittenOff(MathUtil.add(feeChargesWrittenOff.getAmount(), 
this.feeChargesWrittenOff));
+        setPenaltyCharges(MathUtil.add(penaltyChargesDue.getAmount(), 
this.penaltyCharges));
+        setPenaltyChargesWaived(MathUtil.add(penaltyChargesWaived.getAmount(), 
this.penaltyChargesWaived));
+        
setPenaltyChargesWrittenOff(MathUtil.add(penaltyChargesWrittenOff.getAmount(), 
this.penaltyChargesWrittenOff));
         checkIfRepaymentPeriodObligationsAreMet(getObligationsMetOnDate(), 
feeChargesDue.getCurrency());
     }
 
     public void updateAccrualPortion(final Money interest, final Money 
feeCharges, final Money penalityCharges) {
-        this.interestAccrued = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(interest));
-        this.feeAccrued = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(feeCharges));
-        this.penaltyAccrued = 
MathUtil.zeroToNull(MathUtil.toBigDecimal(penalityCharges));
+        setInterestAccrued(interest.getAmount());
+        setFeeAccrued(feeCharges.getAmount());
+        setPenaltyAccrued(penalityCharges.getAmount());
     }
 
     public void updateObligationsMet(final MonetaryCurrency currency, final 
LocalDate transactionDate) {
@@ -735,9 +801,9 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     private void trackAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate 
transactionDate, final MonetaryCurrency currency,
             final Money amountPaidInRepaymentPeriod) {
         if (isInAdvance(transactionDate)) {
-            this.totalPaidInAdvance = asMoney(this.totalPaidInAdvance, 
currency).plus(amountPaidInRepaymentPeriod).getAmount();
+            setTotalPaidInAdvance(asMoney(this.totalPaidInAdvance, 
currency).plus(amountPaidInRepaymentPeriod).getAmount());
         } else if (isLatePayment(transactionDate)) {
-            this.totalPaidLate = asMoney(this.totalPaidLate, 
currency).plus(amountPaidInRepaymentPeriod).getAmount();
+            setTotalPaidLate(asMoney(this.totalPaidLate, 
currency).plus(amountPaidInRepaymentPeriod).getAmount());
         }
     }
 
@@ -785,7 +851,7 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     }
 
     public void updateInterestCharged(final BigDecimal interestCharged) {
-        this.interestCharged = interestCharged;
+        setInterestCharged(interestCharged);
     }
 
     public void updateObligationMet(final Boolean obligationMet) {
@@ -797,72 +863,71 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     }
 
     public void updatePrincipal(final BigDecimal principal) {
-        this.principal = principal;
+        setPrincipal(principal);
     }
 
     public void addToPrincipal(final LocalDate transactionDate, final Money 
transactionAmount) {
         if (this.principal == null) {
-            this.principal = transactionAmount.getAmount();
+            setPrincipal(transactionAmount.getAmount());
         } else {
-            this.principal = this.principal.add(transactionAmount.getAmount());
+            setPrincipal(this.principal.add(transactionAmount.getAmount()));
         }
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, 
transactionAmount.getCurrency());
     }
 
     public void addToInterest(final LocalDate transactionDate, final Money 
transactionAmount) {
         if (this.interestCharged == null) {
-            this.interestCharged = transactionAmount.getAmount();
+            setInterestCharged(transactionAmount.getAmount());
         } else {
-            this.interestCharged = 
this.interestCharged.add(transactionAmount.getAmount());
+            
setInterestCharged(this.interestCharged.add(transactionAmount.getAmount()));
         }
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, 
transactionAmount.getCurrency());
     }
 
     public void addToCreditedInterest(final BigDecimal amount) {
         if (this.creditedInterest == null) {
-            this.creditedInterest = amount;
+            setCreditedInterest(amount);
         } else {
-            this.creditedInterest = this.creditedInterest.add(amount);
+            setCreditedInterest(this.creditedInterest.add(amount));
         }
     }
 
     public void addToCreditedPrincipal(final BigDecimal amount) {
         if (this.creditedPrincipal == null) {
-            this.creditedPrincipal = amount;
+            setCreditedPrincipal(amount);
         } else {
-            this.creditedPrincipal = this.creditedPrincipal.add(amount);
+            setCreditedPrincipal(this.creditedPrincipal.add(amount));
         }
     }
 
     public void addToCreditedFee(final BigDecimal amount) {
         if (this.creditedFee == null) {
-            this.creditedFee = amount;
+            setCreditedFee(amount);
         } else {
-            this.creditedFee = this.creditedFee.add(amount);
+            setCreditedFee(this.creditedFee.add(amount));
         }
     }
 
     public void addToCreditedPenalty(final BigDecimal amount) {
         if (this.creditedPenalty == null) {
-            this.creditedPenalty = amount;
+            setCreditedPenalty(amount);
         } else {
-            this.creditedPenalty = this.creditedPenalty.add(amount);
+            setCreditedPenalty(this.creditedPenalty.add(amount));
         }
     }
 
     /********** UNPAY COMPONENTS ****/
 
     public Money unpayPenaltyChargesComponent(final LocalDate transactionDate, 
final Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money penaltyPortionOfTransactionDeducted;
 
         final Money penaltyChargesCompleted = getPenaltyChargesPaid(currency);
         if 
(transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesCompleted)) {
-            this.penaltyChargesPaid = Money.zero(currency).getAmount();
+            this.penaltyChargesPaid = null;
             penaltyPortionOfTransactionDeducted = penaltyChargesCompleted;
         } else {
-            this.penaltyChargesPaid = 
penaltyChargesCompleted.minus(transactionAmountRemaining).getAmount();
+            
setPenaltyChargesPaid(penaltyChargesCompleted.minus(transactionAmountRemaining).getAmount());
             penaltyPortionOfTransactionDeducted = transactionAmountRemaining;
         }
 
@@ -872,63 +937,57 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     }
 
     public Money unpayFeeChargesComponent(final LocalDate transactionDate, 
final Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money feePortionOfTransactionDeducted;
 
         final Money feeChargesCompleted = getFeeChargesPaid(currency);
         if 
(transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesCompleted)) {
-            this.feeChargesPaid = Money.zero(currency).getAmount();
+            this.feeChargesPaid = null;
             feePortionOfTransactionDeducted = feeChargesCompleted;
         } else {
-            this.feeChargesPaid = 
feeChargesCompleted.minus(transactionAmountRemaining).getAmount();
+            
setFeeChargesPaid(feeChargesCompleted.minus(transactionAmountRemaining).getAmount());
             feePortionOfTransactionDeducted = transactionAmountRemaining;
         }
 
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, 
currency, feePortionOfTransactionDeducted);
 
         return feePortionOfTransactionDeducted;
     }
 
     public Money unpayInterestComponent(final LocalDate transactionDate, final 
Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money interestPortionOfTransactionDeducted;
 
         final Money interestCompleted = getInterestPaid(currency);
         if 
(transactionAmountRemaining.isGreaterThanOrEqualTo(interestCompleted)) {
-            this.interestPaid = Money.zero(currency).getAmount();
+            this.interestPaid = null;
             interestPortionOfTransactionDeducted = interestCompleted;
         } else {
-            this.interestPaid = 
interestCompleted.minus(transactionAmountRemaining).getAmount();
+            
setInterestPaid(interestCompleted.minus(transactionAmountRemaining).getAmount());
             interestPortionOfTransactionDeducted = transactionAmountRemaining;
         }
 
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, 
currency, interestPortionOfTransactionDeducted);
 
         return interestPortionOfTransactionDeducted;
     }
 
     public Money unpayPrincipalComponent(final LocalDate transactionDate, 
final Money transactionAmountRemaining) {
-
         final MonetaryCurrency currency = 
transactionAmountRemaining.getCurrency();
         Money principalPortionOfTransactionDeducted;
 
         final Money principalCompleted = getPrincipalCompleted(currency);
         if 
(transactionAmountRemaining.isGreaterThanOrEqualTo(principalCompleted)) {
-            this.principalCompleted = Money.zero(currency).getAmount();
+            this.principalCompleted = null;
             principalPortionOfTransactionDeducted = principalCompleted;
         } else {
-            this.principalCompleted = 
principalCompleted.minus(transactionAmountRemaining).getAmount();
+            
setPrincipalCompleted(principalCompleted.minus(transactionAmountRemaining).getAmount());
             principalPortionOfTransactionDeducted = transactionAmountRemaining;
         }
 
         checkIfRepaymentPeriodObligationsAreMet(transactionDate, currency);
-
         reduceAdvanceAndLateTotalsForRepaymentPeriod(transactionDate, 
currency, principalPortionOfTransactionDeducted);
 
         return principalPortionOfTransactionDeducted;
@@ -936,23 +995,22 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
 
     private void reduceAdvanceAndLateTotalsForRepaymentPeriod(final LocalDate 
transactionDate, final MonetaryCurrency currency,
             final Money amountDeductedInRepaymentPeriod) {
-
         if (isInAdvance(transactionDate)) {
-            Money mTotalPaidInAdvance = Money.of(currency, 
this.totalPaidInAdvance);
+            final Money mTotalPaidInAdvance = Money.of(currency, 
this.totalPaidInAdvance);
 
             if (mTotalPaidInAdvance.isLessThan(amountDeductedInRepaymentPeriod)
                     || 
mTotalPaidInAdvance.isEqualTo(amountDeductedInRepaymentPeriod)) {
-                this.totalPaidInAdvance = Money.zero(currency).getAmount();
+                this.totalPaidInAdvance = null;
             } else {
-                this.totalPaidInAdvance = 
mTotalPaidInAdvance.minus(amountDeductedInRepaymentPeriod).getAmount();
+                
setTotalPaidInAdvance(mTotalPaidInAdvance.minus(amountDeductedInRepaymentPeriod).getAmount());
             }
         } else if (isLatePayment(transactionDate)) {
-            Money mTotalPaidLate = Money.of(currency, this.totalPaidLate);
+            final Money mTotalPaidLate = Money.of(currency, 
this.totalPaidLate);
 
             if (mTotalPaidLate.isLessThan(amountDeductedInRepaymentPeriod) || 
mTotalPaidLate.isEqualTo(amountDeductedInRepaymentPeriod)) {
-                this.totalPaidLate = Money.zero(currency).getAmount();
+                this.totalPaidLate = null;
             } else {
-                this.totalPaidLate = 
mTotalPaidLate.minus(amountDeductedInRepaymentPeriod).getAmount();
+                
setTotalPaidLate(mTotalPaidLate.minus(amountDeductedInRepaymentPeriod).getAmount());
             }
         }
     }
@@ -983,14 +1041,6 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
         resetInterestDue();
     }
 
-    public void resetInterestDue() {
-        this.interestCharged = null;
-    }
-
-    public void resetPrincipalDue() {
-        this.principal = null;
-    }
-
     public enum PaymentAction {
         PAY, //
         UNPAY //
@@ -1155,4 +1205,14 @@ public class LoanRepaymentScheduleInstallment extends 
AbstractAuditableWithUTCDa
     private static boolean nonNullAndEqual(Object a, Object b) {
         return a != null && b != null && Objects.equals(a, b);
     }
+
+    private BigDecimal setScaleAndDefaultToNullIfZero(final BigDecimal value) {
+        if (value == null) {
+            return null;
+        }
+        if (value.compareTo(BigDecimal.ZERO) == 0) {
+            return null;
+        }
+        return value.setScale(6, MoneyHelper.getRoundingMode());
+    }
 }
diff --git 
a/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentTest.java
 
b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentTest.java
new file mode 100644
index 0000000000..5ab2156a5e
--- /dev/null
+++ 
b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentTest.java
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.domain;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+class LoanRepaymentScheduleInstallmentTest {
+
+    private static final int SCALE = 6;
+    private static final int PRECISION = 19;
+    private static final MockedStatic<MoneyHelper> MONEY_HELPER = 
mockStatic(MoneyHelper.class);
+    private static final MathContext MATH_CONTEXT = new MathContext(PRECISION, 
RoundingMode.HALF_EVEN);
+
+    private LoanRepaymentScheduleInstallment installment;
+
+    @BeforeAll
+    static void init() {
+        
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+        
MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(MATH_CONTEXT);
+    }
+
+    @BeforeEach
+    void setUp() {
+        final Loan loan = mock(Loan.class);
+        installment = new LoanRepaymentScheduleInstallment(loan, 1, 
LocalDate.now(ZoneId.systemDefault()),
+                LocalDate.now(ZoneId.systemDefault()).plusMonths(1), 
BigDecimal.valueOf(1000), BigDecimal.valueOf(100),
+                BigDecimal.valueOf(50), BigDecimal.valueOf(25), 
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false,
+                false, false);
+    }
+
+    @AfterAll
+    static void tearDown() {
+        MONEY_HELPER.close();
+    }
+
+    @Test
+    void testPrincipalSetters() {
+        testBigDecimalSetter(installment::setPrincipal, 
installment::getPrincipal);
+    }
+
+    @Test
+    void testPrincipalCompletedSetters() {
+        testBigDecimalSetter(installment::setPrincipalCompleted, 
installment::getPrincipalCompleted);
+    }
+
+    @Test
+    void testPrincipalWrittenOffSetters() {
+        testBigDecimalSetter(installment::setPrincipalWrittenOff, 
installment::getPrincipalWrittenOff);
+    }
+
+    @Test
+    void testInterestChargedSetters() {
+        testBigDecimalSetter(installment::setInterestCharged, 
installment::getInterestCharged);
+    }
+
+    @Test
+    void testInterestPaidSetters() {
+        testBigDecimalSetter(installment::setInterestPaid, 
installment::getInterestPaid);
+    }
+
+    @Test
+    void testInterestWaivedSetters() {
+        testBigDecimalSetter(installment::setInterestWaived, 
installment::getInterestWaived);
+    }
+
+    @Test
+    void testInterestWrittenOffSetters() {
+        testBigDecimalSetter(installment::setInterestWrittenOff, 
installment::getInterestWrittenOff);
+    }
+
+    @Test
+    void testInterestAccruedSetters() {
+        testBigDecimalSetter(installment::setInterestAccrued, 
installment::getInterestAccrued);
+    }
+
+    @Test
+    void testRescheduleInterestPortionSetters() {
+        testBigDecimalSetter(installment::setRescheduleInterestPortion, 
installment::getRescheduleInterestPortion);
+    }
+
+    @Test
+    void testFeeChargesChargedSetters() {
+        testBigDecimalSetter(installment::setFeeChargesCharged, 
installment::getFeeChargesCharged);
+    }
+
+    @Test
+    void testFeeChargesPaidSetters() {
+        testBigDecimalSetter(installment::setFeeChargesPaid, 
installment::getFeeChargesPaid);
+    }
+
+    @Test
+    void testFeeChargesWrittenOffSetters() {
+        testBigDecimalSetter(installment::setFeeChargesWrittenOff, 
installment::getFeeChargesWrittenOff);
+    }
+
+    @Test
+    void testFeeChargesWaivedSetters() {
+        testBigDecimalSetter(installment::setFeeChargesWaived, 
installment::getFeeChargesWaived);
+    }
+
+    @Test
+    void testFeeAccruedSetters() {
+        testBigDecimalSetter(installment::setFeeAccrued, 
installment::getFeeAccrued);
+    }
+
+    @Test
+    void testPenaltyChargesSetters() {
+        testBigDecimalSetter(installment::setPenaltyCharges, 
installment::getPenaltyCharges);
+    }
+
+    @Test
+    void testPenaltyChargesPaidSetters() {
+        testBigDecimalSetter(installment::setPenaltyChargesPaid, 
installment::getPenaltyChargesPaid);
+    }
+
+    @Test
+    void testPenaltyChargesWrittenOffSetters() {
+        testBigDecimalSetter(installment::setPenaltyChargesWrittenOff, 
installment::getPenaltyChargesWrittenOff);
+    }
+
+    @Test
+    void testPenaltyChargesWaivedSetters() {
+        testBigDecimalSetter(installment::setPenaltyChargesWaived, 
installment::getPenaltyChargesWaived);
+    }
+
+    @Test
+    void testPenaltyAccruedSetters() {
+        testBigDecimalSetter(installment::setPenaltyAccrued, 
installment::getPenaltyAccrued);
+    }
+
+    @Test
+    void testTotalPaidInAdvanceSetters() {
+        testBigDecimalSetter(installment::setTotalPaidInAdvance, 
installment::getTotalPaidInAdvance);
+    }
+
+    @Test
+    void testTotalPaidLateSetters() {
+        testBigDecimalSetter(installment::setTotalPaidLate, 
installment::getTotalPaidLate);
+    }
+
+    @Test
+    void testCreditedAmountsSetters() {
+        testBigDecimalSetter(installment::setCreditedPrincipal, 
installment::getCreditedPrincipal);
+        testBigDecimalSetter(installment::setCreditedInterest, 
installment::getCreditedInterest);
+        testBigDecimalSetter(installment::setCreditedFee, 
installment::getCreditedFee);
+        testBigDecimalSetter(installment::setCreditedPenalty, 
installment::getCreditedPenalty);
+    }
+
+    @Test
+    void testPrecisionAndScale() {
+        final BigDecimal value = new BigDecimal("123456789.123456789");
+
+        // Test that value is properly scaled
+        installment.setPrincipal(value);
+        assertEquals(SCALE, installment.getPrincipal().scale());
+
+        // Test that value is properly rounded
+        final BigDecimal expected = new BigDecimal("123456789.123457");
+        assertEquals(expected, installment.getPrincipal());
+    }
+
+    private void testBigDecimalSetter(final Consumer<BigDecimal> setter, final 
Supplier<BigDecimal> getter) {
+        // Test non-zero value
+        final BigDecimal value = new BigDecimal("123.456789");
+        setter.accept(value);
+        assertEquals(value.setScale(SCALE, RoundingMode.HALF_EVEN), 
getter.get());
+
+        // Test zero value
+        setter.accept(BigDecimal.ZERO);
+        assertNull(getter.get());
+
+        // Test null value
+        setter.accept(null);
+        assertNull(getter.get());
+    }
+}
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
index 7524a9248b..39ee62f061 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/deliquency/DelinquencyWritePlatformServiceRangeChangeEventTest.java
@@ -26,11 +26,13 @@ import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.ArrayList;
@@ -50,6 +52,7 @@ import 
org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanAccountDelinquencyPauseChangedBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
 import 
org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
 import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
 import 
org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappingsRepository;
@@ -79,19 +82,24 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleIns
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
 import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
 public class DelinquencyWritePlatformServiceRangeChangeEventTest {
 
+    private static final MockedStatic<MoneyHelper> MONEY_HELPER = 
mockStatic(MoneyHelper.class);
+
     @Mock
     private DelinquencyBucketParseAndValidator dataValidatorBucket;
     @Mock
@@ -127,6 +135,11 @@ public class 
DelinquencyWritePlatformServiceRangeChangeEventTest {
 
     private DelinquencyWritePlatformServiceImpl underTest;
 
+    @BeforeAll
+    static void init() {
+        
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+    }
+
     @BeforeEach
     public void setUp() {
         ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, 
"default", "Default", "Asia/Kolkata", null));
@@ -143,6 +156,11 @@ public class 
DelinquencyWritePlatformServiceRangeChangeEventTest {
                 delinquencyWritePlatformServiceHelper);
     }
 
+    @AfterAll
+    static void cleanUp() {
+        MONEY_HELPER.close();
+    }
+
     @AfterEach
     public void tearDown() {
         ThreadLocalContextUtil.reset();
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
index 9518aea7f0..c247950a83 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java
@@ -5348,8 +5348,8 @@ public class ClientLoanIntegrationTest extends 
BaseLoanIntegrationTest {
 
             ArrayList<HashMap> loanSchedule = 
LOAN_TRANSACTION_HELPER.getLoanRepaymentSchedule(REQUEST_SPEC, RESPONSE_SPEC, 
loanID);
             assertEquals(2, loanSchedule.size());
-            assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
-            assertEquals(0.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
+            assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
+            assertEquals(0, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
             assertEquals(1000.0f, 
loanSchedule.get(1).get("totalDueForPeriod"));
             assertEquals(1000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
             LocalDate targetDate = LocalDate.of(2022, 9, 7);
@@ -5944,10 +5944,10 @@ public class ClientLoanIntegrationTest extends 
BaseLoanIntegrationTest {
 
         ArrayList<HashMap> loanSchedule = 
LOAN_TRANSACTION_HELPER.getLoanRepaymentSchedule(REQUEST_SPEC, RESPONSE_SPEC, 
loanID);
         assertEquals(2, loanSchedule.size());
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
-        assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
-        assertEquals(0.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
         assertEquals(1000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(1000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
         LocalDate targetDate = LocalDate.of(2022, 9, 7);
@@ -6013,11 +6013,11 @@ public class ClientLoanIntegrationTest extends 
BaseLoanIntegrationTest {
         assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
         assertEquals(0, loanSchedule.get(1).get("feeChargesWaived"));
         assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
-        assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesWaived"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesWaived"));
         assertEquals(10.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
         assertEquals(1010.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(1010.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
-        assertEquals(0.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
+        assertEquals(0, loanSchedule.get(1).get("totalWaivedForPeriod"));
 
         loanSummary = LOAN_TRANSACTION_HELPER.getLoanDetail(REQUEST_SPEC, 
RESPONSE_SPEC, loanID, "summary");
         assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
@@ -6146,13 +6146,13 @@ public class ClientLoanIntegrationTest extends 
BaseLoanIntegrationTest {
         assertEquals(2, loanSchedule.size());
         assertEquals(10.0f, loanSchedule.get(1).get("feeChargesDue"));
         assertEquals(10.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesWaived"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesWaived"));
         assertEquals(10.0f, loanSchedule.get(1).get("penaltyChargesDue"));
         assertEquals(0, loanSchedule.get(1).get("penaltyChargesWaived"));
         assertEquals(10.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
         assertEquals(1020.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(1020.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
-        assertEquals(0.0f, loanSchedule.get(1).get("totalWaivedForPeriod"));
+        assertEquals(0, loanSchedule.get(1).get("totalWaivedForPeriod"));
 
         loanSummary = LOAN_TRANSACTION_HELPER.getLoanDetail(REQUEST_SPEC, 
RESPONSE_SPEC, loanID, "summary");
         assertEquals(10.0f, loanSummary.get("penaltyChargesCharged"));
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
index 6b8b286cc2..bb7b14e3a4 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
@@ -173,10 +173,10 @@ public class LoanSpecificDueDateChargeAfterMaturityTest 
extends BaseLoanIntegrat
 
         ArrayList<HashMap> loanSchedule = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, 
loanID);
         assertEquals(2, loanSchedule.size());
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
-        assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
-        assertEquals(0.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
         assertEquals(10000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(10000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
         targetDate = LocalDate.of(2011, 4, 5);
@@ -306,10 +306,10 @@ public class LoanSpecificDueDateChargeAfterMaturityTest 
extends BaseLoanIntegrat
 
         ArrayList<HashMap> loanSchedule = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, 
loanID);
         assertEquals(2, loanSchedule.size());
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
-        assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
-        assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
-        assertEquals(0.0f, 
loanSchedule.get(1).get("penaltyChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
+        assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
         assertEquals(10000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(10000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
 
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
index 3045df0243..4bc891fe9b 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java
@@ -844,7 +844,7 @@ public class SchedulerJobsTestResults extends 
IntegrationTest {
         ArrayList<HashMap> repaymentScheduleDataAfter = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
                 loanID);
 
-        Assertions.assertEquals(0.0f, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
+        Assertions.assertEquals(0, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
                 "Verifying From Penalty Charges due fot first Repayment after 
Successful completion of Scheduler Job");
 
     }
@@ -1085,7 +1085,7 @@ public class SchedulerJobsTestResults extends 
IntegrationTest {
             this.schedulerJobHelper.executeAndAwaitJob(jobName);
             List<HashMap> repaymentScheduleDataAfter = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
                     loanID);
-            Assertions.assertEquals(0.0f, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
+            Assertions.assertEquals(0, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
                     "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
 
             LocalDate lastBusinessDateBeforeFastForward = LocalDate.of(2019, 
4, 2);
@@ -1153,7 +1153,7 @@ public class SchedulerJobsTestResults extends 
IntegrationTest {
             this.schedulerJobHelper.executeAndAwaitJob(jobName);
             List<HashMap> repaymentScheduleDataAfter = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
                     loanID2);
-            Assertions.assertEquals(0.0f, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
+            Assertions.assertEquals(0, 
repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
                     "Verifying From Penalty Charges due fot first Repayment 
after Successful completion of Scheduler Job");
 
             BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, 
BusinessDateType.COB_DATE, LocalDate.of(2020, 5, 3));

Reply via email to