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 cf94eb8d8 FINERACT-1925: New repayment schedule
cf94eb8d8 is described below

commit cf94eb8d8138e69e8aea3642847ab97b3c4e9cbf
Author: Adam Saghy <[email protected]>
AuthorDate: Wed May 3 12:41:52 2023 +0200

    FINERACT-1925: New repayment schedule
---
 .../core/config/FineractProperties.java            |   1 +
 ...LoanRepaymentScheduleTransactionProcessor.java} |   3 +-
 ...LoanRepaymentScheduleTransactionProcessor.java} |  96 ++-
 ...mentScheduleTransactionProcessorCondition.java} |   2 +-
 ...mentScheduleTransactionProcessorCondition.java} |   4 +-
 .../starter/LoanAccountAutoStarter.java            |  15 +-
 .../src/main/resources/application.properties      |   1 +
 .../db/changelog/tenant/changelog-tenant.xml       |   1 +
 .../tenant/parts/0106_new_repayment_strategy.xml   |  42 ++
 .../src/test/resources/application-test.properties |   1 +
 ...DueDateRespectiveLoanRepaymentScheduleTest.java | 784 ++++++++++++++++++++-
 .../common/loans/LoanApplicationTestBuilder.java   |   3 +-
 .../common/loans/LoanProductTestBuilder.java       |   4 +-
 13 files changed, 918 insertions(+), 39 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index 231a93632..2a38776f0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -326,6 +326,7 @@ public class FineractProperties {
         private FineractTransactionProcessorItemProperties 
principalInterestPenaltiesFees;
         private FineractTransactionProcessorItemProperties rbiIndia;
         private FineractTransactionProcessorItemProperties 
duePenaltyFeeInterestPrincipalInAdvancePrincipalPenaltyFeeInterest;
+        private FineractTransactionProcessorItemProperties 
duePenaltyInterestPrincipalFeeInAdvancePenaltyInterestPrincipalFee;
         private boolean errorNotFoundFail;
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
similarity index 98%
copy from 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
copy to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
index 4221c2202..74c338fbf 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
@@ -39,7 +39,8 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa
  * Due/late principal In advance principal In advance penalty In advance fee 
In advance interest
  */
 @SuppressWarnings("unused")
-public class DueDateRespectiveLoanRepaymentScheduleTransactionProcessor 
extends AbstractLoanRepaymentScheduleTransactionProcessor {
+public class 
DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor
+        extends AbstractLoanRepaymentScheduleTransactionProcessor {
 
     private static final String STRATEGY_CODE = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
similarity index 72%
rename from 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
index 4221c2202..9a4711404 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DueDateRespectiveLoanRepaymentScheduleTransactionProcessor.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
@@ -32,18 +32,19 @@ import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Abs
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 
 /**
- * `First due/late charges, interest, principal, after in advance principal, 
charges, interest` style
+ * `First due/late penalty, interest, principal, fee, after in advance 
penalty, interest, principal, fee` style
  * {@link LoanRepaymentScheduleTransactionProcessor}.
  *
- * For ALL types of transactions, pays off components in order of: Due/late 
penalty Due/late Fee Due/late interest
- * Due/late principal In advance principal In advance penalty In advance fee 
In advance interest
+ * For ALL types of transactions, pays off components in order of: Due/late 
penalty, Due/late interest, Due/late
+ * principal, Due/late fee, In advance penalty, In advance interest In advance 
principal, In advance fee
  */
 @SuppressWarnings("unused")
-public class DueDateRespectiveLoanRepaymentScheduleTransactionProcessor 
extends AbstractLoanRepaymentScheduleTransactionProcessor {
+public class 
DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor
+        extends AbstractLoanRepaymentScheduleTransactionProcessor {
 
-    private static final String STRATEGY_CODE = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
+    private static final String STRATEGY_CODE = 
"due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
 
-    private static final String STRATEGY_NAME = "Due penalty, fee, interest, 
principal, In advance principal, penalty, fee, interest";
+    private static final String STRATEGY_NAME = "Due penalty, interest, 
principal, fee, In advance penalty, interest, principal, fee";
 
     @Override
     public String getCode() {
@@ -71,9 +72,66 @@ public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessor extends
     protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final 
LoanRepaymentScheduleInstallment currentInstallment,
             final List<LoanRepaymentScheduleInstallment> installments, final 
LoanTransaction loanTransaction, final Money paymentInAdvance,
             List<LoanTransactionToRepaymentScheduleMapping> 
transactionMappings, Set<LoanCharge> charges) {
+        final LocalDate transactionDate = loanTransaction.getTransactionDate();
+        final MonetaryCurrency currency = paymentInAdvance.getCurrency();
+        Money transactionAmountRemaining = paymentInAdvance;
+        Money principalPortion = Money.zero(currency);
+        Money interestPortion = Money.zero(currency);
+        Money feeChargesPortion = Money.zero(currency);
+        Money penaltyChargesPortion = Money.zero(currency);
+
+        if (loanTransaction.isChargesWaiver()) {
+            penaltyChargesPortion = 
currentInstallment.waivePenaltyChargesComponent(transactionDate,
+                    loanTransaction.getPenaltyChargesPortion(currency));
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(penaltyChargesPortion);
+
+            feeChargesPortion = 
currentInstallment.waiveFeeChargesComponent(transactionDate,
+                    loanTransaction.getFeeChargesPortion(currency));
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(feeChargesPortion);
+
+        } else if (loanTransaction.isInterestWaiver()) {
+            interestPortion = 
currentInstallment.waiveInterestComponent(transactionDate, 
transactionAmountRemaining);
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(interestPortion);
+
+            loanTransaction.updateComponents(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
+        } else if (loanTransaction.isChargePayment()) {
+            if (loanTransaction.isPenaltyPayment()) {
+                penaltyChargesPortion = 
currentInstallment.payPenaltyChargesComponent(transactionDate, 
transactionAmountRemaining);
+                transactionAmountRemaining = 
transactionAmountRemaining.minus(penaltyChargesPortion);
+            } else {
+                feeChargesPortion = 
currentInstallment.payFeeChargesComponent(transactionDate, 
transactionAmountRemaining);
+                transactionAmountRemaining = 
transactionAmountRemaining.minus(feeChargesPortion);
+            }
+            loanTransaction.updateComponents(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
+        } else {
+            // In advance penalty, interest, principal, fee
+
+            Money subPenaltyPortion;
+            subPenaltyPortion = 
currentInstallment.payPenaltyChargesComponent(transactionDate, 
transactionAmountRemaining);
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(subPenaltyPortion);
+            penaltyChargesPortion = 
penaltyChargesPortion.add(subPenaltyPortion);
 
-        return 
handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, 
loanTransaction, paymentInAdvance, transactionMappings,
-                charges);
+            Money subInterestPortion;
+            subInterestPortion = 
currentInstallment.payInterestComponent(transactionDate, 
transactionAmountRemaining);
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(subInterestPortion);
+            interestPortion = interestPortion.add(subInterestPortion);
+
+            Money subPrincipalPortion = 
currentInstallment.payPrincipalComponent(transactionDate, 
transactionAmountRemaining);
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(subPrincipalPortion);
+            principalPortion = principalPortion.add(subPrincipalPortion);
+
+            Money subFeePortion;
+            subFeePortion = 
currentInstallment.payFeeChargesComponent(transactionDate, 
transactionAmountRemaining);
+            transactionAmountRemaining = 
transactionAmountRemaining.minus(subFeePortion);
+            feeChargesPortion = feeChargesPortion.add(subFeePortion);
+
+            loanTransaction.updateComponents(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
+        }
+        if 
(principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero())
 {
+            
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction,
 currentInstallment,
+                    principalPortion, interestPortion, feeChargesPortion, 
penaltyChargesPortion));
+        }
+        return transactionAmountRemaining;
     }
 
     /**
@@ -130,6 +188,7 @@ public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessor extends
             }
             loanTransaction.updateComponents(principalPortion, 
interestPortion, feeChargesPortion, penaltyChargesPortion);
         } else {
+            // Due penalty, interest, principal, fee, In advance penalty, 
interest, principal, fee
             boolean ignoreDueDateCheck = false;
             boolean rerun = false;
 
@@ -161,6 +220,17 @@ public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessor extends
                 transactionAmountRemaining = 
transactionAmountRemaining.minus(subPenaltyPortion);
                 penaltyChargesPortion = 
penaltyChargesPortion.add(subPenaltyPortion);
 
+                Money subInterestPortion;
+                if (ignoreDueDateCheck || 
!transactionDate.isBefore(currentInstallment.getDueDate())) {
+                    subInterestPortion = 
currentInstallment.payInterestComponent(transactionDate, 
transactionAmountRemaining);
+                    transactionAmountRemaining = 
transactionAmountRemaining.minus(subInterestPortion);
+                    interestPortion = interestPortion.add(subInterestPortion);
+                }
+
+                Money subPrincipalPortion = 
currentInstallment.payPrincipalComponent(transactionDate, 
transactionAmountRemaining);
+                transactionAmountRemaining = 
transactionAmountRemaining.minus(subPrincipalPortion);
+                principalPortion = principalPortion.add(subPrincipalPortion);
+
                 Money subFeePortion;
                 if (!ignoreDueDateCheck) {
                     if 
(calculatedFeeCharge.isGreaterThan(transactionAmountRemaining)) {
@@ -173,16 +243,6 @@ public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessor extends
                 transactionAmountRemaining = 
transactionAmountRemaining.minus(subFeePortion);
                 feeChargesPortion = feeChargesPortion.add(subFeePortion);
 
-                Money subInterestPortion;
-                if (ignoreDueDateCheck || 
!transactionDate.isBefore(currentInstallment.getDueDate())) {
-                    subInterestPortion = 
currentInstallment.payInterestComponent(transactionDate, 
transactionAmountRemaining);
-                    transactionAmountRemaining = 
transactionAmountRemaining.minus(subInterestPortion);
-                    interestPortion = interestPortion.add(subInterestPortion);
-                }
-
-                Money subPrincipalPortion = 
currentInstallment.payPrincipalComponent(transactionDate, 
transactionAmountRemaining);
-                transactionAmountRemaining = 
transactionAmountRemaining.minus(subPrincipalPortion);
-                principalPortion = principalPortion.add(subPrincipalPortion);
                 // If the transactionAmountRemaining is greater than zero, 
rerun the allocation without due date check
                 // to distribute the in advance portions
                 if (transactionAmountRemaining.isGreaterThanZero()) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.java
similarity index 90%
copy from 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
copy to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.java
index 7bead6d98..a910992a1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.java
@@ -21,7 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.starter;
 import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 
-public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition extends 
PropertiesCondition {
+public class 
DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition
 extends PropertiesCondition {
 
     @Override
     protected boolean matches(FineractProperties properties) {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.java
similarity index 85%
rename from 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
rename to 
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.java
index 7bead6d98..a06c1e262 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.java
@@ -21,11 +21,11 @@ package org.apache.fineract.portfolio.loanaccount.starter;
 import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 
-public class 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition extends 
PropertiesCondition {
+public class 
DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition
 extends PropertiesCondition {
 
     @Override
     protected boolean matches(FineractProperties properties) {
-        return 
properties.getLoan().getTransactionProcessor().getDuePenaltyFeeInterestPrincipalInAdvancePrincipalPenaltyFeeInterest()
+        return 
properties.getLoan().getTransactionProcessor().getDuePenaltyInterestPrincipalFeeInAdvancePenaltyInterestPrincipalFee()
                 .isEnabled();
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
index 8e04519cd..2e91c4cce 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java
@@ -22,7 +22,8 @@ import java.util.List;
 import 
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
-import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DueDateRespectiveLoanRepaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
 import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
@@ -80,9 +81,15 @@ public class LoanAccountAutoStarter {
     }
 
     @Bean
-    
@Conditional(DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.class)
-    public DueDateRespectiveLoanRepaymentScheduleTransactionProcessor 
dueDateRespectiveTransactionProcessor() {
-        return new 
DueDateRespectiveLoanRepaymentScheduleTransactionProcessor();
+    
@Conditional(DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.class)
+    public 
DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor 
duePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor() 
{
+        return new 
DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor();
+    }
+
+    @Bean
+    
@Conditional(DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.class)
+    public 
DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor 
duePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor() 
{
+        return new 
DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor();
     }
 
     @Bean
diff --git a/fineract-provider/src/main/resources/application.properties 
b/fineract-provider/src/main/resources/application.properties
index 4d07b7230..24252be91 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -90,6 +90,7 @@ 
fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=${F
 
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_PRINCIPAL_INTEREST_PENALTIES_FEES_ENABLED:true}
 
fineract.loan.transactionprocessor.rbi-india.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_RBI_INDIA_ENABLED:true}
 
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_ENABLED:true}
+fineract.loan.transactionprocessor.due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_ENABLED:true}
 
fineract.loan.transactionprocessor.error-not-found-fail=${FINERACT_LOAN_TRANSACTIONPROCESSOR_ERROR_NOT_FOUND_FAIL:true}
 
 
fineract.content.regex-whitelist-enabled=${FINERACT_CONTENT_REGEX_WHITELIST_ENABLED:true}
diff --git 
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml 
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 73bee640d..fc68768f5 100644
--- 
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ 
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -125,4 +125,5 @@
     <include 
file="parts/0103_modify_parameter_json_column_custom_job_parameters.xml" 
relativeToChangelogFile="true" />
     <include 
file="parts/0104_loan_product_add_repayment_overdue_days_config.xml" 
relativeToChangelogFile="true" />
     <include file="parts/0105_add_indices_loan_table.xml" 
relativeToChangelogFile="true" />
+    <include file="parts/0106_new_repayment_strategy.xml" 
relativeToChangelogFile="true" />
 </databaseChangeLog>
diff --git 
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0106_new_repayment_strategy.xml
 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0106_new_repayment_strategy.xml
new file mode 100644
index 000000000..77e5e537f
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0106_new_repayment_strategy.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog";
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+                   
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog 
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd";>
+    <changeSet author="fineract" id="1">
+        <insert tableName="r_enum_value">
+            <column name="enum_name" value="loan_transaction_strategy_id"/>
+            <column name="enum_id" valueNumeric="9"/>
+            <column name="enum_message_property" value="Due penalty, interest, 
principal, fee, In advance penalty, interest, principal, fee"/>
+            <column name="enum_value" value="Due penalty, interest, principal, 
fee, In advance penalty, interest, principal, fee"/>
+            <column name="enum_type" valueBoolean="false"/>
+        </insert>
+    </changeSet>
+    <changeSet id="2" author="fineract">
+        <insert tableName="ref_loan_transaction_processing_strategy">
+            <column name="id" valueNumeric="9"/>
+            <column name="code" 
value="due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy"/>
+            <column name="name" value="Due penalty, interest, principal, fee, 
In advance penalty, interest, principal, fee"/>
+            <column name="sort_order" valueNumeric="9"/>
+        </insert>
+    </changeSet>
+</databaseChangeLog>
diff --git a/fineract-provider/src/test/resources/application-test.properties 
b/fineract-provider/src/test/resources/application-test.properties
index b21b4c2a7..cc0153d0a 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -61,6 +61,7 @@ 
fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=tru
 
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=true
 fineract.loan.transactionprocessor.rbi-india.enabled=true
 
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=true
+fineract.loan.transactionprocessor.due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee.enabled=true
 fineract.loan.transactionprocessor.error-not-found-fail=true
 
 fineract.content.regex-whitelist-enabled=true
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java
index 4933ef598..03bd66359 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DueDateRespectiveLoanRepaymentScheduleTest.java
@@ -22,24 +22,30 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import com.google.gson.Gson;
 import io.restassured.builder.RequestSpecBuilder;
 import io.restassured.builder.ResponseSpecBuilder;
 import io.restassured.http.ContentType;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
+import java.time.LocalDate;
 import java.util.HashMap;
 import org.apache.fineract.client.models.BusinessDateRequest;
 import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
+import 
org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
 import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
 import org.apache.fineract.integrationtests.common.BusinessDateHelper;
 import org.apache.fineract.integrationtests.common.ClientHelper;
 import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.accounting.Account;
 import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
 import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
 import 
org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
 import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import 
org.apache.fineract.integrationtests.common.loans.LoanRescheduleRequestTestBuilder;
 import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
 import 
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
 import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
@@ -57,6 +63,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
     private RequestSpecification requestSpec;
     private BusinessDateHelper businessDateHelper;
     private LoanTransactionHelper loanTransactionHelper;
+    private LoanRescheduleRequestHelper loanRescheduleRequestHelper;
 
     private AccountHelper accountHelper;
 
@@ -68,12 +75,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
         this.responseSpec = new 
ResponseSpecBuilder().expectStatusCode(200).build();
         this.requestSpec.header("Fineract-Platform-TenantId", "default");
         this.loanTransactionHelper = new 
LoanTransactionHelper(this.requestSpec, this.responseSpec);
-        this.loanTransactionHelper = new 
LoanTransactionHelper(this.requestSpec, this.responseSpec);
+        this.loanRescheduleRequestHelper = new 
LoanRescheduleRequestHelper(this.requestSpec, this.responseSpec);
         this.businessDateHelper = new BusinessDateHelper();
         this.accountHelper = new AccountHelper(this.requestSpec, 
this.responseSpec);
     }
 
     // Scenario1:
+    // 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
     // 1. Disburse the loan
     // 2. Adding a partial repayment
     // 3. Adding a charge
@@ -97,11 +105,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
             Integer penalty = ChargesHelper.createCharges(requestSpec, 
responseSpec,
                     
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "50", true));
             final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
-                    LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+                    
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
             final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
 
             final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
-                    LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
"01 January 2023", "01 January 2023");
+                    
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    "01 January 2023", "01 January 2023");
 
             HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
             LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -176,6 +186,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
     }
 
     // Scenario2:
+    // 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
     // 1. Disburse the loan
     // 2. Adding a partial repayment
     // 3. Adding a charge
@@ -206,11 +217,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
             Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
                     
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "50", false));
             final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
-                    LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+                    
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
             final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
 
             final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
-                    LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
"01 January 2023", "01 January 2023");
+                    
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    "01 January 2023", "01 January 2023");
 
             HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
             LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -290,6 +303,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
     }
 
     // Scenario3:
+    // 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
     // 1. Disburse the loan
     // 2. Adding a partial repayment
     // 3. Adding a charge
@@ -311,11 +325,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
             Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
                     
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "50", false));
             final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
-                    LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+                    
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
             final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
 
             final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
-                    LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
"01 January 2023", "01 January 2023");
+                    
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    "01 January 2023", "01 January 2023");
 
             HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
             LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -405,6 +421,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
     }
 
     // Scenario4:
+    // 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
     // 1. Disburse the loan with 3 installments
     // 2. Adding a charge but not due
     // 2. Adding a repayment which fully pays 1st installment and partially 
the next
@@ -425,11 +442,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
             Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
                     
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "50", false));
             final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
-                    LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+                    
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
             final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
 
             final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "3", "1", "3", "0",
-                    LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
"01 January 2023", "01 January 2023");
+                    
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    "01 January 2023", "01 January 2023");
 
             HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
             LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -490,6 +509,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
     }
 
     // Scenario5:
+    // 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
     // 1. Disburse the loan with 3 installments
     // 2. Adding a charge but not due
     // 2. Adding a repayment which fully pays 1st installment and partially 
the next
@@ -511,11 +531,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
             Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
                     
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "50", false));
             final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
-                    LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+                    
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
             final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
 
             final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "3", "1", "3", "0",
-                    LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, 
"01 January 2023", "01 January 2023");
+                    
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
+                    "01 January 2023", "01 January 2023");
 
             HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
             LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -635,6 +657,746 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
         }
     }
 
+    // Scenario6:
+    // 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
+    // 1. Disburse the loan
+    // 2. Adding a snooze fee
+    // 3. Do partial repayment
+    // 3.1 Repay principal fully
+    // 3.2 Repay fee partially
+    @Test
+    public void scenario6() {
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
+
+            final Account assetAccount = 
this.accountHelper.createAssetAccount();
+            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
+
+            Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "20", false));
+            final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
+                    
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
+            final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
+
+            final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
+                    
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    "01 January 2023", "01 January 2023");
+
+            HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 
2023", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+            
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
+
+            loanStatusHashMap = 
loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", 
loanID, "1000");
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+            Integer firstChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee),
 "25 January 2023", "20"));
+            Integer firstRepaymentId = (Integer) 
loanTransactionHelper.makeRepayment("01 March 2023", 
Float.parseFloat("1010.00"), loanID)
+                    .get("resourceId");
+
+            GetLoansLoanIdResponse response = 
loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(10.0, response.getSummary().getTotalOutstanding());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertNull(response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
+    // Scenario7:
+    // 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
+    // 1. Disburse the loan
+    // 2. Full repayment
+    // 3. Reverse repayment
+    // 3.1 Add NSF Fee
+    // 4. Partial repayment
+    @Test
+    public void scenario7() {
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.01.28").dateFormat("yyyy.MM.dd").locale("en"));
+
+            final Account assetAccount = 
this.accountHelper.createAssetAccount();
+            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
+
+            Integer penalty = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "15", true));
+            final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
+                    
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
+            final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
+
+            final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
+                    
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    "01 January 2023", "01 January 2023");
+
+            HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 
2023", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+            
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
+
+            loanStatusHashMap = 
loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", 
loanID, "1000");
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+            Integer firstRepaymentId = (Integer) 
loanTransactionHelper.makeRepayment("25 January 2023", 
Float.parseFloat("1000.00"), loanID)
+                    .get("resourceId");
+
+            GetLoansLoanIdResponse response = 
loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(0.0, response.getSummary().getTotalOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getClosedObligationsMet());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertNull(response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(0, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            PostLoansLoanIdTransactionsResponse reverseRepayment = 
loanTransactionHelper.reverseLoanTransaction((long) loanID,
+                    (long) firstRepaymentId, new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
+                            .transactionDate("28 January 
2023").transactionAmount(0.0).locale("en"));
+
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.01.31").dateFormat("yyyy.MM.dd").locale("en"));
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(1000.0, response.getSummary().getTotalOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertEquals(LocalDate.of(2023, 1, 28), 
response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getManuallyReversed());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(0, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            Integer firstChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
 "28 January 2023", "15"));
+            Integer secondRepayment = (Integer) 
loanTransactionHelper.makeRepayment("31 January 2023", 
Float.parseFloat("1010.00"), loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(5.0, response.getSummary().getTotalOutstanding());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(995.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(secondRepayment, 
response.getTransactions().get(2).getId().intValue());
+            assertNull(response.getTransactions().get(2).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(2).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(2).getAmount());
+            assertEquals(995.0, 
response.getTransactions().get(2).getPrincipalPortion());
+            assertEquals(15.0, 
response.getTransactions().get(2).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getFeeChargesPortion());
+            assertEquals(5.0, 
response.getTransactions().get(2).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(2).getLoanChargePaidByList().size());
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
+    // Scenario8:
+    // 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
+    // 1. Disburse the loan
+    // 2. Snooze fee
+    // 3. Partial repayment
+    // 4. Reverse repayment
+    // 4.1 NSF Fee added
+    // 4. Partial repayment
+    @Test
+    public void scenario8() {
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+
+            final Account assetAccount = 
this.accountHelper.createAssetAccount();
+            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
+
+            Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "20", false));
+            Integer penalty = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "15", true));
+            final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
+                    
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
+            final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
+
+            final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
+                    
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    "01 January 2023", "01 January 2023");
+
+            HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 
2023", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+            
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
+
+            loanStatusHashMap = 
loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", 
loanID, "1000");
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+            final String requestJSON = new 
LoanRescheduleRequestTestBuilder().updateRescheduleFromDate("1 February 2023")
+                    .updateAdjustedDueDate("01 March 
2023").updateSubmittedOnDate("25 January 2023").updateGraceOnPrincipal(null)
+                    
.updateGraceOnInterest(null).updateExtraTerms(null).build(loanID.toString());
+            final HashMap<String, String> map = new HashMap<>();
+            map.put("locale", "en");
+            map.put("dateFormat", "dd MMMM yyyy");
+            map.put("approvedOnDate", "25 January 2023");
+            final String aproveRequestJSON = new Gson().toJson(map);
+
+            Integer loanRescheduleRequestId = 
this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
+            
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(loanRescheduleRequestId,
 aproveRequestJSON);
+
+            Integer firstChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee),
 "01 March 2023", "20"));
+            Integer firstRepaymentId = (Integer) loanTransactionHelper
+                    .makeRepayment("10 February 2023", 
Float.parseFloat("1010.00"), loanID).get("resourceId");
+
+            GetLoansLoanIdResponse response = 
loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(10.0, response.getSummary().getTotalOutstanding());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertNull(response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            PostLoansLoanIdTransactionsResponse reverseRepayment = 
loanTransactionHelper.reverseLoanTransaction((long) loanID,
+                    (long) firstRepaymentId, new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
+                            .transactionDate("15 February 
2023").transactionAmount(0.0).locale("en"));
+
+            Integer secondChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
 "15 February 2023", "15"));
+
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(1035.0, response.getSummary().getTotalOutstanding());
+            assertEquals(1035.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertEquals(LocalDate.of(2023, 2, 15), 
response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getManuallyReversed());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            Integer secondRepayment = (Integer) 
loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("15.00"), 
loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(1020.0, response.getSummary().getTotalOutstanding());
+            assertEquals(1020.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(secondRepayment, 
response.getTransactions().get(2).getId().intValue());
+            assertNull(response.getTransactions().get(2).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(2).getType().getRepayment());
+            assertEquals(15.0, response.getTransactions().get(2).getAmount());
+            assertEquals(0.0, 
response.getTransactions().get(2).getPrincipalPortion());
+            assertEquals(15.0, 
response.getTransactions().get(2).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getFeeChargesPortion());
+            assertEquals(1000.0, 
response.getTransactions().get(2).getOutstandingLoanBalance());
+            assertEquals(secondChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(2).getLoanChargePaidByList().size());
+
+            Integer thirdRepayment = (Integer) 
loanTransactionHelper.makeRepayment("01 March 2023", 
Float.parseFloat("1000.00"), loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(20.0, response.getSummary().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(thirdRepayment, 
response.getTransactions().get(3).getId().intValue());
+            assertNull(response.getTransactions().get(3).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(3).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(3).getType().getRepayment());
+            assertEquals(1000.0, 
response.getTransactions().get(3).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(3).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getOutstandingLoanBalance());
+            assertEquals(0, 
response.getTransactions().get(3).getLoanChargePaidByList().size());
+
+            Integer forthRepayment = (Integer) 
loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("10.00"), 
loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(10.0, response.getSummary().getTotalOutstanding());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(forthRepayment, 
response.getTransactions().get(4).getId().intValue());
+            assertNull(response.getTransactions().get(4).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(4).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(4).getType().getRepayment());
+            assertEquals(10.0, response.getTransactions().get(4).getAmount());
+            assertEquals(0.0, 
response.getTransactions().get(4).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(4).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(4).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(4).getLoanChargePaidByList().size());
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
+    // Scenario9:
+    // 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
+    // 1. Disburse the loan
+    // 2. Snooze fee
+    // 3. Partial repayment
+    // 4. Reverse repayment
+    // 4.1 NSF Fee added
+    // 4. Partial repayment
+    // 5. Reverse repayment
+    // 5.1 NSF Fee added
+    // 6. Partial repayment
+    @Test
+    public void scenario9() {
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
+
+            final Account assetAccount = 
this.accountHelper.createAssetAccount();
+            final Account incomeAccount = 
this.accountHelper.createIncomeAccount();
+            final Account expenseAccount = 
this.accountHelper.createExpenseAccount();
+            final Account overpaymentAccount = 
this.accountHelper.createLiabilityAccount();
+
+            Integer fee = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "20", false));
+            Integer penalty = ChargesHelper.createCharges(requestSpec, 
responseSpec,
+                    
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT,
 "15", true));
+            final Integer loanProductID = 
createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
+                    
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    assetAccount, incomeAccount, expenseAccount, 
overpaymentAccount);
+            final Integer clientID = ClientHelper.createClient(requestSpec, 
responseSpec, "01 January 2023");
+
+            final Integer loanID = applyForLoanApplication(clientID, 
loanProductID, "1000", "1", "1", "1", "0",
+                    
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
+                    "01 January 2023", "01 January 2023");
+
+            HashMap<String, Object> loanStatusHashMap = 
LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
+            LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
+
+            loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 
2023", loanID);
+            LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
+            
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
+
+            loanStatusHashMap = 
loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", 
loanID, "1000");
+            LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
+
+            final String requestJSON = new 
LoanRescheduleRequestTestBuilder().updateRescheduleFromDate("1 February 2023")
+                    .updateAdjustedDueDate("01 March 
2023").updateSubmittedOnDate("25 January 2023").updateGraceOnPrincipal(null)
+                    
.updateGraceOnInterest(null).updateExtraTerms(null).build(loanID.toString());
+            final HashMap<String, String> map = new HashMap<>();
+            map.put("locale", "en");
+            map.put("dateFormat", "dd MMMM yyyy");
+            map.put("approvedOnDate", "25 January 2023");
+            final String aproveRequestJSON = new Gson().toJson(map);
+
+            Integer loanRescheduleRequestId = 
this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
+            
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(loanRescheduleRequestId,
 aproveRequestJSON);
+
+            Integer firstChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee),
 "01 March 2023", "20"));
+            Integer firstRepaymentId = (Integer) loanTransactionHelper
+                    .makeRepayment("10 February 2023", 
Float.parseFloat("1010.00"), loanID).get("resourceId");
+
+            GetLoansLoanIdResponse response = 
loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(10.0, response.getSummary().getTotalOutstanding());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertNull(response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            PostLoansLoanIdTransactionsResponse reverseRepayment = 
loanTransactionHelper.reverseLoanTransaction((long) loanID,
+                    (long) firstRepaymentId, new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
+                            .transactionDate("15 February 
2023").transactionAmount(0.0).locale("en"));
+
+            Integer secondChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
 "15 February 2023", "15"));
+
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(1035.0, response.getSummary().getTotalOutstanding());
+            assertEquals(1035.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(firstRepaymentId, 
response.getTransactions().get(1).getId().intValue());
+            assertEquals(LocalDate.of(2023, 2, 15), 
response.getTransactions().get(1).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(1).getManuallyReversed());
+            
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(1).getType().getRepayment());
+            assertEquals(1010.0, 
response.getTransactions().get(1).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(1).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getInterestPortion());
+            assertEquals(10.0, 
response.getTransactions().get(1).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(1).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(1).getLoanChargePaidByList().size());
+
+            Integer secondRepayment = (Integer) 
loanTransactionHelper.makeRepayment("01 March 2023", 
Float.parseFloat("1030.00"), loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(5.0, response.getSummary().getTotalOutstanding());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(secondRepayment, 
response.getTransactions().get(2).getId().intValue());
+            assertNull(response.getTransactions().get(2).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(2).getType().getRepayment());
+            assertEquals(1030.0, 
response.getTransactions().get(2).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(2).getPrincipalPortion());
+            assertEquals(15.0, 
response.getTransactions().get(2).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getInterestPortion());
+            assertEquals(15.0, 
response.getTransactions().get(2).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(2).getOutstandingLoanBalance());
+            if 
(secondChargeId.equals(response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue()))
 {
+                assertEquals(secondChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
+                assertEquals(firstChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(1).getChargeId().intValue());
+            } else {
+                assertEquals(secondChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(1).getChargeId().intValue());
+                assertEquals(firstChargeId, 
response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            }
+            assertEquals(2, 
response.getTransactions().get(2).getLoanChargePaidByList().size());
+
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.03.07").dateFormat("yyyy.MM.dd").locale("en"));
+
+            PostLoansLoanIdTransactionsResponse secondReverseRepayment = 
loanTransactionHelper.reverseLoanTransaction((long) loanID,
+                    (long) secondRepayment, new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
+                            .transactionDate("07 March 
2023").transactionAmount(0.0).locale("en"));
+
+            Integer thirdChargeId = 
loanTransactionHelper.addChargesForLoan(loanID,
+                    
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty),
 "07 March 2023", "15"));
+
+            businessDateHelper.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("2023.03.08").dateFormat("yyyy.MM.dd").locale("en"));
+
+            Integer thirdRepayment = (Integer) 
loanTransactionHelper.makeRepayment("08 March 2023", Float.parseFloat("15.00"), 
loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(1035.0, response.getSummary().getTotalOutstanding());
+            assertEquals(1035.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
+
+            assertEquals(thirdRepayment, 
response.getTransactions().get(3).getId().intValue());
+            assertNull(response.getTransactions().get(3).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(3).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(3).getType().getRepayment());
+            assertEquals(15.0, response.getTransactions().get(3).getAmount());
+            assertEquals(0.0, 
response.getTransactions().get(3).getPrincipalPortion());
+            assertEquals(15.0, 
response.getTransactions().get(3).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getInterestPortion());
+            assertEquals(0.0, 
response.getTransactions().get(3).getFeeChargesPortion());
+            assertEquals(1000.0, 
response.getTransactions().get(3).getOutstandingLoanBalance());
+            assertEquals(secondChargeId, 
response.getTransactions().get(3).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(3).getLoanChargePaidByList().size());
+
+            Integer forthRepayment = (Integer) 
loanTransactionHelper.makeRepayment("08 March 2023", 
Float.parseFloat("1015.00"), loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(20.0, response.getSummary().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
+
+            assertEquals(forthRepayment, 
response.getTransactions().get(4).getId().intValue());
+            assertNull(response.getTransactions().get(4).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(4).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(4).getType().getRepayment());
+            assertEquals(1015.0, 
response.getTransactions().get(4).getAmount());
+            assertEquals(1000.0, 
response.getTransactions().get(4).getPrincipalPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getInterestPortion());
+            assertEquals(15.0, 
response.getTransactions().get(4).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(4).getOutstandingLoanBalance());
+            assertEquals(firstChargeId, 
response.getTransactions().get(4).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            assertEquals(1, 
response.getTransactions().get(4).getLoanChargePaidByList().size());
+
+            Integer fifthRepayment = (Integer) 
loanTransactionHelper.makeRepayment("08 March 2023", Float.parseFloat("10.00"), 
loanID)
+                    .get("resourceId");
+
+            response = loanTransactionHelper.getLoanDetails((long) loanID);
+            assertEquals(10.0, response.getSummary().getTotalOutstanding());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getTotalOutstanding());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
+            assertEquals(20.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
+            assertEquals(1000.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
+            assertTrue(response.getStatus().getActive());
+
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
+            assertEquals(15.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
+            assertEquals(5.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
+            assertEquals(10.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
+            assertEquals(0.0, 
response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
+
+            assertEquals(fifthRepayment, 
response.getTransactions().get(5).getId().intValue());
+            assertNull(response.getTransactions().get(5).getReversedOnDate());
+            
assertTrue(response.getTransactions().get(5).getTransactionRelations().isEmpty());
+            
assertTrue(response.getTransactions().get(5).getType().getRepayment());
+            assertEquals(10.0, response.getTransactions().get(5).getAmount());
+            assertEquals(0.0, 
response.getTransactions().get(5).getPrincipalPortion());
+            assertEquals(5.0, 
response.getTransactions().get(5).getPenaltyChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(5).getOverpaymentPortion());
+            assertEquals(0.0, 
response.getTransactions().get(5).getInterestPortion());
+            assertEquals(5.0, 
response.getTransactions().get(5).getFeeChargesPortion());
+            assertEquals(0.0, 
response.getTransactions().get(5).getOutstandingLoanBalance());
+            if 
(firstChargeId.equals(response.getTransactions().get(5).getLoanChargePaidByList().get(0).getChargeId().intValue()))
 {
+                assertEquals(thirdChargeId, 
response.getTransactions().get(5).getLoanChargePaidByList().get(1).getChargeId().intValue());
+            } else {
+                assertEquals(firstChargeId, 
response.getTransactions().get(5).getLoanChargePaidByList().get(1).getChargeId().intValue());
+                assertEquals(thirdChargeId, 
response.getTransactions().get(5).getLoanChargePaidByList().get(0).getChargeId().intValue());
+            }
+            assertEquals(2, 
response.getTransactions().get(5).getLoanChargePaidByList().size());
+
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
     private Integer applyForLoanApplication(final Integer clientID, final 
Integer loanProductID, final String principal,
             final String loanTermFrequency, final String repaymentAfterEvery, 
final String numberOfRepayments, final String interestRate,
             final String repaymentStrategy, final String 
expectedDisbursementDate, final String submittedOnDate) {
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
index 3fd737bda..55e7e95e6 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanApplicationTestBuilder.java
@@ -42,7 +42,8 @@ public class LoanApplicationTestBuilder {
     public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
     public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";
     public static final String 
INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = 
"interest-principal-penalties-fees-order-strategy";
-    public static final String DUE_DATE_RESPECTIVE_STRATEGY = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
+    public static final String 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
 = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
+    public static final String 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
 = 
"due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
 
     private String externalId = null;
     private String principal = "10,000";
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
index ee14dffda..7a678db8f 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java
@@ -42,7 +42,9 @@ public class LoanProductTestBuilder {
     private static final String FLAT_BALANCE = "1";
     public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
     public static final String 
INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = 
"interest-principal-penalties-fees-order-strategy";
-    public static final String DUE_DATE_RESPECTIVE_STRATEGY = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
+    public static final String 
DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
 = 
"due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
+    public static final String 
DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
 = 
"due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
+
     // private static final String HEAVENS_FAMILY_STRATEGY 
="heavensfamily-strategy";
     // private static final String CREO_CORE_STRATEGY ="creocore-strategy";
     public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";

Reply via email to