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 071592eceb FINERACT-2220: Use stored 
ProgressiveLoanInterestScheduleModel for Periodic Accrual Calculation
071592eceb is described below

commit 071592eceb4a920c0a198d3cd7d4b0dd9c8c5824
Author: Soma Sörös <[email protected]>
AuthorDate: Thu Apr 24 15:30:48 2025 +0200

    FINERACT-2220: Use stored ProgressiveLoanInterestScheduleModel for Periodic 
Accrual Calculation
---
 .../service/LoanDownPaymentHandlerServiceImpl.java |  5 +++
 ...EmbeddableProgressiveLoanScheduleGenerator.java | 39 +++++++++++++++++++++-
 .../domain/ProgressiveLoanScheduleGenerator.java   | 16 +++++++--
 .../domain/LoanScheduleGeneratorTest.java          |  9 +++--
 4 files changed, 63 insertions(+), 6 deletions(-)

diff --git 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
index 8b984321bb..9b0a1d8304 100644
--- 
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
+++ 
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanDownPaymentHandlerServiceImpl.java
@@ -131,6 +131,11 @@ public class LoanDownPaymentHandlerServiceImpl implements 
LoanDownPaymentHandler
                 || 
!DateUtils.isEqualBusinessDate(loanTransaction.getTransactionDate()) || 
currentInstallment == null
                 || 
!currentInstallment.getTotalOutstanding(loan.getCurrency()).isEqualTo(loanTransaction.getAmount(loan.getCurrency()));
 
