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
commit 83905d627d98fcbc3b3bb643de111e6ef08410cf Author: mark.vituska <[email protected]> AuthorDate: Tue Jun 3 12:55:01 2025 +0200 FINERACT-2181: fix name collision in swagger resources --- .../InternalProgressiveLoanApiResource.java | 8 -- .../InternalProgressiveLoanApiResourceSwagger.java | 126 --------------------- .../LoanRescheduleRequestTest.java | 78 +++++++++++++ .../ProgressiveLoanModelIntegrationTest.java | 90 --------------- .../common/LoanRescheduleRequestHelper.java | 5 + 5 files changed, 83 insertions(+), 224 deletions(-) diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java index 7485d14114..61e5a9d388 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResource.java @@ -21,10 +21,6 @@ package org.apache.fineract.portfolio.loanaccount.service; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; @@ -80,8 +76,6 @@ public class InternalProgressiveLoanApiResource implements InitializingBean { @Produces({ MediaType.APPLICATION_JSON }) @Path("{loanId}/model") @Operation(summary = "Fetch ProgressiveLoanInterestScheduleModel", description = "DO NOT USE THIS IN PRODUCTION!") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = InternalProgressiveLoanApiResourceSwagger.ProgressiveLoanInterestScheduleModel.class))) }) public String fetchModel(@PathParam("loanId") @Parameter(description = "loanId") long loanId) { Loan loan = loanRepository.findOneWithNotFoundDetection(loanId); if (!loan.isProgressiveSchedule()) { @@ -116,8 +110,6 @@ public class InternalProgressiveLoanApiResource implements InitializingBean { @Path("{loanId}/model") @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update and Save ProgressiveLoanInterestScheduleModel", description = "DO NOT USE THIS IN PRODUCTION!") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = InternalProgressiveLoanApiResourceSwagger.ProgressiveLoanInterestScheduleModel.class))) }) public String updateModel(@PathParam("loanId") @Parameter(description = "loanId") long loanId) { Loan loan = loanRepository.findOneWithNotFoundDetection(loanId); if (!loan.isProgressiveSchedule()) { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResourceSwagger.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResourceSwagger.java deleted file mode 100644 index 9c249db68b..0000000000 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InternalProgressiveLoanApiResourceSwagger.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * 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; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import java.util.TreeSet; -import org.apache.fineract.infrastructure.core.data.EnumOptionData; - -final class InternalProgressiveLoanApiResourceSwagger { - - @Schema(description = "ProgressiveLoanInterestScheduleModel") - static final class ProgressiveLoanInterestScheduleModel { - - private ProgressiveLoanInterestScheduleModel() {} - - @Schema(example = "[]") - public List<RepaymentPeriod> repaymentPeriods; - @Schema(example = "[]") - public TreeSet<InterestRate> interestRates; - @Schema(example = "{}") - public Map<Integer, List<LoanTermVariationsData>> loanTermVariations; - @Schema(example = "1") - public Integer installmentAmountInMultiplesOf; - @Schema(example = "{}") - public Map<Integer, Boolean> modifiers; - } - - @Schema(description = "Interest Period") - static final class InterestPeriod { - - private InterestPeriod() {} - - @Schema(example = "01/01/2024") - public String fromDate; - @Schema(example = "01/09/2024") - public String dueDate; - @Schema(example = "0.9636548454") - public BigDecimal rateFactor; - @Schema(example = "0.9456878987") - public BigDecimal rateFactorTillPeriodDueDate; - @Schema(example = "0.0") - public BigDecimal chargebackPrincipal; - @Schema(example = "0.0") - public BigDecimal chargebackInterest; - @Schema(example = "1000.0") - public BigDecimal disbursementAmount; - @Schema(example = "3.38") - public BigDecimal balanceCorrectionAmount; - @Schema(example = "865.71") - public BigDecimal outstandingLoanBalance; - @Schema(example = "false") - public boolean isPaused; - } - - @Schema(description = "Repayment Period") - static final class RepaymentPeriod { - - private RepaymentPeriod() {} - - @Schema(example = "01/01/2024") - public String fromDate; - @Schema(example = "01/02/2024") - public String dueDate; - @Schema(example = "[]") - public List<InterestPeriod> interestPeriods; - @Schema(example = "127.04") - public BigDecimal emi; - @Schema(example = "127.04") - public BigDecimal originalEmi; - @Schema(example = "104.04") - public BigDecimal paidPrincipal; - @Schema(example = "23.00") - public BigDecimal paidInterest; - } - - @Schema(description = "Interest Rate") - static final class InterestRate { - - private InterestRate() {} - - @Schema(example = "21/12/2024") - public String effectiveFrom; - @Schema(example = "7.963") - public BigDecimal interestRate; - } - - @Schema(description = "Loan Term Variations Data") - static final class LoanTermVariationsData { - - private LoanTermVariationsData() {} - - @Schema(example = "12345") - public Long id; - @Schema(example = "null") - public EnumOptionData termType; - @Schema(example = "21/12/2024") - public String termVariationApplicableFrom; - @Schema(example = "1.20") - public BigDecimal decimalValue; - @Schema(example = "21/12/2024") - public String dateValue; - @Schema(example = "true") - public boolean isSpecificToInstallment; - @Schema(example = "true") - public Boolean isProcessed; - } -} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java index 0c5a9551eb..9cac88e05c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.integrationtests; +import static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.DEFAULT_STRATEGY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -34,10 +35,12 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import org.apache.fineract.client.models.AdvancedPaymentData; +import org.apache.fineract.client.models.GetLoanRescheduleRequestResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostClientsResponse; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PostLoansResponse; @@ -398,6 +401,31 @@ public class LoanRescheduleRequestTest extends BaseLoanIntegrationTest { }); } + @Test + public void testLoanTermVariationDeserializesProperly() { + PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()); + Long commonLoanProductId = createLoanProductPeriodicWithInterest(); + + AtomicReference<Long> loanIdRef = new AtomicReference<>(); + runAt("01 March 2024", () -> { + Long loanId = applyForLoanApplicationWithInterest(client.getClientId(), commonLoanProductId, BigDecimal.valueOf(4000), + "1 March 2023", "1 March 2024"); + loanIdRef.set(loanId); + loanTransactionHelper.approveLoan("1 March 2024", loanId.intValue()); + + loanTransactionHelper.disburseLoan("1 March 2024", loanId.intValue(), "400", null); + + PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper + .createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanIdRef.get()).dateFormat(DATETIME_PATTERN) + .locale("en").submittedOnDate("1 March 2024").newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L) + .rescheduleFromDate("1 April 2024")); + + GetLoanRescheduleRequestResponse getLoanRescheduleRequestResponse = Assertions.assertDoesNotThrow( + () -> loanRescheduleRequestHelper.readLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(), null)); + Assertions.assertNotNull(getLoanRescheduleRequestResponse); + }); + } + private Integer createProgressiveLoanProduct() { AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT"); final String loanProductJSON = new LoanProductTestBuilder().withNumberOfRepayments(numberOfRepayments) @@ -501,4 +529,54 @@ public class LoanRescheduleRequestTest extends BaseLoanIntegrationTest { .withDaysInYear("365").withMoratorium("0", "0").build(null); return loanTransactionHelper.getLoanProductId(loanProductJSON); } + + private Long createLoanProductPeriodicWithInterest() { + String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6); + String shortName = Utils.uniqueRandomStringGenerator("", 4); + Long resourceId = loanTransactionHelper.createLoanProduct(new PostLoanProductsRequest() // + .name(name) // + .shortName(shortName) // + .multiDisburseLoan(true) // + .maxTrancheCount(2) // + .interestType(InterestType.DECLINING_BALANCE) // + .interestCalculationPeriodType(InterestCalculationPeriodType.DAILY) // + .disallowExpectedDisbursements(true) // + .description("Test loan description") // + .currencyCode("USD") // + .digitsAfterDecimal(2) // + .daysInYearType(DaysInYearType.ACTUAL) // + .daysInMonthType(DaysInYearType.ACTUAL) // + .interestRecalculationCompoundingMethod(0) // + .recalculationRestFrequencyType(1) // + .rescheduleStrategyMethod(1) // + .recalculationRestFrequencyInterval(0) // + .isInterestRecalculationEnabled(false) // + .interestRateFrequencyType(2) // + .locale("en_GB") // + .numberOfRepayments(4) // + .repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()) // + .interestRatePerPeriod(2.0) // + .repaymentEvery(1) // + .minPrincipal(100.0) // + .principal(1000.0) // + .maxPrincipal(10000000.0) // + .amortizationType(AmortizationType.EQUAL_INSTALLMENTS) // + .dateFormat(DATETIME_PATTERN) // + .transactionProcessingStrategyCode(DEFAULT_STRATEGY) // + .accountingRule(1)) // + .getResourceId(); + return resourceId; + } + + private Long applyForLoanApplicationWithInterest(final Long clientId, final Long loanProductId, BigDecimal principal, + String submittedOnDate, String expectedDisburmentDate) { + final PostLoansRequest loanRequest = new PostLoansRequest() // + .loanTermFrequency(4).locale("en_GB").loanTermFrequencyType(2).numberOfRepayments(4).repaymentFrequencyType(2) + .interestRatePerPeriod(BigDecimal.valueOf(2)).repaymentEvery(1).principal(principal).amortizationType(1).interestType(1) + .interestCalculationPeriodType(0).dateFormat("dd MMMM yyyy").transactionProcessingStrategyCode(DEFAULT_STRATEGY) + .loanType("individual").submittedOnDate(submittedOnDate).expectedDisbursementDate(expectedDisburmentDate).clientId(clientId) + .productId(loanProductId); + Long loanId = loanTransactionHelper.applyLoan(loanRequest).getLoanId(); + return loanId; + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanModelIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanModelIntegrationTest.java deleted file mode 100644 index ed0c17a921..0000000000 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ProgressiveLoanModelIntegrationTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * 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 java.util.concurrent.atomic.AtomicLong; -import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.ProgressiveLoanInterestScheduleModel; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -@Slf4j -public class ProgressiveLoanModelIntegrationTest extends BaseLoanIntegrationTest { - - private final Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); - private final Long loanProductId = loanProductHelper.createLoanProduct(create4IProgressive().isInterestRecalculationEnabled(true)) - .getResourceId(); - - @Test - public void testModelReturnsSavedModelAfterDisbursement() { - AtomicLong loanIdA = new AtomicLong(); - runAt("1 January 2024", () -> { - Long loanId = applyAndApproveProgressiveLoan(clientId, loanProductId, "1 January 2024", 1000.0, 96.32, 6, null); - loanIdA.set(loanId); - log.info("Testing on loanId: {}", loanId); - loanTransactionHelper.disburseLoan(loanId, "1 January 2024", 1000.0); - // Model saved automatically, fetching it. It should return non null - ProgressiveLoanInterestScheduleModel model = assertNotNullAndChanged(null, loanId); - loanTransactionHelper.makeLoanRepayment(loanId, "Repayment", "1 January 2024", 12.78); - model = assertNotNullAndChanged(model, loanId); - assertNotNullAndSame(model, loanId); - }); - runAt("28 February 2024", () -> { - Long loanId = loanIdA.get(); - GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); - BigDecimal totalUnpaidPayableNotDueInterest = loanDetails.getSummary().getTotalUnpaidPayableNotDueInterest(); - BigDecimal totalUnpaidDueInterest = loanDetails.getSummary().getTotalUnpaidPayableDueInterest(); - - Assertions.assertEquals(73.78, totalUnpaidPayableNotDueInterest.doubleValue(), 0.001); - Assertions.assertEquals(79.24, totalUnpaidDueInterest.doubleValue(), 0.001); - }); - } - - private ProgressiveLoanInterestScheduleModel assertNotNullAndChanged(ProgressiveLoanInterestScheduleModel prev, Long loanId) { - return assertNotNullAndChanged(prev, ok(fineractClient().progressiveLoanApi.fetchModel(loanId))); - } - - private ProgressiveLoanInterestScheduleModel assertNotNullAndSame(ProgressiveLoanInterestScheduleModel prev, Long loanId) { - return assertNotNullAndSame(prev, ok(fineractClient().progressiveLoanApi.fetchModel(loanId))); - } - - private ProgressiveLoanInterestScheduleModel assertNotNullAndSame(ProgressiveLoanInterestScheduleModel prev, - ProgressiveLoanInterestScheduleModel actual) { - if (actual == null) { - Assertions.fail("Model is null"); - } - Assertions.assertEquals(prev.toString(), actual.toString()); - return actual; - } - - private ProgressiveLoanInterestScheduleModel assertNotNullAndChanged(ProgressiveLoanInterestScheduleModel prev, - ProgressiveLoanInterestScheduleModel actual) { - if (actual == null) { - Assertions.fail("Model is null"); - } - if (prev != null) { - Assertions.assertNotEquals(prev.toString(), actual.toString()); - } - return actual; - } - -} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java index fa2c3eb7f6..e7a2d17403 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java @@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.HashMap; +import org.apache.fineract.client.models.GetLoanRescheduleRequestResponse; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse; import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest; @@ -89,6 +90,10 @@ public class LoanRescheduleRequestHelper { return Utils.performServerGet(requestSpec, responseSpec, URL, param); } + public GetLoanRescheduleRequestResponse readLoanRescheduleRequest(final Long requestId, final String param) { + return Calls.ok(FineractClientHelper.getFineractClient().rescheduleLoans.readLoanRescheduleRequest(requestId, param)); + } + // TODO: Rewrite to use fineract-client instead! // Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long, // org.apache.fineract.client.models.PostLoansLoanIdRequest)
