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

taskain 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 f05be57c5 FINERACT-2060: Validation rules for loan reamortization
f05be57c5 is described below

commit f05be57c50015e820fe2beffdae662ec03df6590
Author: Arnold Galovics <[email protected]>
AuthorDate: Wed Mar 6 18:04:54 2024 +0100

    FINERACT-2060: Validation rules for loan reamortization
---
 .../LoanReAmortizationValidator.java               | 104 +++++++-
 .../LoanReAmortizationValidatorTest.java           | 294 +++++++++++++++++++++
 .../loan/reaging/LoanReAgingIntegrationTest.java   |   7 +-
 .../LoanReAmortizationIntegrationTest.java         |  25 +-
 4 files changed, 416 insertions(+), 14 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
index 643c26060..b530714c1 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java
@@ -18,18 +18,118 @@
  */
 package org.apache.fineract.portfolio.loanaccount.service.reamortization;
 
+import static 
org.apache.fineract.infrastructure.core.service.DateUtils.getBusinessLocalDate;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import 
org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
+import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import 
org.apache.fineract.portfolio.loanaccount.api.LoanReAmortizationApiConstants;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.ChargeOrTransaction;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
 import org.springframework.stereotype.Component;
 
 @Component
 public class LoanReAmortizationValidator {
 
     public void validateReAmortize(Loan loan, JsonCommand command) {
-        // TODO: implement
+        validateReAmortizeRequest(command);
+        validateReAmortizeBusinessRules(loan);
+    }
+
+    private void validateReAmortizeRequest(JsonCommand command) {
+        List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors).resource("loan.reAmortization");
+
+        String externalId = 
command.stringValueOfParameterNamedAllowingNull(LoanReAmortizationApiConstants.externalIdParameterName);
+        
baseDataValidator.reset().parameter(LoanReAmortizationApiConstants.externalIdParameterName).ignoreIfNull().value(externalId)
+                .notExceedingLengthOf(100);
+
+        throwExceptionIfValidationErrorsExist(dataValidationErrors);
+    }
+
+    private void validateReAmortizeBusinessRules(Loan loan) {
+        // validate reamortization shouldn't happen after maturity
+        if (DateUtils.isAfter(getBusinessLocalDate(), loan.getMaturityDate())) 
{
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.cannot.be.submitted.after.maturity",
+                    "Loan cannot be re-amortized after maturity", 
loan.getId());
+        }
+
+        // validate reamortization is only available for progressive schedule 
& advanced payment allocation
+        LoanScheduleType loanScheduleType = 
LoanScheduleType.valueOf(loan.getLoanProductRelatedDetail().getLoanScheduleType().name());
+        boolean isProgressiveSchedule = 
LoanScheduleType.PROGRESSIVE.equals(loanScheduleType);
+
+        String transactionProcessingStrategyCode = 
loan.getTransactionProcessingStrategyCode();
+        boolean isAdvancedPaymentSchedule = 
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY
+                .equals(transactionProcessingStrategyCode);
+
+        if (!(isProgressiveSchedule && isAdvancedPaymentSchedule)) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.supported.only.for.progressive.loan.schedule.type",
+                    "Loan reamortization is only available for progressive 
repayment schedule and Advanced payment allocation strategy",
+                    loan.getId());
+        }
+
+        // validate reamortization is only available for non-interest bearing 
loans
+        if (loan.isInterestBearing()) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.supported.only.for.non.interest.loans",
+                    "Loan reamortization is only available for non-interest 
bearing loans", loan.getId());
+        }
+
+        // validate reamortization is only done on an active loan
+        if (!loan.getStatus().isActive()) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.supported.only.for.active.loans",
+                    "Loan reamortization can only be done on active loans", 
loan.getId());
+        }
+
+        // validate if there's already a re-amortization transaction for today
+        boolean isReAmortizationTransactionForTodayPresent = 
loan.getLoanTransactions().stream()
+                .anyMatch(tx -> tx.getTypeOf().isReAmortize() && 
tx.getTransactionDate().equals(getBusinessLocalDate()));
+        if (isReAmortizationTransactionForTodayPresent) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.reamortize.transaction.already.present.for.today",
+                    "Loan reamortization can only be done once a day. There 
has already been a reamortization done for today",
+                    loan.getId());
+        }
     }
 
     public void validateUndoReAmortize(Loan loan, JsonCommand command) {
-        // TODO: implement
+        validateUndoReAmortizeBusinessRules(loan);
+    }
+
+    private void validateUndoReAmortizeBusinessRules(Loan loan) {
+        // validate if there's a reamortization transaction already
+        Optional<LoanTransaction> optionalReAmortizationTx = 
loan.getLoanTransactions().stream().filter(tx -> tx.getTypeOf().isReAmortize())
+                
.min(Comparator.comparing(LoanTransaction::getTransactionDate));
+        if (optionalReAmortizationTx.isEmpty()) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.reamortization.transaction.missing",
+                    "Undoing a reamortization can only be done if there was a 
reamortization already", loan.getId());
+        }
+
+        // validate if there's no payment between the reamortization and today
+        boolean repaymentExistsAfterReAmortization = 
loan.getLoanTransactions().stream()
+                .anyMatch(tx -> tx.getTypeOf().isRepaymentType() && 
transactionHappenedAfterOther(tx, optionalReAmortizationTx.get()));
+        if (repaymentExistsAfterReAmortization) {
+            throw new 
GeneralPlatformDomainRuleException("error.msg.loan.reamortize.repayment.exists.after.reamortization",
+                    "Undoing a reamortization can only be done if there hasn't 
been any repayment afterwards", loan.getId());
+        }
+    }
+
+    private void throwExceptionIfValidationErrorsExist(List<ApiParameterError> 
dataValidationErrors) {
+        if (!dataValidationErrors.isEmpty()) {
+            throw new 
PlatformApiDataValidationException("validation.msg.validation.errors.exist", 
"Validation errors exist.",
+                    dataValidationErrors);
+        }
+    }
+
+    private boolean transactionHappenedAfterOther(LoanTransaction transaction, 
LoanTransaction otherTransaction) {
+        return new ChargeOrTransaction(transaction).compareTo(new 
ChargeOrTransaction(otherTransaction)) > 0;
     }
 }
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
new file mode 100644
index 000000000..fa95c4b00
--- /dev/null
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java
@@ -0,0 +1,294 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.service.reamortization;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+import java.time.Clock;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.domain.ActionContext;
+import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
+import 
org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
+import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor;
+import 
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
+import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class LoanReAmortizationValidatorTest {
+
+    private final LocalDate actualDate = LocalDate.now(Clock.systemUTC());
+
+    private LoanReAmortizationValidator underTest = new 
LoanReAmortizationValidator();
+
+    @BeforeEach
+    public void setUp() {
+        ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, 
"default", "Default", "Asia/Kolkata", null));
+        ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
+        ThreadLocalContextUtil.setBusinessDates(new 
HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate)));
+    }
+
+    @AfterEach
+    public void tearDown() {
+        ThreadLocalContextUtil.reset();
+    }
+
+    @Test
+    public void testValidateReAmortize_ShouldNotThrowException() {
+        // given
+        Loan loan = loan();
+        JsonCommand command = jsonCommand();
+        // when
+        underTest.validateReAmortize(loan, command);
+        // then no exception thrown
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenExternalIdIsLongerThan100() {
+        // given
+        Loan loan = loan();
+        JsonCommand command = 
jsonCommand(RandomStringUtils.randomAlphabetic(120));
+        // when
+        PlatformApiDataValidationException result = 
assertThrows(PlatformApiDataValidationException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanIsAfterMaturity() {
+        // given
+        Loan loan = loan();
+        given(loan.getMaturityDate()).willReturn(actualDate.minusDays(2));
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.cannot.be.submitted.after.maturity");
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanIsOnCumulativeSchedule() {
+        // given
+        Loan loan = loan();
+        
given(loan.getLoanProductRelatedDetail().getLoanScheduleType()).willReturn(LoanScheduleType.CUMULATIVE);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        assertThat(result.getGlobalisationMessageCode())
+                
.isEqualTo("error.msg.loan.reamortize.supported.only.for.progressive.loan.schedule.type");
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanIsNotOnAdvancedPaymentAllocation()
 {
+        // given
+        Loan loan = loan();
+        given(loan.getTransactionProcessingStrategyCode())
+                
.willReturn(DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.STRATEGY_CODE);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        assertThat(result.getGlobalisationMessageCode())
+                
.isEqualTo("error.msg.loan.reamortize.supported.only.for.progressive.loan.schedule.type");
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanIsInterestBearing() {
+        // given
+        Loan loan = loan();
+        given(loan.isInterestBearing()).willReturn(true);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.supported.only.for.non.interest.loans");
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanIsNotActive() {
+        // given
+        Loan loan = loan();
+        given(loan.getStatus()).willReturn(LoanStatus.APPROVED);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.supported.only.for.active.loans");
+    }
+
+    @Test
+    public void 
testValidateReAmortize_ShouldThrowException_WhenLoanAlreadyHasReAmortizationForToday()
 {
+        // given
+        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(2)),
+                loanTransaction(LoanTransactionType.REAMORTIZE, actualDate));
+        Loan loan = loan();
+        given(loan.getLoanTransactions()).willReturn(transactions);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        assertThat(result.getGlobalisationMessageCode())
+                
.isEqualTo("error.msg.loan.reamortize.reamortize.transaction.already.present.for.today");
+    }
+
+    @Test
+    public void 
testValidateUndoReAmortize_ShouldThrowException_WhenLoanDoesntHaveReAmortization()
 {
+        // given
+        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(3)));
+        Loan loan = loan();
+        given(loan.getLoanTransactions()).willReturn(transactions);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateUndoReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.reamortization.transaction.missing");
+    }
+
+    @Test
+    public void 
testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization()
 {
+        // given
+        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(3)),
+                loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(2)),
+                loanTransaction(LoanTransactionType.REPAYMENT, 
actualDate.minusDays(1)));
+        Loan loan = loan();
+        given(loan.getLoanTransactions()).willReturn(transactions);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateUndoReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
+    }
+
+    @Test
+    public void 
testValidateUndoReAmortize_ShouldThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay()
 {
+        // given
+        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(2)),
+                loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(1),
+                        OffsetDateTime.of(actualDate, LocalTime.of(10, 0), 
ZoneOffset.UTC)),
+                loanTransaction(LoanTransactionType.REPAYMENT, 
actualDate.minusDays(1),
+                        OffsetDateTime.of(actualDate, LocalTime.of(11, 0), 
ZoneOffset.UTC)));
+        Loan loan = loan();
+        given(loan.getLoanTransactions()).willReturn(transactions);
+        JsonCommand command = jsonCommand();
+        // when
+        GeneralPlatformDomainRuleException result = 
assertThrows(GeneralPlatformDomainRuleException.class,
+                () -> underTest.validateUndoReAmortize(loan, command));
+        // then
+        assertThat(result).isNotNull();
+        
assertThat(result.getGlobalisationMessageCode()).isEqualTo("error.msg.loan.reamortize.repayment.exists.after.reamortization");
+    }
+
+    @Test
+    public void 
testValidateUndoReAmortize_ShouldNotThrowException_WhenLoanAlreadyHasRepaymentAfterReAmortization_SameDay_RepaymentBeforeReAmortization()
 {
+        // given
+        List<LoanTransaction> transactions = 
List.of(loanTransaction(LoanTransactionType.DISBURSEMENT, 
actualDate.minusDays(2)),
+                loanTransaction(LoanTransactionType.REAMORTIZE, 
actualDate.minusDays(1),
+                        OffsetDateTime.of(actualDate, LocalTime.of(10, 0), 
ZoneOffset.UTC)),
+                loanTransaction(LoanTransactionType.REPAYMENT, 
actualDate.minusDays(1),
+                        OffsetDateTime.of(actualDate, LocalTime.of(9, 0), 
ZoneOffset.UTC)));
+        Loan loan = loan();
+        given(loan.getLoanTransactions()).willReturn(transactions);
+        JsonCommand command = jsonCommand();
+        // when
+        underTest.validateUndoReAmortize(loan, command);
+        // then no exception thrown
+    }
+
+    private JsonCommand jsonCommand() {
+        return jsonCommand("123456");
+    }
+
+    private JsonCommand jsonCommand(String externalId) {
+        String json = """
+                {
+                    "externalId": "%s"
+                }
+                """.formatted(externalId);
+        FromJsonHelper fromJsonHelper = new FromJsonHelper();
+        return new JsonCommand(1L, fromJsonHelper.parse(json), fromJsonHelper);
+    }
+
+    private LoanTransaction loanTransaction(LoanTransactionType type, 
LocalDate txDate, OffsetDateTime creationTime) {
+        LoanTransaction loanTransaction = loanTransaction(type, txDate);
+        given(loanTransaction.getCreatedDateTime()).willReturn(creationTime);
+        return loanTransaction;
+    }
+
+    private LoanTransaction loanTransaction(LoanTransactionType type, 
LocalDate txDate) {
+        LoanTransaction loanTransaction = mock(LoanTransaction.class);
+        given(loanTransaction.getTypeOf()).willReturn(type);
+        given(loanTransaction.getTransactionDate()).willReturn(txDate);
+        given(loanTransaction.getSubmittedOnDate()).willReturn(txDate);
+        return loanTransaction;
+    }
+
+    private Loan loan() {
+        Loan loan = mock(Loan.class);
+        given(loan.getStatus()).willReturn(LoanStatus.ACTIVE);
+        given(loan.getMaturityDate()).willReturn(actualDate.plusDays(30));
+        given(loan.getTransactionProcessingStrategyCode())
+                
.willReturn(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
+        LoanProductRelatedDetail loanProductRelatedDetail = 
mock(LoanProductRelatedDetail.class);
+        
given(loan.getLoanProductRelatedDetail()).willReturn(loanProductRelatedDetail);
+        
given(loanProductRelatedDetail.getLoanScheduleType()).willReturn(LoanScheduleType.PROGRESSIVE);
+        given(loan.isInterestBearing()).willReturn(false);
+        given(loan.getLoanTransactions()).willReturn(List.of());
+        return loan;
+    }
+
+}
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java
index 20fae1996..c5a64bfc2 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reaging/LoanReAgingIntegrationTest.java
@@ -27,6 +27,7 @@ import org.apache.fineract.client.models.PostLoansRequest;
 import org.apache.fineract.client.models.PostLoansResponse;
 import org.apache.fineract.integrationtests.BaseLoanIntegrationTest;
 import org.apache.fineract.integrationtests.common.ClientHelper;
