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

arnold 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 c89e7c3f4 FINERACT-1971: Adding charge on a closed loan after maturity 
date should create an N+1 installment
c89e7c3f4 is described below

commit c89e7c3f461ba0841a3987f411d9b0c9c1ffc05d
Author: Adam Saghy <[email protected]>
AuthorDate: Wed Oct 4 17:38:52 2023 -0400

    FINERACT-1971: Adding charge on a closed loan after maturity date should 
create an N+1 installment
---
 .../LoanChargeWritePlatformServiceImpl.java        |   8 +-
 ...LoanSpecificDueDateChargeAfterMaturityTest.java | 226 ++++++++++++++++++---
 2 files changed, 203 insertions(+), 31 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
index 83b4c0508..27c292d52 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
@@ -985,13 +985,7 @@ public class LoanChargeWritePlatformServiceImpl implements 
LoanChargeWritePlatfo
             }
         }
 
-        LocalDate loanMaturityDate = loan.getExpectedMaturityDate();
-
-        if (loan.getMaturityDate() != null) {
-            loanMaturityDate = loan.getMaturityDate();
-        }
-
-        if (!loan.isInterestBearing() && loanCharge.isSpecifiedDueDate() && 
loanCharge.getDueDate().isAfter(loanMaturityDate)) {
+        if (!loan.isInterestBearing() && loanCharge.isSpecifiedDueDate()) {
             LoanRepaymentScheduleInstallment latestRepaymentScheduleInstalment 
= loan.getRepaymentScheduleInstallments()
                     .get(loan.getLoanRepaymentScheduleInstallmentsSize() - 1);
             if 
(loanCharge.getDueDate().isAfter(latestRepaymentScheduleInstalment.getDueDate()))
 {
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
index 6945f57d1..7efe0be71 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanSpecificDueDateChargeAfterMaturityTest.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.integrationtests;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import io.restassured.builder.RequestSpecBuilder;
 import io.restassured.builder.ResponseSpecBuilder;
@@ -26,13 +27,31 @@ import io.restassured.http.ContentType;
 import io.restassured.path.json.JsonPath;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
+import org.apache.fineract.client.models.BusinessDateRequest;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.client.models.PostChargesRequest;
+import org.apache.fineract.client.models.PostChargesResponse;
+import org.apache.fineract.client.models.PostClientsResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
+import 
org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
+import org.apache.fineract.client.models.PostLoansRequest;
+import org.apache.fineract.client.models.PostLoansResponse;
+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.Utils;
 import org.apache.fineract.integrationtests.common.accounting.Account;
 import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
@@ -44,7 +63,10 @@ import 
org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
 import 
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
 import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
 import 
org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
+import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
+import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.slf4j.Logger;
@@ -54,9 +76,10 @@ import org.slf4j.LoggerFactory;
 @ExtendWith(LoanTestLifecycleExtension.class)
 public class LoanSpecificDueDateChargeAfterMaturityTest {
 
-    public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
-    public static final String MINIMUM_OPENING_BALANCE = "1000.0";
-    public static final String DEPOSIT_AMOUNT = "7000";
+    private static final String DATETIME_PATTERN = "dd MMMM yyyy";
+    private static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
+    private static final String MINIMUM_OPENING_BALANCE = "1000.0";
+    private static final String DEPOSIT_AMOUNT = "7000";
     private static final Logger LOG = 
LoggerFactory.getLogger(LoanSpecificDueDateChargeAfterMaturityTest.class);
     private static final String DATE_OF_JOINING = "01 January 2011";
     private static final Float LP_PRINCIPAL = 10000.0f;
@@ -66,12 +89,16 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
     private static final String LOAN_APPLICATION_SUBMISSION_DATE = "03 March 
2011";
     private static final String LOAN_TERM_FREQUENCY = "1";
     private static final String INDIVIDUAL_LOAN = "individual";
+    private static final BusinessDateHelper BUSINESS_DATE_HELPER = new 
BusinessDateHelper();
+    private static final DateTimeFormatter DATE_FORMATTER = new 
DateTimeFormatterBuilder().appendPattern(DATETIME_PATTERN).toFormatter();
+    private static final ChargesHelper CHARGES_HELPER = new ChargesHelper();
     private static RequestSpecification requestSpec;
     private static ResponseSpecification responseSpec;
-    private LoanTransactionHelper loanTransactionHelper;
-    private AccountHelper accountHelper;
-    private PeriodicAccrualAccountingHelper periodicAccrualAccountingHelper;
-    private DateTimeFormatter dateFormatter = new 
DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
+    private static LoanTransactionHelper loanTransactionHelper;
+    private static AccountHelper accountHelper;
+    private static PeriodicAccrualAccountingHelper 
periodicAccrualAccountingHelper;
+    private static Integer commonLoanProductId;
+    private static PostClientsResponse client;
 
     public static Integer createSavingsProduct(final String 
minOpenningBalance, final Account... accounts) {
         LOG.info("------------------------------CREATING NEW SAVINGS PRODUCT 
---------------------------------------");
@@ -82,17 +109,24 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         return SavingsProductHelper.createSavingsProduct(savingsProductJSON, 
requestSpec, responseSpec);
     }
 
-    @BeforeEach
-    public void setup() {
+    @BeforeAll
+    public static void setupCommon() {
         Utils.initializeRESTAssured();
+        ClientHelper clientHelper = new ClientHelper(requestSpec, 
responseSpec);
         requestSpec = new 
RequestSpecBuilder().setContentType(ContentType.JSON).build();
         requestSpec.header("Authorization", "Basic " + 
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
         requestSpec.header("Fineract-Platform-TenantId", "default");
         responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
 
-        this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, 
responseSpec);
-        this.accountHelper = new AccountHelper(requestSpec, responseSpec);
-        this.periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec, responseSpec);
+        loanTransactionHelper = new LoanTransactionHelper(requestSpec, 
responseSpec);
+        accountHelper = new AccountHelper(requestSpec, responseSpec);
+        periodicAccrualAccountingHelper = new 
PeriodicAccrualAccountingHelper(requestSpec, responseSpec);
+        final Account assetAccount = accountHelper.createAssetAccount();
+        final Account incomeAccount = accountHelper.createIncomeAccount();
+        final Account expenseAccount = accountHelper.createExpenseAccount();
+        final Account overpaymentAccount = 
accountHelper.createLiabilityAccount();
+        commonLoanProductId = createLoanProduct("500", "15", "4", 
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
+        client = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
     }
 
     @Test
@@ -132,7 +166,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
 
         LocalDate targetDate = LocalDate.of(2011, 3, 4);
-        final String loanDisbursementDate = dateFormatter.format(targetDate);
+        final String loanDisbursementDate = DATE_FORMATTER.format(targetDate);
 
         String loanDetails = 
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
         loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(loanDisbursementDate,
 loanID,
@@ -148,7 +182,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         assertEquals(10000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
         assertEquals(10000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
         targetDate = LocalDate.of(2011, 4, 5);
-        final String penaltyCharge1AddedDate = 
dateFormatter.format(targetDate);
+        final String penaltyCharge1AddedDate = 
DATE_FORMATTER.format(targetDate);
         Integer penalty1LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID,
                 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDate),
 penaltyCharge1AddedDate,
                         String.valueOf(PENALTY_PORTION)));
@@ -173,7 +207,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         
this.loanTransactionHelper.checkAccrualTransactionForRepayment(runOnDate, 0.0f, 
0.0f, PENALTY_PORTION, loanID);
 
         targetDate = LocalDate.of(2011, 4, 6);
-        final String feeCharge1AddedDate = dateFormatter.format(targetDate);
+        final String feeCharge1AddedDate = DATE_FORMATTER.format(targetDate);
         Integer fee1LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper
                 .getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flat), 
feeCharge1AddedDate, String.valueOf(FEE_PORTION)));
 
@@ -189,7 +223,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
                 (int) ((List) loanSchedule.get(2).get("dueDate")).get(1), 
(int) ((List) loanSchedule.get(2).get("dueDate")).get(2)));
 
         targetDate = LocalDate.of(2011, 4, 7);
-        final String penaltyCharge2AddedDate = 
dateFormatter.format(targetDate);
+        final String penaltyCharge2AddedDate = 
DATE_FORMATTER.format(targetDate);
         Integer penalty2LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID,
                 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDateNext),
                         penaltyCharge2AddedDate, 