+        // TODO FINERACT-2220 fix processLatestTransaction to save model.
+        if (loan.isProgressiveSchedule() && loan.isInterestBearing()) {
+            reprocess = true;
+        }
+
         if (isTransactionChronologicallyLatest && adjustedTransaction == null
                 && (!reprocess || 
!loan.isInterestBearingAndInterestRecalculationEnabled()) && 
!loan.isForeclosure()) {
             
loanTransactionProcessingService.processLatestTransaction(loan.getTransactionProcessingStrategyCode(),
 loanTransaction,
diff --git 
a/fineract-progressive-loan-embeddable-schedule-generator/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGenerator.java
 
b/fineract-progressive-loan-embeddable-schedule-generator/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGenerator.java
index 1b77749768..1c3a19bbd4 100644
--- 
a/fineract-progressive-loan-embeddable-schedule-generator/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGenerator.java
+++ 
b/fineract-progressive-loan-embeddable-schedule-generator/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/EmbeddableProgressiveLoanScheduleGenerator.java
@@ -19,9 +19,16 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
 
 import java.math.MathContext;
+import java.time.LocalDate;
+import java.util.Optional;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.ProgressiveLoanModel;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlan;
+import 
org.apache.fineract.portfolio.loanaccount.service.InterestScheduleModelRepositoryWrapper;
 import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
 import org.apache.fineract.portfolio.loanproduct.calc.ProgressiveEMICalculator;
+import 
org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
+import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
 
 @SuppressWarnings("unused")
 public class EmbeddableProgressiveLoanScheduleGenerator {
@@ -33,10 +40,40 @@ public class EmbeddableProgressiveLoanScheduleGenerator {
     public EmbeddableProgressiveLoanScheduleGenerator() {
         this.emiCalculator = new ProgressiveEMICalculator();
         this.scheduledDateGenerator = new DefaultScheduledDateGenerator();
-        this.scheduleGenerator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator);
+        this.scheduleGenerator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator,
+                new NoopInterestScheduleModelRepositoryWrapper());
     }
 
     public LoanSchedulePlan generate(final MathContext mc, final 
LoanRepaymentScheduleModelData modelData) {
         return scheduleGenerator.generate(mc, modelData);
     }
+
+    private static final class NoopInterestScheduleModelRepositoryWrapper 
implements InterestScheduleModelRepositoryWrapper {
+
+        @Override
+        public Optional<ProgressiveLoanModel> findOneByLoanId(Long loanId) {
+            return Optional.empty();
+        }
+
+        @Override
+        public Optional<ProgressiveLoanInterestScheduleModel> 
extractModel(Optional<ProgressiveLoanModel> progressiveLoanModel) {
+            return Optional.empty();
+        }
+
+        @Override
+        public String writeInterestScheduleModel(Loan loan, 
ProgressiveLoanInterestScheduleModel model) {
+            return "";
+        }
+
+        @Override
+        public Optional<ProgressiveLoanInterestScheduleModel> 
readProgressiveLoanInterestScheduleModel(Long loanId,
+                LoanProductMinimumRepaymentScheduleRelatedDetail detail, 
Integer installmentAmountInMultipliesOf) {
+            return Optional.empty();
+        }
+
+        @Override
+        public Optional<ProgressiveLoanInterestScheduleModel> 
getSavedModel(Loan loan, LocalDate businessDate) {
+            return Optional.empty();
+        }
+    }
 }
diff --git 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
index caa7ea5edc..5e3f85ffd9 100644
--- 
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
+++ 
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java
@@ -29,6 +29,7 @@ import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import org.apache.fineract.infrastructure.core.service.MathUtil;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
@@ -48,6 +49,7 @@ import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleM
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleParams;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlan;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
+import 
org.apache.fineract.portfolio.loanaccount.service.InterestScheduleModelRepositoryWrapper;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionProcessingService;
 import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
 import org.apache.fineract.portfolio.loanproduct.calc.data.OutstandingDetails;
@@ -61,12 +63,15 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
 
     private final ScheduledDateGenerator scheduledDateGenerator;
     private final EMICalculator emiCalculator;
+    private final InterestScheduleModelRepositoryWrapper 
interestScheduleModelRepositoryWrapper;
 
     private LoanTransactionProcessingService loanTransactionProcessingService;
 
-    public ProgressiveLoanScheduleGenerator(ScheduledDateGenerator 
scheduledDateGenerator, EMICalculator emiCalculator) {
+    public ProgressiveLoanScheduleGenerator(ScheduledDateGenerator 
scheduledDateGenerator, EMICalculator emiCalculator,
+            InterestScheduleModelRepositoryWrapper 
interestScheduleModelRepositoryWrapper) {
         this.scheduledDateGenerator = scheduledDateGenerator;
         this.emiCalculator = emiCalculator;
+        this.interestScheduleModelRepositoryWrapper = 
interestScheduleModelRepositoryWrapper;
     }
 
     @Autowired(required = false)
@@ -187,7 +192,10 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
             case NONE -> throw new IllegalStateException("Unexpected 
PreClosureInterestCalculationStrategy: NONE");
         };
 
-        ProgressiveLoanInterestScheduleModel model = 
processor.calculateInterestScheduleModel(loan.getId(), onDate);
+        Optional<ProgressiveLoanInterestScheduleModel> savedModel = 
interestScheduleModelRepositoryWrapper.getSavedModel(loan,
+                transactionDate);
+        ProgressiveLoanInterestScheduleModel model = savedModel
+                .orElseGet(() -> 
processor.calculateInterestScheduleModel(loan.getId(), onDate));
         OutstandingDetails outstandingAmounts = 
emiCalculator.getOutstandingAmountsTillDate(model, transactionDate);
         // TODO: We should add all the past due outstanding amounts as well
         OutstandingAmountsDTO result = new OutstandingAmountsDTO(currency) //
@@ -228,7 +236,9 @@ public class ProgressiveLoanScheduleGenerator implements 
LoanScheduleGenerator {
         if (installment.isAdditional() || installment.isDownPayment() || 
installment.isReAged()) {
             return Money.zero(loan.getCurrency());
         }
-        ProgressiveLoanInterestScheduleModel model = 
processor.calculateInterestScheduleModel(loan.getId(), targetDate);
+        Optional<ProgressiveLoanInterestScheduleModel> savedModel = 
interestScheduleModelRepositoryWrapper.getSavedModel(loan, targetDate);
+        ProgressiveLoanInterestScheduleModel model = savedModel
+                .orElseGet(() -> 
processor.calculateInterestScheduleModel(loan.getId(), targetDate));
         return emiCalculator.getPeriodInterestTillDate(model, 
installment.getDueDate(), targetDate, false);
     }
 
diff --git 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
index e56927d6b8..552c52c80d 100644
--- 
a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
+++ 
b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGeneratorTest.java
@@ -33,6 +33,7 @@ import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleP
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanDisbursementPeriod;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanDownPaymentPeriod;
 import 
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePlanRepaymentPeriod;
+import 
org.apache.fineract.portfolio.loanaccount.service.InterestScheduleModelRepositoryWrapper;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanTransactionProcessingService;
 import org.apache.fineract.portfolio.loanproduct.calc.ProgressiveEMICalculator;
 import org.junit.jupiter.api.Test;
@@ -55,6 +56,8 @@ class LoanScheduleGeneratorTest {
     private static final MathContext mc = new MathContext(12, 
RoundingMode.HALF_EVEN);
     private static final BigDecimal DOWN_PAYMENT_PORTION = 
BigDecimal.valueOf(25);
     private static final LoanTransactionProcessingService 
loanTransactionProcessingService = mock(LoanTransactionProcessingService.class);
+    private static final InterestScheduleModelRepositoryWrapper 
interestScheduleModelRepositoryWrapperMock = mock(
+            InterestScheduleModelRepositoryWrapper.class);
 
     @Test
     void testGenerateLoanSchedule() {
@@ -63,7 +66,8 @@ class LoanScheduleGeneratorTest {
                 NOMINAL_INTEREST_RATE, false, DaysInMonthType.DAYS_30, 
DaysInYearType.DAYS_360, null, null, null, false, null);
 
         ScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
-        ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator);
+        ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator,
+                interestScheduleModelRepositoryWrapperMock);
         
generator.setLoanTransactionProcessingService(loanTransactionProcessingService);
 
         LoanSchedulePlan loanSchedule = generator.generate(mc, modelData);
@@ -100,7 +104,8 @@ class LoanScheduleGeneratorTest {
                 null);
 
         ScheduledDateGenerator scheduledDateGenerator = new 
DefaultScheduledDateGenerator();
-        ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator);
+        ProgressiveLoanScheduleGenerator generator = new 
ProgressiveLoanScheduleGenerator(scheduledDateGenerator, emiCalculator,
+                interestScheduleModelRepositoryWrapperMock);
         
generator.setLoanTransactionProcessingService(loanTransactionProcessingService);
 
         LoanSchedulePlan loanSchedule = generator.generate(mc, modelData);

Reply via email to