+import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
 import org.junit.jupiter.api.Test;
 
 public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
@@ -43,7 +44,7 @@ public class LoanReAgingIntegrationTest extends 
BaseLoanIntegrationTest {
             int repaymentEvery = 1;
 
             // Create Loan Product
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
+            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
 //
                     .numberOfRepayments(numberOfRepayments) //
                     .repaymentEvery(repaymentEvery) //
                     
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
@@ -55,6 +56,7 @@ public class LoanReAgingIntegrationTest extends 
BaseLoanIntegrationTest {
             double amount = 1250.0;
 
             PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductId, "01 January 2023", amount, numberOfRepayments)//
+                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
                     .repaymentEvery(repaymentEvery)//
                     .loanTermFrequency(numberOfRepayments)//
                     .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
@@ -112,7 +114,7 @@ public class LoanReAgingIntegrationTest extends 
BaseLoanIntegrationTest {
             int repaymentEvery = 1;
 
             // Create Loan Product
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
+            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
 //
                     .numberOfRepayments(numberOfRepayments) //
                     .repaymentEvery(repaymentEvery) //
                     
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
@@ -124,6 +126,7 @@ public class LoanReAgingIntegrationTest extends 
BaseLoanIntegrationTest {
             double amount = 1250.0;
 
             PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductId, "01 January 2023", amount, numberOfRepayments)//
+                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
                     .repaymentEvery(repaymentEvery)//
                     .loanTermFrequency(numberOfRepayments)//
                     .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
index fd3946931..d902baf85 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
@@ -27,6 +27,7 @@ import org.apache.fineract.client.models.PostLoansRequest;
 import org.apache.fineract.client.models.PostLoansResponse;
 import org.apache.fineract.integrationtests.BaseLoanIntegrationTest;
 import org.apache.fineract.integrationtests.common.ClientHelper;
+import 
org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
 import org.junit.jupiter.api.Test;
 
 public class LoanReAmortizationIntegrationTest extends BaseLoanIntegrationTest 
{
@@ -39,11 +40,11 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // Create Client
             Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
 
-            int numberOfRepayments = 1;
+            int numberOfRepayments = 2;
             int repaymentEvery = 1;
 
             // Create Loan Product
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
+            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
 //
                     .numberOfRepayments(numberOfRepayments) //
                     .repaymentEvery(repaymentEvery) //
                     
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
@@ -55,6 +56,7 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             double amount = 1250.0;
 
             PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductId, "01 January 2023", amount, numberOfRepayments)//
+                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
                     .repaymentEvery(repaymentEvery)//
                     .loanTermFrequency(numberOfRepayments)//
                     .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
@@ -78,7 +80,8 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // verify schedule
             verifyRepaymentSchedule(loanId, //
                     installment(0, null, "01 January 2023"), //
-                    installment(1250.0, false, "01 February 2023") //
+                    installment(625.0, false, "01 February 2023"), //
+                    installment(625.0, false, "01 March 2023") //
             );
 
             createdLoanId.set(loanId);
@@ -93,7 +96,7 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // verify transactions
             verifyTransactions(loanId, //
                     transaction(1250.0, "Disbursement", "01 January 2023"), //
-                    transaction(1250.0, "Re-amortize", "02 February 2023") //
+                    transaction(625.0, "Re-amortize", "02 February 2023") //
             );
 
             // TODO: verify installments when schedule generation is 
implemented
@@ -108,11 +111,11 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // Create Client
             Long clientId = 
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
 
-            int numberOfRepayments = 1;
+            int numberOfRepayments = 2;
             int repaymentEvery = 1;
 
             // Create Loan Product
-            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
+            PostLoanProductsRequest product = 
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
 //
                     .numberOfRepayments(numberOfRepayments) //
                     .repaymentEvery(repaymentEvery) //
                     
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
@@ -124,6 +127,7 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             double amount = 1250.0;
 
             PostLoansRequest applicationRequest = applyLoanRequest(clientId, 
loanProductId, "01 January 2023", amount, numberOfRepayments)//
+                    
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
                     .repaymentEvery(repaymentEvery)//
                     .loanTermFrequency(numberOfRepayments)//
                     .repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
@@ -147,7 +151,8 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // verify schedule
             verifyRepaymentSchedule(loanId, //
                     installment(0, null, "01 January 2023"), //
-                    installment(1250.0, false, "01 February 2023") //
+                    installment(625.0, false, "01 February 2023"), //
+                    installment(625.0, false, "01 March 2023") //
             );
 
             createdLoanId.set(loanId);
@@ -162,20 +167,20 @@ public class LoanReAmortizationIntegrationTest extends 
BaseLoanIntegrationTest {
             // verify transactions
             verifyTransactions(loanId, //
                     transaction(1250.0, "Disbursement", "01 January 2023"), //
-                    transaction(1250.0, "Re-amortize", "02 February 2023") //
+                    transaction(625.0, "Re-amortize", "02 February 2023") //
             );
         });
 
         runAt("03 February 2023", () -> {
             long loanId = createdLoanId.get();
 
-            // create re-amortize transaction
+            // undo re-amortize transaction
             undoReAmortizeLoan(loanId);
 
             // verify transactions
             verifyTransactions(loanId, //
                     transaction(1250.0, "Disbursement", "01 January 2023"), //
-                    reversedTransaction(1250.0, "Re-amortize", "02 February 
2023") //
+                    reversedTransaction(625.0, "Re-amortize", "02 February 
2023") //
             );
 
             // TODO: verify installments when schedule generation is 
implemented

Reply via email to