String.valueOf(NEXT_PENALTY_PORTION)));
@@ -206,7 +240,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
                 (int) ((List) loanSchedule.get(2).get("dueDate")).get(1), 
(int) ((List) loanSchedule.get(2).get("dueDate")).get(2)));
 
         targetDate = LocalDate.of(2011, 4, 8);
-        final String feeCharge2AddedDate = dateFormatter.format(targetDate);
+        final String feeCharge2AddedDate = DATE_FORMATTER.format(targetDate);
         Integer fee2LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper
                 
.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatNext), 
feeCharge2AddedDate, String.valueOf(NEXT_FEE_PORTION)));
 
@@ -265,7 +299,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
 
         LocalDate targetDate = LocalDate.of(2011, 3, 4);
-        final String loanDisbursementDate = dateFormatter.format(targetDate);
+        final String loanDisbursementDate = DATE_FORMATTER.format(targetDate);
 
         String loanDetails = 
this.loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID);
         loanStatusHashMap = 
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(loanDisbursementDate,
 loanID,
@@ -282,14 +316,14 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         assertEquals(10000.0f, 
loanSchedule.get(1).get("totalOutstandingForPeriod"));
 
         targetDate = LocalDate.of(2011, 3, 10);
-        String repaymentDateStr = dateFormatter.format(targetDate);
+        String repaymentDateStr = DATE_FORMATTER.format(targetDate);
         loanTransactionHelper.makeRepayment(repaymentDateStr, 10000.0f, 
loanID);
 
         loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, 
responseSpec, loanID);
         LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
 
         targetDate = LocalDate.of(2011, 4, 13);
