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 06edb4c7d FINERACT-2081: Loan account summary with Unpaid Payable 
Interest
06edb4c7d is described below

commit 06edb4c7d93959ac54f66a5dbfa49c0c30b0cf94
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Thu Aug 1 00:10:45 2024 -0600

    FINERACT-2081: Loan account summary with Unpaid Payable Interest
---
 .../src/main/avro/loan/v1/LoanSummaryDataV1.avsc   |   4 +-
 .../loanaccount/data/LoanSummaryData.java          |  99 ++++++-------
 .../loanschedule/data/LoanSchedulePeriodData.java  |  13 ++
 .../loanaccount/api/LoansApiResourceSwagger.java   |   4 +-
 ...PaymentAllocationLoanRepaymentScheduleTest.java | 161 +++++++++++++++++----
 5 files changed, 190 insertions(+), 91 deletions(-)

diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanSummaryDataV1.avsc 
b/fineract-avro-schemas/src/main/avro/loan/v1/LoanSummaryDataV1.avsc
index 5e74118cf..9ad816a55 100644
--- a/fineract-avro-schemas/src/main/avro/loan/v1/LoanSummaryDataV1.avsc
+++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanSummaryDataV1.avsc
@@ -437,7 +437,7 @@
         },
         {
             "default": null,
-            "name": "totalUnpaidAccruedDueInterest",
+            "name": "totalUnpaidPayableDueInterest",
             "type": [
                 "null",
                 "bigdecimal"
@@ -445,7 +445,7 @@
         },
         {
             "default": null,
-            "name": "totalUnpaidAccruedNotDueInterest",
+            "name": "totalUnpaidPayableNotDueInterest",
             "type": [
                 "null",
                 "bigdecimal"
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
index af9e1b9f1..9adb59de0 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanSummaryData.java
@@ -26,8 +26,9 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.experimental.Accessors;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
-import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
@@ -100,11 +101,12 @@ public class LoanSummaryData {
     private final Long chargeOffReasonId;
     private final String chargeOffReason;
 
-    private BigDecimal totalUnpaidAccruedDueInterest;
-    private BigDecimal totalUnpaidAccruedNotDueInterest;
+    private BigDecimal totalUnpaidPayableDueInterest;
+    private BigDecimal totalUnpaidPayableNotDueInterest;
 
     public static LoanSummaryData withTransactionAmountsSummary(final 
LoanSummaryData defaultSummaryData,
             final LoanScheduleData repaymentSchedule, final 
Collection<LoanTransactionBalance> loanTransactionBalances) {
+        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
 
         BigDecimal totalMerchantRefund = BigDecimal.ZERO;
         BigDecimal totalMerchantRefundReversed = BigDecimal.ZERO;
@@ -121,8 +123,8 @@ public class LoanSummaryData {
         BigDecimal totalRepaymentTransactionReversed = BigDecimal.ZERO;
         BigDecimal totalInterestPaymentWaiver = BigDecimal.ZERO;
         BigDecimal totalInterestRefund = BigDecimal.ZERO;
-        BigDecimal totalUnpaidAccruedDueInterest = BigDecimal.ZERO;
-        BigDecimal totalUnpaidAccruedNotDueInterest = BigDecimal.ZERO;
+        BigDecimal totalUnpaidPayableDueInterest = BigDecimal.ZERO;
+        BigDecimal totalUnpaidPayableNotDueInterest = BigDecimal.ZERO;
 
         totalChargeAdjustment = 
fetchLoanTransactionBalanceByType(loanTransactionBalances,
                 LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
@@ -160,25 +162,12 @@ public class LoanSummaryData {
                 LoanTransactionType.REPAYMENT.getValue());
 
         if (repaymentSchedule != null) {
-            // Accrued Due Interest on Past due installments
-            totalUnpaidAccruedDueInterest = 
computeTotalAccruedDueInterestAmount(repaymentSchedule.getPeriods());
-            if (MathUtil.isGreaterThanZero(totalUnpaidAccruedDueInterest)) {
-                totalUnpaidAccruedDueInterest = totalUnpaidAccruedDueInterest
-                        
.subtract(computeTotalInterestPaidDueAmount(repaymentSchedule.getPeriods()));
-                if (MathUtil.isLessThanZero(totalUnpaidAccruedDueInterest)) {
-                    totalUnpaidAccruedDueInterest = BigDecimal.ZERO;
-                }
-            }
+            // Outstanding Interest on Past due installments
+            totalUnpaidPayableDueInterest = 
computeTotalUnpaidPayableDueInterestAmount(repaymentSchedule.getPeriods(), 
businessDate);
 
-            // Accrued Due Interest on Actual Installment
-            totalUnpaidAccruedNotDueInterest = 
computeTotalAccruedNotDueInterestAmountOnActualPeriod(repaymentSchedule.getPeriods());
-            if (MathUtil.isGreaterThanZero(totalUnpaidAccruedNotDueInterest)) {
-                totalUnpaidAccruedNotDueInterest = 
totalUnpaidAccruedNotDueInterest
-                        
.subtract(computeTotalInterestPaidNotDueAmountOnActualPeriod(repaymentSchedule.getPeriods()));
-                if (MathUtil.isLessThanZero(totalUnpaidAccruedNotDueInterest)) 
{
-                    totalUnpaidAccruedNotDueInterest = BigDecimal.ZERO;
-                }
-            }
+            // Accumulated daily interest of the current Installment period
+            totalUnpaidPayableNotDueInterest = 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(repaymentSchedule.getPeriods(),
+                    businessDate, defaultSummaryData.currency);
         }
 
         return 
LoanSummaryData.builder().currency(defaultSummaryData.currency).principalDisbursed(defaultSummaryData.principalDisbursed)
@@ -212,8 +201,8 @@ public class LoanSummaryData {
                 
.totalChargeback(totalChargeback).totalCreditBalanceRefund(totalCreditBalanceRefund)
                 
.totalCreditBalanceRefundReversed(totalCreditBalanceRefundReversed).totalRepaymentTransaction(totalRepaymentTransaction)
                 
.totalRepaymentTransactionReversed(totalRepaymentTransactionReversed).totalInterestPaymentWaiver(totalInterestPaymentWaiver)
-                .totalUnpaidAccruedDueInterest(totalUnpaidAccruedDueInterest)
-                
.totalUnpaidAccruedNotDueInterest(totalUnpaidAccruedNotDueInterest).totalInterestRefund(totalInterestRefund).build();
+                .totalUnpaidPayableDueInterest(totalUnpaidPayableDueInterest)
+                
.totalUnpaidPayableNotDueInterest(totalUnpaidPayableNotDueInterest).totalInterestRefund(totalInterestRefund).build();
     }
 
     private static BigDecimal fetchLoanTransactionBalanceByType(final 
Collection<LoanTransactionBalance> loanTransactionBalances,
@@ -236,44 +225,42 @@ public class LoanSummaryData {
         return LoanSummaryData.builder().currency(currencyData).build();
     }
 
-    private static BigDecimal 
computeTotalAccruedDueInterestAmount(Collection<LoanSchedulePeriodData> 
periods) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-        return periods.stream().filter(period -> 
!period.getDownPaymentPeriod() && businessDate.isAfter(period.getDueDate()))
-                .map(period -> 
period.getTotalAccruedInterest()).reduce(BigDecimal.ZERO, BigDecimal::add);
+    private static BigDecimal 
computeTotalUnpaidPayableDueInterestAmount(Collection<LoanSchedulePeriodData> 
periods,
+            final LocalDate businessDate) {
+        return periods.stream().filter(period -> 
!period.getDownPaymentPeriod() && businessDate.compareTo(period.getDueDate()) 
>= 0)
+                .map(period -> 
period.getInterestOutstanding()).reduce(BigDecimal.ZERO, BigDecimal::add);
     }
 
-    private static BigDecimal 
computeTotalInterestPaidDueAmount(Collection<LoanSchedulePeriodData> periods) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-        return periods.stream().filter(period -> 
!period.getDownPaymentPeriod() && businessDate.isAfter(period.getDueDate()))
-                .map(period -> 
period.getInterestPaid()).reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
+    private static BigDecimal 
computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(final 
Collection<LoanSchedulePeriodData> periods,
+            final LocalDate businessDate, final CurrencyData currency) {
+        // Find the current Period (If exists one) based on the Business date
+        final Optional<LoanSchedulePeriodData> optCurrentPeriod = 
periods.stream()
+                .filter(period -> !period.getDownPaymentPeriod() && 
period.isActualPeriodForNotDuePayableCalculation(businessDate))
+                .findFirst();
 
-    private static BigDecimal 
computeTotalAccruedNotDueInterestAmountOnActualPeriod(Collection<LoanSchedulePeriodData>
 periods) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-        return periods.stream()
-                .filter(period -> !period.getDownPaymentPeriod() && 
isActualPeriod(period) && businessDate.isBefore(period.getDueDate()))
-                .map(period -> 
period.getTotalAccruedInterest()).reduce(BigDecimal.ZERO, BigDecimal::add);
-    }
+        if (optCurrentPeriod.isPresent()) {
+            final LoanSchedulePeriodData currentPeriod = 
optCurrentPeriod.get();
+            final long remainingDays = currentPeriod.getDaysInPeriod()
+                    - 
DateUtils.getDifferenceInDays(currentPeriod.getFromDate(), businessDate);
 
-    private static BigDecimal 
computeTotalInterestPaidNotDueAmountOnActualPeriod(Collection<LoanSchedulePeriodData>
 periods) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-        return periods.stream()
-                .filter(period -> !period.getDownPaymentPeriod() && 
isActualPeriod(period) && businessDate.isBefore(period.getDueDate()))
-                .map(period -> 
period.getInterestPaid()).reduce(BigDecimal.ZERO, BigDecimal::add);
+            return computeAccruedInterestTillDay(currentPeriod, remainingDays, 
currency);
+        }
+        // Default value equal to Zero
+        return BigDecimal.ZERO;
     }
 
-    private static boolean isActualPeriod(LoanSchedulePeriodData period) {
-        final LocalDate businessDate = DateUtils.getBusinessLocalDate();
-        boolean actualPeriod = false;
-        if (period.getPeriod() != null) {
-            if (period.getPeriod() == 1) {
-                actualPeriod = ((businessDate.isEqual(period.getFromDate()) || 
businessDate.isAfter(period.getFromDate()))
-                        && businessDate.isBefore(period.getDueDate()));
-            } else {
-                actualPeriod = (businessDate.isAfter(period.getFromDate()) && 
businessDate.isBefore(period.getDueDate()));
-            }
+    private static BigDecimal computeAccruedInterestTillDay(final 
LoanSchedulePeriodData period, final long untilDay,
+            final CurrencyData currency) {
+        Integer remainingDays = period.getDaysInPeriod();
+        BigDecimal totalAccruedInterest = BigDecimal.ZERO;
+        while (remainingDays > untilDay) {
+            final BigDecimal accruedInterest = 
period.getInterestDue().subtract(totalAccruedInterest)
+                    .divide(BigDecimal.valueOf(remainingDays), 
MoneyHelper.getMathContext());
+            totalAccruedInterest = totalAccruedInterest.add(accruedInterest);
+            remainingDays--;
         }
 
-        return actualPeriod;
+        return Money.of(currency, totalAccruedInterest).getAmount();
     }
+
 }
diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
index fcf050ee7..22a3eb173 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/data/LoanSchedulePeriodData.java
@@ -402,6 +402,19 @@ public final class LoanSchedulePeriodData {
         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() {
         return defaultToZeroIfNull(this.principalDisbursed);
     }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
index 44dbe6621..91ba44c03 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java
@@ -640,9 +640,9 @@ final class LoansApiResourceSwagger {
             @Schema(example = "0.000000")
             public Double totalRepaymentTransactionReversed;
             @Schema(example = "0.000000")
-            public BigDecimal totalUnpaidAccruedDueInterest;
+            public BigDecimal totalUnpaidPayableDueInterest;
             @Schema(example = "0.000000")
-            public BigDecimal totalUnpaidAccruedNotDueInterest;
+            public BigDecimal totalUnpaidPayableNotDueInterest;
             @Schema(example = "0.000000")
             public BigDecimal totalInterestRefund;
             public Set<GetLoansLoanIdOverdueCharges> overdueCharges;
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
index f94bca231..f12f9fa93 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java
@@ -4720,8 +4720,8 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
 
             // After Disbursement we are expecting no Accrual transactions
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
         // Not Due yet
@@ -4732,14 +4732,14 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("30 
January 2024");
 
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(new BigDecimal("0.97"), 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(new BigDecimal("0.97"), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
 
             // Partial interest repayment
             addRepaymentForLoan(createdLoanId.get(), 20.50, "30 January 2024");
             loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(new BigDecimal("0.05"), 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(new BigDecimal("0.97"), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
         // Not Due and Due Interest
@@ -4749,8 +4749,8 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("20 
February 2024");
 
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(new BigDecimal("0.12"), 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(new BigDecimal("0.52"), 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(new BigDecimal("0.12"), 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(new BigDecimal("0.52"), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
     }
 
@@ -4767,11 +4767,12 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
         runAt(operationDate, () -> {
             Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
             PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
-                    
.interestRatePerPeriod(12.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
-                    
.daysInMonthType(DaysInMonthType.ACTUAL.getValue()).daysInYearType(DaysInYearType.DAYS_365.getValue())
-                    .numberOfRepayments(4)//
-                    .repaymentEvery(5)//
-                    .repaymentFrequencyType(0L)//
+                    
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
+                    
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL.getValue())
+                    
.daysInYearType(DaysInYearType.DAYS_360.getValue()).numberOfRepayments(4)//
+                    .maxInterestRatePerPeriod((double) 110)//
+                    .repaymentEvery(1)//
+                    .repaymentFrequencyType(1L)//
                     .allowPartialPeriodInterestCalcualtion(false)//
                     .multiDisburseLoan(false)//
                     .disallowExpectedDisbursements(null)//
@@ -4781,7 +4782,8 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
                     .installmentAmountInMultiplesOf(null)//
             ;//
             PostLoanProductsResponse loanProductResponse = 
loanProductHelper.createLoanProduct(product);
-            PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductResponse.getResourceId(), operationDate, 1000.0, 4);
+            PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductResponse.getResourceId(), operationDate, 1000.0, 4)
+                    .interestRatePerPeriod(BigDecimal.valueOf(108.0));
 
             applicationRequest = 
applicationRequest.interestCalculationPeriodType(DAYS)
                     
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
@@ -4796,12 +4798,13 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             loanTransactionHelper.disburseLoan(loanResponse.getLoanId(), new 
PostLoansLoanIdRequest().actualDisbursementDate(operationDate)
                     
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
 
-            // After Disbursement we are expecting no Accrual transactions
+            // After Disbursement we are expecting amount in Zero (first day)
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
+        // First day on First Period, then TotalUnpaidPayableDueInterest = 0 
and TotalUnpaidPayableNotDueInterest = 3
         runAt("2 January 2024", () -> {
             // Generate the Accruals
             final PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec,
@@ -4809,30 +4812,126 @@ public class 
AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
             periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("2 
January 2024");
 
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(3.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
+        // Second day on First Period, then TotalUnpaidPayableDueInterest = 0 
and TotalUnpaidPayableNotDueInterest = 6
         runAt("3 January 2024", () -> {
-            // Add a Charge
-            addCharge(createdLoanId.get(), false, 10, "6 January 2024");
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(6.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
 
-            final PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec,
-                    responseSpec);
-            periodicAccrualAccountingHelper.runPeriodicAccrualAccounting("2 
January 2024");
+        // Third day on First Period, then TotalUnpaidPayableDueInterest = 0 
and TotalUnpaidPayableNotDueInterest = 9
+        runAt("4 January 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(9.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
 
+        // Fourth day on First Period, then TotalUnpaidPayableDueInterest = 0 
and TotalUnpaidPayableNotDueInterest = 12
+        runAt("5 January 2024", () -> {
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(12.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
 
-        // Add Payment higher than accrued amount
-        runAt("4 January 2024", () -> {
-            addRepaymentForLoan(createdLoanId.get(), 150.0, "4 January 2024");
+        // Last day on First Period, then TotalUnpaidPayableDueInterest = 90 
and TotalUnpaidPayableNotDueInterest = 0
+        runAt("31 January 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(90.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO.stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // First day on Second Period, then TotalUnpaidPayableDueInterest = 90 
and TotalUnpaidPayableNotDueInterest =
+        // 2.34
+        runAt("1 February 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(90.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(2.34), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Second day on Second Period, then TotalUnpaidPayableDueInterest = 
90 and TotalUnpaidPayableNotDueInterest =
+        // 4.69
+        runAt("2 February 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(90.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(4.69), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Third day on Second Period, then TotalUnpaidPayableDueInterest = 90 
and TotalUnpaidPayableNotDueInterest =
+        // 7.03
+        runAt("3 February 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(90.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(7.03), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // N day on Second Period, then TotalUnpaidPayableDueInterest = 90 and 
TotalUnpaidPayableNotDueInterest = 21.096
+        runAt("10 February 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(90.0).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(23.44).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // First day on Third Period, then TotalUnpaidPayableDueInterest = 90 
+ 70.32 and
+        // TotalUnpaidPayableNotDueInterest = 0
+        runAt("1 March 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(160.32).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Second day on Third Period, then TotalUnpaidPayableDueInterest = 90 
+ 70.32 and
+        // TotalUnpaidPayableNotDueInterest = 1.63
+        runAt("2 March 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(160.32).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(1.63), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Third day on Third Period, then TotalUnpaidPayableDueInterest = 90 
+ 70.32 and
+        // TotalUnpaidPayableNotDueInterest = 3.26
+        runAt("3 March 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(160.32).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(3.26), 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Last day on Third Period, then TotalUnpaidPayableDueInterest = 90 + 
70.32 + 48.87 and
+        // TotalUnpaidPayableNotDueInterest = 0
+        runAt("31 March 2024", () -> {
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
+            assertEquals(BigDecimal.valueOf(209.19).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
+        });
+
+        // Add Payment to pay the First installment, then 
TotalUnpaidPayableDueInterest = 70.32 and
+        // TotalUnpaidPayableNotDueInterest = 16.29
+        runAt("11 March 2024", () -> {
+            addRepaymentForLoan(createdLoanId.get(), 340.00, "11 March 2024");
 
             GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(createdLoanId.get());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedDueInterest().stripTrailingZeros());
-            assertEquals(BigDecimal.ZERO, 
loanDetails.getSummary().getTotalUnpaidAccruedNotDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(70.32).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableDueInterest().stripTrailingZeros());
+            assertEquals(BigDecimal.valueOf(16.29).stripTrailingZeros(),
+                    
loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest().stripTrailingZeros());
         });
     }
 

Reply via email to