From e848160dd06fc66eaae00f93a86caa0061d8b193 Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Fri, 11 Oct 2024 01:44:22 +0200 Subject: [PATCH] FINERACT-1981: Progressive loan enable backdated transactions --- .../portfolio/loanaccount/domain/Loan.java | 4 +- .../LoanChargeWritePlatformServiceImpl.java | 5 +- ...anTransactionBackdatedProgressiveTest.java | 108 ++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionBackdatedProgressiveTest.java diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 82f58a30834..a99c7ecb73b 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -132,6 +132,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod; import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType; import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; @@ -3816,7 +3817,8 @@ private void validateActivityNotBeforeClientOrGroupTransferDate(final LoanEvent } private void validateActivityNotBeforeLastTransactionDate(final LoanEvent event, final LocalDate activityDate) { - if (!(this.repaymentScheduleDetail().isInterestRecalculationEnabled() || this.loanProduct().isHoldGuaranteeFunds())) { + if (!(this.repaymentScheduleDetail().isInterestRecalculationEnabled() || this.loanProduct().isHoldGuaranteeFunds()) + || !this.getLoanRepaymentScheduleDetail().getLoanScheduleType().equals(LoanScheduleType.CUMULATIVE)) { return; } LocalDate lastTransactionDate = getLastUserTransactionDate(); 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 773116fdb27..64203628057 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 @@ -125,6 +125,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeApiJsonValidator; import org.apache.fineract.portfolio.loanproduct.data.LoanOverdueDTO; @@ -998,7 +999,9 @@ private void validateAddLoanCharge(final Loan loan, final Charge chargeDefinitio chargeDefinition.getName()); } else if (loanCharge.getDueLocalDate() != null) { // TODO: Review, error message seems not valid if interest recalculation is not enabled. - LocalDate validationDate = loan.repaymentScheduleDetail().isInterestRecalculationEnabled() ? loan.getLastUserTransactionDate() + boolean isCumulative = loan.getLoanRepaymentScheduleDetail().getLoanScheduleType().equals(LoanScheduleType.CUMULATIVE); + LocalDate validationDate = loan.repaymentScheduleDetail().isInterestRecalculationEnabled() && isCumulative + ? loan.getLastUserTransactionDate() : loan.getDisbursementDate(); if (DateUtils.isBefore(loanCharge.getDueLocalDate(), validationDate)) { final String defaultUserMessage = "charge with date before last transaction date can not be added to loan."; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionBackdatedProgressiveTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionBackdatedProgressiveTest.java new file mode 100644 index 00000000000..e5f520d123c --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionBackdatedProgressiveTest.java @@ -0,0 +1,108 @@ +/** + * 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.integrationtests; + +import java.math.BigDecimal; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; +import org.apache.fineract.client.models.PostLoansResponse; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@Slf4j +@ExtendWith({ LoanTestLifecycleExtension.class }) +public class LoanTransactionBackdatedProgressiveTest extends BaseLoanIntegrationTest { + + private Long clientId; + private Long loanId; + + @BeforeEach + public void beforeEach() { + runAt("01 July 2024", () -> { + clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive()); + PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan( + applyPin4ProgressiveLoanRequest(clientId, loanProductsResponse.getResourceId(), "01 June 2024", 1000.0, 10.0, 4, null)); + loanId = postLoansResponse.getLoanId(); + loanTransactionHelper.approveLoan(loanId, approveLoanRequest(1000.0, "01 June 2024")); + disburseLoan(loanId, BigDecimal.valueOf(250.0), "01 June 2024"); + addRepaymentForLoan(loanId, 100.0, "10 June 2024"); + }); + } + + @Test + public void testProgressiveBackdatedDisbursement() { + runAt("01 July 2024", () -> { + disburseLoan(loanId, BigDecimal.valueOf(250.0), "5 June 2024"); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertEquals(loanDetails.getDisbursementDetails().size(), 2); + }); + } + + @Test + public void testProgressiveBackdatedRepayment() { + runAt("01 July 2024", () -> { + addRepaymentForLoan(loanId, 100.0, "5 June 2024"); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertTrue(loanDetails.getTransactions().size() >= 2); + }); + } + + @Test + public void testProgressiveBackdatedMerchantIssuedRefund() { + runAt("01 July 2024", () -> { + loanTransactionHelper.makeMerchantIssuedRefund(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN) + .transactionDate("5 June 2024").locale("en").transactionAmount(100.0)); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertTrue(loanDetails.getTransactions().size() >= 2); + }); + } + + @Test + public void testProgressiveBackdatedPayoutRefund() { + runAt("01 July 2024", () -> { + loanTransactionHelper.makePayoutRefund(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN) + .transactionDate("5 June 2024").locale("en").transactionAmount(100.0)); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertTrue(loanDetails.getTransactions().size() >= 2); + }); + } + + @Test + public void testProgressiveBackdatedGoodwillCredit() { + runAt("01 July 2024", () -> { + loanTransactionHelper.makeGoodwillCredit(loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN) + .transactionDate("5 June 2024").locale("en").transactionAmount(100.0)); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertTrue(loanDetails.getTransactions().size() >= 2); + }); + } + +}