-        final String penaltyCharge1AddedDate = 
dateFormatter.format(targetDate);
+        final String penaltyCharge1AddedDate = 
DATE_FORMATTER.format(targetDate);
         Integer penalty1LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID,
                 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDate),
 penaltyCharge1AddedDate,
                         String.valueOf(PENALTY_PORTION)));
@@ -309,7 +343,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
                 (int) ((List) loanSchedule.get(2).get("dueDate")).get(1), 
(int) ((List) loanSchedule.get(2).get("dueDate")).get(2)));
 
         targetDate = LocalDate.of(2011, 4, 14);
-        String runOnDateStr = dateFormatter.format(targetDate);
+        String runOnDateStr = DATE_FORMATTER.format(targetDate);
         
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOnDateStr);
 
         // Transaction date will be the due date of the instalment (in case of 
N+1 scenario)
@@ -335,7 +369,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
                 (int) ((List) loanSchedule.get(2).get("dueDate")).get(1), 
(int) ((List) loanSchedule.get(2).get("dueDate")).get(2)));
 
         targetDate = LocalDate.of(2011, 4, 14);
-        String penaltyCharge2AddedDate = dateFormatter.format(targetDate);
+        String penaltyCharge2AddedDate = DATE_FORMATTER.format(targetDate);
         Integer penalty2LoanChargeId = 
this.loanTransactionHelper.addChargesForLoan(loanID,
                 
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(flatSpecifiedDueDate),
 penaltyCharge2AddedDate,
                         String.valueOf(PENALTY_PORTION)));
@@ -357,7 +391,7 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
 
         targetDate = LocalDate.of(2011, 4, 15);
-        repaymentDateStr = dateFormatter.format(targetDate);
+        repaymentDateStr = DATE_FORMATTER.format(targetDate);
         loanTransactionHelper.makeRepayment(repaymentDateStr, PENALTY_PORTION, 
loanID);
 
         loanSchedule = 
this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, 
loanID);
@@ -399,6 +433,85 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
                 (int) ((List) loanSchedule.get(2).get("dueDate")).get(1), 
(int) ((List) loanSchedule.get(2).get("dueDate")).get(2)));
     }
 
+    @Test
+    public void addChargeAfterLoanMaturity() {
+        try {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.TRUE);
+            BUSINESS_DATE_HELPER.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("01 September 
2023").dateFormat(DATETIME_PATTERN).locale("en"));
+
+            PostChargesResponse penaltyCharge = 
CHARGES_HELPER.createCharges(new PostChargesRequest().penalty(true).amount(10.0)
+                    
.chargeCalculationType(ChargeCalculationType.FLAT.getValue())
+                    
.chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()).chargePaymentMode(ChargePaymentMode.REGULAR.getValue())
+                    
.currencyCode("USD").name(Utils.randomStringGenerator("PENALTY_" + 
Calendar.getInstance().getTimeInMillis(), 5))
+                    .chargeAppliesTo(1).locale("en").active(true));
+
+            final PostLoansResponse loanResponse = 
applyForLoanApplication(client.getClientId(), commonLoanProductId, 1000L, 30, 
30, 1, 0,
+                    "01 September 2023", "01 September 2023");
+
+            loanTransactionHelper.approveLoan(loanResponse.getLoanId(),
+                    new 
PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000)).dateFormat(DATETIME_PATTERN)
+                            .approvedOnDate("01 September 2023").locale("en"));
+
+            loanTransactionHelper.disburseLoan(loanResponse.getLoanId(),
+                    new PostLoansLoanIdRequest().actualDisbursementDate("01 
September 2023").dateFormat(DATETIME_PATTERN)
+                            
.transactionAmount(BigDecimal.valueOf(1000)).locale("en"));
+
+            GetLoansLoanIdResponse loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 1000.0, 0.0, 1000.0, 0.0, 
null);
+            validateRepaymentPeriod(loanDetails, 1, 1000.0, 0.0, 1000.0, 0.0, 
0.0);
+            validateLoanTransaction(loanDetails, 0, 1000.0, 0.0, 0.0, 1000.0);
+            assertTrue(loanDetails.getStatus().getActive());
+
+            BUSINESS_DATE_HELPER.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("01 October 
2023").dateFormat(DATETIME_PATTERN).locale("en"));
+
+            PostLoansLoanIdTransactionsResponse repaymentTransaction = 
loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(),
+                    new 
PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("01
 October 2023").locale("en")
+                            .transactionAmount(1000.0));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 0.0, 1000.0, 0.0, 1000.0, 
null);
+            validateRepaymentPeriod(loanDetails, 1, 1000.0, 1000.0, 0.0, 0.0, 
0.0);
+            validateLoanTransaction(loanDetails, 1, 1000.0, 1000.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getClosedObligationsMet());
+
+            BUSINESS_DATE_HELPER.updateBusinessDate(new 
BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
+                    .date("04 October 
2023").dateFormat(DATETIME_PATTERN).locale("en"));
+
+            
loanTransactionHelper.makeMerchantIssuedRefund(loanResponse.getLoanId(), new 
PostLoansLoanIdTransactionsRequest()
+                    .dateFormat(DATETIME_PATTERN).transactionDate("04 October 
2023").locale("en").transactionAmount(1000.0));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 0.0, 1000.0, 0.0, 1000.0, 
1000.0);
+            validateRepaymentPeriod(loanDetails, 1, 1000.0, 1000.0, 0.0, 0.0, 
0.0);
+            validateLoanTransaction(loanDetails, 2, 1000.0, 0.0, 1000.0, 0.0);
+            assertTrue(loanDetails.getStatus().getOverpaid());
+
+            
loanTransactionHelper.reverseLoanTransaction(loanResponse.getLoanId(), 
repaymentTransaction.getResourceId(),
+                    new 
PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("04
 October 2023")
+                            .transactionAmount(0.0).locale("en"));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 0.0, 1000.0, 0.0, 1000.0, 
null);
+            validateRepaymentPeriod(loanDetails, 1, 1000.0, 1000.0, 0.0, 0.0, 
1000.0);
+            validateLoanTransaction(loanDetails, 2, 1000.0, 1000.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getClosedObligationsMet());
+
+            PostLoansLoanIdChargesResponse penaltyLoanChargeResult = 
loanTransactionHelper.addChargesForLoan(loanResponse.getLoanId(),
+                    new 
PostLoansLoanIdChargesRequest().chargeId(penaltyCharge.getResourceId()).dateFormat(DATETIME_PATTERN).locale("en")
+                            .amount(10.0).dueDate("04 October 2023"));
+
+            loanDetails = 
loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
+            validateLoanSummaryBalances(loanDetails, 10.0, 1000.0, 0.0, 
1000.0, null);
+            validateRepaymentPeriod(loanDetails, 1, 1000.0, 1000.0, 0.0, 0.0, 
1000.0);
+            validateRepaymentPeriod(loanDetails, 2, 0.0, 0.0, 0.0, 10.0, 0.0, 
10.0, 0.0, 0.0);
+            assertTrue(loanDetails.getStatus().getActive());
+        } finally {
+            GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, 
responseSpec, Boolean.FALSE);
+        }
+    }
+
     private Integer applyForLoanApplication(final Integer clientID, final 
Integer loanProductID, String interestRate) {
         LOG.info("--------------------------------APPLYING FOR LOAN 
APPLICATION--------------------------------");
         final String loanApplicationJSON = new 
LoanApplicationTestBuilder().withPrincipal(LP_PRINCIPAL.toString())
@@ -421,4 +534,69 @@ public class LoanSpecificDueDateChargeAfterMaturityTest {
         return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
     }
 
+    private static Integer createLoanProduct(final String principal, final 
String repaymentAfterEvery, final String numberOfRepayments,
+            final Account... accounts) {
+        LOG.info("------------------------------CREATING NEW LOAN PRODUCT 
---------------------------------------");
+        final String loanProductJSON = new 
LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
+                
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
+                
.withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsMonths()
+                .withRepaymentStrategy(
+                        
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY)
+                
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts)
+                
.withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", 
"0").build(null);
+        return loanTransactionHelper.getLoanProductId(loanProductJSON);
+    }
+
+    private static PostLoansResponse applyForLoanApplication(final Long 
clientId, final Integer loanProductId, final Long principal,
+            final int loanTermFrequency, final int repaymentAfterEvery, final 
int numberOfRepayments, final int interestRate,
+            final String expectedDisbursementDate, final String 
submittedOnDate) {
+        LOG.info("--------------------------------APPLYING FOR LOAN 
APPLICATION--------------------------------");
+        return loanTransactionHelper.applyLoan(new 
PostLoansRequest().clientId(clientId).productId(loanProductId.longValue())
+                
.expectedDisbursementDate(expectedDisbursementDate).dateFormat(DATETIME_PATTERN)
+                .transactionProcessingStrategyCode(
+                        
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY)
+                
.locale("en").submittedOnDate(submittedOnDate).amortizationType(1).interestRatePerPeriod(interestRate)
+                
.interestCalculationPeriodType(1).interestType(0).repaymentFrequencyType(0).repaymentEvery(repaymentAfterEvery)
+                
.repaymentFrequencyType(0).numberOfRepayments(numberOfRepayments).loanTermFrequency(loanTermFrequency)
+                
.loanTermFrequencyType(0).principal(BigDecimal.valueOf(principal)).loanType("individual"));
+    }
+
+    private static void validateLoanTransaction(GetLoansLoanIdResponse 
loanDetails, int index, double transactionAmount,
+            double principalPortion, double overPaidPortion, double 
loanBalance) {
+        assertEquals(transactionAmount, 
loanDetails.getTransactions().get(index).getAmount());
+        assertEquals(principalPortion, 
loanDetails.getTransactions().get(index).getPrincipalPortion());
+        assertEquals(overPaidPortion, 
loanDetails.getTransactions().get(index).getOverpaymentPortion());
+        assertEquals(loanBalance, 
loanDetails.getTransactions().get(index).getOutstandingLoanBalance());
+    }
+
+    private static void validateRepaymentPeriod(GetLoansLoanIdResponse 
loanDetails, int index, double principalDue, double principalPaid,
+            double principalOutstanding, double paidInAdvance, double 
paidLate) {
+        assertEquals(principalDue, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalDue());
+        assertEquals(principalPaid, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalPaid());
+        assertEquals(principalOutstanding, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalOutstanding());
+        assertEquals(paidInAdvance, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getTotalPaidInAdvanceForPeriod());
+        assertEquals(paidLate, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getTotalPaidLateForPeriod());
+    }
+
+    private static void validateRepaymentPeriod(GetLoansLoanIdResponse 
loanDetails, int index, double principalDue, double principalPaid,
+            double principalOutstanding, double penaltyDue, double 
penaltyPaid, double penaltyOutstanding, double paidInAdvance,
+            double paidLate) {
+        assertEquals(principalDue, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalDue());
+        assertEquals(principalPaid, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalPaid());
+        assertEquals(principalOutstanding, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPrincipalOutstanding());
+        assertEquals(penaltyDue, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPenaltyChargesDue());
+        assertEquals(penaltyPaid, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPenaltyChargesPaid());
+        assertEquals(penaltyOutstanding, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getPenaltyChargesOutstanding());
+        assertEquals(paidInAdvance, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getTotalPaidInAdvanceForPeriod());
+        assertEquals(paidLate, 
loanDetails.getRepaymentSchedule().getPeriods().get(index).getTotalPaidLateForPeriod());
+    }
+
+    private static void validateLoanSummaryBalances(GetLoansLoanIdResponse 
loanDetails, Double totalOutstanding, Double totalRepayment,
+            Double principalOutstanding, Double principalPaid, Double 
totalOverpaid) {
+        assertEquals(totalOutstanding, 
loanDetails.getSummary().getTotalOutstanding());
+        assertEquals(totalRepayment, 
loanDetails.getSummary().getTotalRepayment());
+        assertEquals(principalOutstanding, 
loanDetails.getSummary().getPrincipalOutstanding());
+        assertEquals(principalPaid, 
loanDetails.getSummary().getPrincipalPaid());
+        assertEquals(totalOverpaid, loanDetails.getTotalOverpaid());
+    }
 }

Reply via email to