From 27c11173609e15f5b4a49f94f01d1dae98b2d00b Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:19:05 +0530 Subject: [PATCH 01/15] FINERACT-2779: fix loan swagger DTOs and retire the REST-assured command paths FeignLoanHelper drove the server through REST-assured for six loan commands, so every test taking those paths was Feign in name only. The gaps that forced them are fixed at source rather than worked around: PostLoansRequest += calendarId, syncDisbursementWithMeeting, createStandingInstructionAtDisbursement, interestChargedFromDate PostLoansRequest.repaymentsStartingFromDate LocalDate -> String PostLoansLoanIdDisbursementData.expectedDisbursementDate LocalDate -> String PostCreateRescheduleLoansRequest += recalculateInterest PostProvisioningCriteriaRequest += definitions, locale Both date fields were declared LocalDate while the same request body declares dateFormat "dd MMMM yyyy", so a generated client serialised ISO and the server rejected it. Their response-side twins were already String; the schema example "[2012, 4, 3]" was the bug frozen into the spec. Only the format changes, so the wire payload is unchanged and swagger-brake reports no breaking change. Adding the fields made two workaround subclasses redundant - RescheduleRequestWithRecalculateInterest and ApplyLoanWithLegacyDates, both of which existed solely because "the generated OpenAPI model omits this field". Error Prone found them via MissingOverride once the real setters appeared. disburseToSavings, disburseLoanFromJson and the reschedule create now call the typed client. The JSON builders they used silently injected a note and a netDisbursalAmount, so those are set explicitly at the call sites to keep the payload identical. createRescheduleRequestWithFullResponse returned an untyped HashMap and took an expected status code; it is now FeignCalls.fail(...) with the status asserted at the call site. The specific error code lives in errors[0], not the top-level userMessageGlobalisationCode, so the assertion goes through FeignLoanTestBase.extractErrorGlobalisationCode. Signed-off-by: DeathGun44 --- .../RescheduleLoansApiResourceSwagger.java | 2 + .../api/LoansApiResourceSwagger.java | 18 +- ...ientLoanChargeExternalIntegrationTest.java | 4 +- .../ClientLoanIntegrationTest.java | 10 +- ...ementToSavingsWithAutoDownPaymentTest.java | 2 +- .../LoanDueCalculationTest.java | 3 +- ...RepaymentRescheduleAtDisbursementTest.java | 7 +- ...nRescheduleOnDecliningBalanceLoanTest.java | 9 +- .../LoanRescheduleWithAdvancePaymentTest.java | 4 +- .../LoanReschedulingWithinCenterTest.java | 9 +- .../client/feign/FeignLoanTestBase.java | 8 +- .../client/feign/helpers/FeignLoanHelper.java | 87 +--------- .../feign/modules/LoanRequestBuilders.java | 159 +++--------------- 13 files changed, 67 insertions(+), 255 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResourceSwagger.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResourceSwagger.java index c08010ef6fd..5757acd6583 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResourceSwagger.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResourceSwagger.java @@ -204,6 +204,8 @@ public static final class PostCreateRescheduleLoansRequest { public Long rescheduleReasonId; @Schema(example = "20 September 2011") public String submittedOnDate; + @Schema(example = "true") + public Boolean recalculateInterest; } @Schema(description = "PostUpdateRescheduleLoansRequest") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index eebd8606ffe..cf30c550d68 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -1408,6 +1408,10 @@ private PostLoansRequest() {} public String daysInYearCustomStrategy; @Schema(example = "individual") public String loanType; + @Schema(example = "1", description = "Meeting calendar to attach the loan to; required for jlg loans") + public Long calendarId; + @Schema(example = "true", description = "Sync the disbursement date with the attached meeting") + public Boolean syncDisbursementWithMeeting; @Schema(example = "20 September 2011") public String submittedOnDate; @Schema(example = "786444UUUYYH7") @@ -1418,10 +1422,12 @@ private PostLoansRequest() {} public Boolean allowFullTermForTranche; @Schema(description = "Maximum allowed outstanding balance") public BigDecimal maxOutstandingLoanBalance; - @Schema(example = "[2011, 10, 20]") - public LocalDate repaymentsStartingFromDate; + @Schema(example = "20 September 2011") + public String repaymentsStartingFromDate; @Schema(example = "1") public Integer graceOnInterestCharged; + @Schema(example = "20 September 2011") + public String interestChargedFromDate; @Schema(example = "1") public Integer graceOnPrincipalPayment; @Schema(example = "1") @@ -1467,6 +1473,8 @@ private PostLoansRequest() {} public List collateral; @Schema(example = "1") public Long linkAccountId; + @Schema(example = "true", description = "Requires linkAccountId when true") + public Boolean createStandingInstructionAtDisbursement; @Schema(description = """ Optional array of originators to associate with this loan. \ @@ -1803,8 +1811,10 @@ static final class PostLoansLoanIdDisbursementData { private PostLoansLoanIdDisbursementData() {} - @Schema(example = "[2012, 4, 3]") - public LocalDate expectedDisbursementDate; + // Parsed with the request's dateFormat, like every other date on this DTO. Declaring it + // LocalDate made a generated client serialise ISO into a body declaring "dd MMMM yyyy". + @Schema(example = "1 November 2023") + public String expectedDisbursementDate; @Schema(example = "22000") public BigDecimal principal; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java index 7ca6ad7eb3d..eaabe1a0b90 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java @@ -50,7 +50,7 @@ public void checkNewClientLoanChargeSavesExternalId() { final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00"); approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011")); - disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12,000.00"); + disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId(); @@ -72,7 +72,7 @@ public void checkNewClientLoanChargeFindsDuplicateExternalId() { final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00"); approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011")); - disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12,000.00"); + disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index 5b4be76fc3d..f56a1afa2e4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -136,6 +136,8 @@ public class ClientLoanIntegrationTest extends FeignLoanTestBase { /** The loan/product JSON builders this test replaced used {@code en_GB}; keep it so number parsing is unchanged. */ private static final String LOCALE = "en_GB"; private static final String OVERRIDE_MESSAGE = "Loan overrode the product's %s"; + /** The disburse-to-savings JSON builder this test replaced always sent this note; keep the payload unchanged. */ + private static final String DISBURSE_NOTE = "DISBURSE NOTE"; /** The interoperation repayment body was built with plain {@code en}, unlike the {@code en_GB} used elsewhere. */ private static final String INTEROP_LOCALE = "en"; @@ -7298,8 +7300,9 @@ private Long applyForLoanApplicationForInterestRecalculationWithFirstRepaymentDa .expectedDisbursementDate(disbursementDate)// .submittedOnDate(disbursementDate)// .transactionProcessingStrategyCode(repaymentStrategy)// - .collateral(createClientCollateral(clientId)); - return applyForLoan(LoanRequestBuilders.applyLoanWithLegacyDates(request, null, firstRepaymentDate)); + .collateral(createClientCollateral(clientId))// + .repaymentsStartingFromDate(firstRepaymentDate); + return applyForLoan(request); } private PostLoansResponse applyForLoanApplicationForOnePeriod30DaysLongNoInterestPeriodicAccrual(Long clientId, Long loanProductId, @@ -7824,7 +7827,8 @@ private GetLoansLoanIdResponse disburseToSavingsWithNetDisbursalAmount(String da .actualDisbursementDate(date)// .dateFormat(DATETIME_PATTERN)// .locale(LOCALE)// - .netDisbursalAmount(netDisbursalAmount)); + .netDisbursalAmount(netDisbursalAmount)// + .note(DISBURSE_NOTE)); return getLoanDetails(loanId); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java index bed75243c31..0bc6b866d0a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java @@ -104,7 +104,7 @@ public void loanDisbursementToSavingsWithAutoDownPaymentAndStandingInstructionsT PostLoansLoanIdResponse responseLoanDisburseToSavings = disburseToSavings(loanId, new PostLoansLoanIdRequest().actualDisbursementDate("01 March 2023").transactionAmount(new BigDecimal("1000")) - .locale("en").dateFormat("dd MMMM yyyy")); + .netDisbursalAmount(new BigDecimal("1000")).note("DISBURSE NOTE").locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr, responseLoanDisburseToSavings.getResourceExternalId()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java index b30fbd01475..b686fff9ff2 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDueCalculationTest.java @@ -21,7 +21,6 @@ import static org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY; import java.math.BigDecimal; -import java.time.LocalDate; import java.util.stream.Stream; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; @@ -57,7 +56,7 @@ public void dueDateBasedOnFirstRepaymentDate(String repaymentProcessor) { PostLoansRequest loanRequest = applyLoanRequest(clientId, loanProductId, "2024-01-31", 1000.0, 4, (postLoansRequest) -> { postLoansRequest.transactionProcessingStrategyCode(repaymentProcessor).repaymentEvery(1).repaymentFrequencyType(2) .loanTermFrequency(4).loanTermFrequencyType(2).dateFormat(LoanTestData.ISO_DATE_PATTERN) - .repaymentsStartingFromDate(LocalDate.of(2024, 2, 29)); + .repaymentsStartingFromDate("2024-02-29"); }); Long loanId = applyForLoan(loanRequest); verifyRepaymentSchedule(loanId, installment(1000.0, null, "31 January 2024"), // diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java index f65a300a606..7835617ab72 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java @@ -27,6 +27,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansDisbursementData; +import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestValidators; @@ -53,14 +54,14 @@ public void testLoanRepaymentRescheduleAtDisbursement() { List createTranches = List.of(LoanRequestBuilders.applyTrancheDetail("01 March 2015", 5000.0), LoanRequestBuilders.applyTrancheDetail("01 May 2015", 5000.0)); - List approveTranches = List.of(LoanRequestBuilders.applyTrancheDetail("01 March 2015", 5000.0), - LoanRequestBuilders.applyTrancheDetail("01 May 2015", 5000.0)); + List approveTranches = List.of(LoanRequestBuilders.approveTrancheDetail("01 March 2015", 5000.0), + LoanRequestBuilders.approveTrancheDetail("01 May 2015", 5000.0)); Long loanId = applyForLoanFromJson(buildLoanApplicationJson(clientId, loanProductId, disbursementDate, createTranches)); verifyLoanStatus(loanId, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL); - approveLoanFromJson(loanId, LoanRequestBuilders.approveLoanWithTranchesJson(Double.valueOf(approvalAmount), approveDate, + approveLoan(loanId, LoanRequestBuilders.approveLoanWithTranches(Double.valueOf(approvalAmount), approveDate, expectedDisbursementDate, approveTranches)); GetLoansLoanIdResponse approvedLoan = getLoanDetails(loanId); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java index a7475c4312f..707a9062db7 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java @@ -22,8 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; -import java.util.List; -import java.util.Map; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; import org.apache.fineract.client.models.PostLoanProductsRequest; @@ -225,9 +224,9 @@ private void createLoanRescheduleRequestWhichFailsAsLoanIdChargedOff() { chargeOffLoan(this.loanId, "04 January 2015"); - Map response = loanHelper.createRescheduleRequestWithFullResponse(rescheduleRequest, 403); - assertEquals("error.msg.loan.is.charged.off", - ((Map) ((List) response.get("errors")).get(0)).get("userMessageGlobalisationCode")); + CallFailedRuntimeException exception = loanHelper.createRescheduleRequestExpectingError(rescheduleRequest); + assertEquals(403, exception.getStatus()); + assertEquals("error.msg.loan.is.charged.off", extractErrorGlobalisationCode(exception)); undoChargeOffLoan(this.loanId); closeRescheduledLoan(this.loanId, new PostLoansLoanIdTransactionsRequest().dateFormat(LoanTestData.DATETIME_PATTERN) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleWithAdvancePaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleWithAdvancePaymentTest.java index b518dceb093..abc1380c11e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleWithAdvancePaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleWithAdvancePaymentTest.java @@ -145,7 +145,7 @@ private void createLoanEntityWithEntitiesForTestResceduleWithLatePayment() { req.dateFormat(LoanTestData.ISO_DATE_PATTERN); req.submittedOnDate(submittedDate); req.expectedDisbursementDate(submittedDate); - req.repaymentsStartingFromDate(LocalDate.of(2021, 6, 14)); + req.repaymentsStartingFromDate("2021-06-14"); }); this.loanId = applyForLoan(applyRequest); @@ -243,7 +243,7 @@ private void createLoanEntityForTestMultipleAdvancePaymentWithReschedule() { req.dateFormat(LoanTestData.ISO_DATE_PATTERN); req.submittedOnDate(submittedDate); req.expectedDisbursementDate(submittedDate); - req.repaymentsStartingFromDate(LocalDate.of(2022, 1, 3)); + req.repaymentsStartingFromDate("2022-01-03"); }); this.loanId = applyForLoan(applyRequest); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java index 267623a50e4..ba9916c65bf 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java @@ -42,6 +42,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; +import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignCenterHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignGroupHelper; @@ -198,8 +199,9 @@ public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnab List createTranches = List.of(LoanRequestBuilders.applyTrancheDetail(disbursementDate, 5000.0), LoanRequestBuilders.applyTrancheDetail(secondDisbursement, 5000.0)); - List approveTranches = List.of(LoanRequestBuilders.applyTrancheDetail(disbursementDate, 5000.0), - LoanRequestBuilders.applyTrancheDetail(secondDisbursement, 5000.0)); + List approveTranches = List.of( + LoanRequestBuilders.approveTrancheDetail(disbursementDate, 5000.0), + LoanRequestBuilders.approveTrancheDetail(secondDisbursement, 5000.0)); Long collateralId = createCollateralProduct(); assertNotNull(collateralId); @@ -215,8 +217,7 @@ public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnab verifyLoanStatus(loanId, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL); LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - approveLoanFromJson(loanId, - LoanRequestBuilders.approveLoanWithTranchesJson(10000.0, approveDate, expectedDisbursementDate, approveTranches)); + approveLoan(loanId, LoanRequestBuilders.approveLoanWithTranches(10000.0, approveDate, expectedDisbursementDate, approveTranches)); GetLoansLoanIdResponse approvedLoan = getLoanDetails(loanId); verifyLoanStatus(approvedLoan, LoanStatus.APPROVED); verifyLoanStatus(approvedLoan, status -> Boolean.TRUE.equals(status.getWaitingForDisbursal())); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java index 236d8b0e2cc..db9b51edc53 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java @@ -1651,15 +1651,11 @@ protected PostLoansLoanIdResponse disburseLoan(Long loanId, String date, Double } protected void disburseLoanWithRepaymentReschedule(Long loanId, String date, String adjustRepaymentDate) { - loanHelper.disburseLoanFromJson(loanId, LoanRequestBuilders.disburseLoanWithRepaymentRescheduleJson(date, adjustRepaymentDate)); + loanHelper.disburseLoan(loanId, LoanRequestBuilders.disburseLoanWithRepaymentReschedule(date, adjustRepaymentDate)); } protected void disburseLoanWithNetDisbursalAmount(Long loanId, String date, String netDisbursalAmount) { - loanHelper.disburseLoanFromJson(loanId, LoanRequestBuilders.disburseLoanWithNetDisbursalAmountJson(date, netDisbursalAmount)); - } - - protected void approveLoanFromJson(Long loanId, String approveLoanJson) { - loanHelper.approveLoanFromJson(loanId, approveLoanJson); + loanHelper.disburseLoan(loanId, LoanRequestBuilders.disburseLoanWithNetDisbursalAmount(date, new BigDecimal(netDisbursalAmount))); } protected Long addRepaymentForLoan(Long loanId, Double amount, String date) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java index 31ad9426794..6aaeeed86f7 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java @@ -23,15 +23,12 @@ import static org.apache.fineract.client.feign.util.FeignCalls.ok; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.math.BigDecimal; -import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.fineract.client.feign.FineractFeignClient; @@ -85,18 +82,12 @@ import org.apache.fineract.client.models.PutLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.PutLoansLoanIdRequest; import org.apache.fineract.client.models.PutLoansLoanIdResponse; -import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.Utils; public class FeignLoanHelper { private static final String CREATE_LOAN_PRODUCT_URL = "/fineract-provider/api/v1/loanproducts?" + Utils.TENANT_IDENTIFIER; private static final String APPLY_LOAN_URL = "/fineract-provider/api/v1/loans?" + Utils.TENANT_IDENTIFIER; - private static final String LOAN_STATE_TRANSITION_URL = "/fineract-provider/api/v1/loans/%d?" + Utils.TENANT_IDENTIFIER - + "&command=approve"; - private static final String LOAN_DISBURSE_URL = "/fineract-provider/api/v1/loans/%d?" + Utils.TENANT_IDENTIFIER + "&command=disburse"; - private static final String LOAN_DISBURSE_TO_SAVINGS_URL = "/fineract-provider/api/v1/loans/%d?" + Utils.TENANT_IDENTIFIER - + "&command=disburseToSavings"; private final FineractFeignClient fineractClient; @@ -269,24 +260,12 @@ public List getLoanDelinquencyActions(String loan return ok(() -> fineractClient.loans().retrieveDelinquencyActionsLoanByExternalId(loanExternalId)); } - // TODO: Rewrite to use fineract-client instead! - public void approveLoanFromJson(Long loanId, String approveLoanJson) { - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - Utils.performServerPost(jsonRequestSpec(), responseSpec, LOAN_STATE_TRANSITION_URL.formatted(loanId), approveLoanJson, ""); - } - - // TODO: Rewrite to use fineract-client instead! - public void disburseLoanFromJson(Long loanId, String disburseLoanJson) { - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - Utils.performServerPost(jsonRequestSpec(), responseSpec, LOAN_DISBURSE_URL.formatted(loanId), disburseLoanJson, ""); - } - public PostLoansLoanIdResponse disburseLoan(Long loanId, PostLoansLoanIdRequest request) { return ok(() -> fineractClient.loans().handleCommandsLoan(loanId, request, Map.of("command", "disburse"))); } public PostLoansLoanIdResponse disburseToSavings(Long loanId, PostLoansLoanIdRequest request) { - return disburseToSavingsFromJson(loanId, toDisburseToSavingsJson(request)); + return ok(() -> fineractClient.loans().handleCommandsLoan(loanId, request, Map.of("command", "disburseToSavings"))); } public PostLoansLoanIdResponse rejectLoanByExternalId(String loanExternalId, PostLoansLoanIdRequest request) { @@ -538,43 +517,11 @@ public PutLoansAvailableDisbursementAmountResponse modifyAvailableDisbursementAm } public PostCreateRescheduleLoansResponse createRescheduleRequest(PostCreateRescheduleLoansRequest request) { - if (request instanceof LoanRequestBuilders.RescheduleRequestWithRecalculateInterest recalcRequest - && Boolean.TRUE.equals(recalcRequest.getRecalculateInterest())) { - return new PostCreateRescheduleLoansResponse().resourceId(createRescheduleRequestFromJson(toRescheduleJson(request, true))); - } return ok(() -> fineractClient.rescheduleLoans().createRescheduleLoan(request)); } - @SuppressWarnings("unchecked") - public HashMap createRescheduleRequestWithFullResponse(PostCreateRescheduleLoansRequest request, - int expectedStatusCode) { - String json = toRescheduleJson(request, - request instanceof LoanRequestBuilders.RescheduleRequestWithRecalculateInterest recalcRequest - && Boolean.TRUE.equals(recalcRequest.getRecalculateInterest())); - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(expectedStatusCode).build(); - return Utils.performServerPost(jsonRequestSpec(), responseSpec, - "/fineract-provider/api/v1/rescheduleloans?" + Utils.TENANT_IDENTIFIER, json, ""); - } - - private String toRescheduleJson(PostCreateRescheduleLoansRequest request, boolean recalculateInterest) { - ObjectMapper mapper = ObjectMapperFactory.getShared(); - ObjectNode body = mapper.valueToTree(request); - if (recalculateInterest) { - body.put("recalculateInterest", true); - } - try { - return mapper.writeValueAsString(body); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Failed to serialize reschedule request", e); - } - } - - // TODO: Rewrite to use fineract-client instead! - private Long createRescheduleRequestFromJson(String json) { - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - Integer resourceId = Utils.performServerPost(jsonRequestSpec(), responseSpec, - "/fineract-provider/api/v1/rescheduleloans?" + Utils.TENANT_IDENTIFIER, json, "resourceId"); - return resourceId.longValue(); + public CallFailedRuntimeException createRescheduleRequestExpectingError(PostCreateRescheduleLoansRequest request) { + return fail(() -> fineractClient.rescheduleLoans().createRescheduleLoan(request)); } // TODO: Rewrite to use fineract-client instead! @@ -585,34 +532,6 @@ private static RequestSpecification jsonRequestSpec() { .addHeader("Fineract-Platform-TenantId", "default").build(); } - // TODO: Rewrite to use fineract-client instead! - private PostLoansLoanIdResponse disburseToSavingsFromJson(Long loanId, String disburseJson) { - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - String response = Utils.performServerPost(jsonRequestSpec(), responseSpec, LOAN_DISBURSE_TO_SAVINGS_URL.formatted(loanId), - disburseJson, null); - try { - return ObjectMapperFactory.getShared().readValue(response, PostLoansLoanIdResponse.class); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Failed to parse disburseToSavings response", e); - } - } - - private static String toDisburseToSavingsJson(PostLoansLoanIdRequest request) { - ObjectMapper mapper = ObjectMapperFactory.getShared(); - ObjectNode body = mapper.valueToTree(request); - if (request.getTransactionAmount() != null && !body.has("netDisbursalAmount")) { - body.put("netDisbursalAmount", request.getTransactionAmount().toPlainString()); - } - if (!body.has("note")) { - body.put("note", "DISBURSE NOTE"); - } - try { - return mapper.writeValueAsString(body); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Failed to serialize disburseToSavings request", e); - } - } - public PostUpdateRescheduleLoansResponse approveRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) { return ok(() -> fineractClient.rescheduleLoans().updateRescheduleLoan(scheduleId, request, "approve")); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java index 817db107ca1..8884293d0df 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java @@ -18,16 +18,8 @@ */ package org.apache.fineract.integrationtests.client.feign.modules; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.gson.Gson; import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Stream; @@ -48,11 +40,8 @@ public final class LoanRequestBuilders { - private static final Gson GSON = new Gson(); - - private static final String KEY_LOCALE = "locale"; - private static final String KEY_DATE_FORMAT = "dateFormat"; - private static final String KEY_ACTUAL_DISBURSEMENT_DATE = "actualDisbursementDate"; + /** The JSON disburse builders this replaced always sent this note; keep the payload unchanged. */ + private static final String DISBURSE_NOTE = "DISBURSE NOTE"; private LoanRequestBuilders() {} @@ -135,23 +124,21 @@ public static PostLoansLoanIdRequest disburseLoan(Double disbursedAmount, String .dateFormat(LoanTestData.DATETIME_PATTERN); } - public static String disburseLoanWithRepaymentRescheduleJson(String disbursedOnDate, String adjustRepaymentDate) { - Map map = new LinkedHashMap<>(); - map.put(KEY_LOCALE, LoanTestData.LOCALE); - map.put(KEY_DATE_FORMAT, LoanTestData.DATETIME_PATTERN); - map.put(KEY_ACTUAL_DISBURSEMENT_DATE, disbursedOnDate); - map.put("adjustRepaymentDate", adjustRepaymentDate); - map.put("note", "DISBURSE NOTE"); - return GSON.toJson(map); + public static PostLoansLoanIdRequest disburseLoanWithRepaymentReschedule(String disbursedOnDate, String adjustRepaymentDate) { + return new PostLoansLoanIdRequest()// + .actualDisbursementDate(disbursedOnDate)// + .adjustRepaymentDate(adjustRepaymentDate)// + .note(DISBURSE_NOTE)// + .locale(LoanTestData.LOCALE)// + .dateFormat(LoanTestData.DATETIME_PATTERN); } - public static String disburseLoanWithNetDisbursalAmountJson(String disbursedOnDate, String netDisbursalAmount) { - Map map = new LinkedHashMap<>(); - map.put(KEY_LOCALE, LoanTestData.LOCALE); - map.put(KEY_DATE_FORMAT, LoanTestData.DATETIME_PATTERN); - map.put(KEY_ACTUAL_DISBURSEMENT_DATE, disbursedOnDate); - map.put("netDisbursalAmount", netDisbursalAmount); - return GSON.toJson(map); + public static PostLoansLoanIdRequest disburseLoanWithNetDisbursalAmount(String disbursedOnDate, BigDecimal netDisbursalAmount) { + return new PostLoansLoanIdRequest()// + .actualDisbursementDate(disbursedOnDate)// + .netDisbursalAmount(netDisbursalAmount)// + .locale(LoanTestData.LOCALE)// + .dateFormat(LoanTestData.DATETIME_PATTERN); } public static PostLoansDisbursementData applyTrancheDetail(String expectedDisbursementDate, double principal) { @@ -162,7 +149,7 @@ public static PostLoansDisbursementData applyTrancheDetail(String expectedDisbur public static PostLoansLoanIdDisbursementData approveTrancheDetail(String expectedDisbursementDate, double principal) { return new PostLoansLoanIdDisbursementData()// - .expectedDisbursementDate(parseDate(expectedDisbursementDate))// + .expectedDisbursementDate(expectedDisbursementDate)// .principal(BigDecimal.valueOf(principal)); } @@ -172,27 +159,6 @@ public static PostLoansLoanIdRequest approveLoanWithTranches(Double approvedAmou .disbursementData(tranches); } - public static String approveLoanWithTranchesJson(Double approvedAmount, String approvedOnDate, String expectedDisbursementDate, - List tranches) { - Map map = new LinkedHashMap<>(); - map.put("approvedLoanAmount", approvedAmount.toString()); - map.put("approvedOnDate", approvedOnDate); - map.put("expectedDisbursementDate", expectedDisbursementDate); - map.put(KEY_LOCALE, LoanTestData.LOCALE); - map.put(KEY_DATE_FORMAT, LoanTestData.DATETIME_PATTERN); - map.put("disbursementData", tranches.stream().map(tranche -> { - Map trancheMap = new LinkedHashMap<>(); - trancheMap.put("expectedDisbursementDate", tranche.getExpectedDisbursementDate()); - trancheMap.put("principal", tranche.getPrincipal().toPlainString()); - return trancheMap; - }).toList()); - return GSON.toJson(map); - } - - private static LocalDate parseDate(String date) { - return LocalDate.parse(date, DateTimeFormatter.ofPattern(LoanTestData.DATETIME_PATTERN, Locale.ENGLISH)); - } - public static PostLoansLoanIdTransactionsRequest repayLoan(Double amount, String transactionDate) { PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest(); request.setTransactionDate(transactionDate); @@ -271,60 +237,16 @@ public static PostCreateRescheduleLoansRequest rescheduleWithExtraTerms(Long loa .dateFormat(LoanTestData.DATETIME_PATTERN); } - /** - * Reschedule request with {@code recalculateInterest=true}. The generated OpenAPI model omits this field; the - * subclass ensures Gson serializes it for Feign calls. - */ public static PostCreateRescheduleLoansRequest rescheduleWithRecalculateInterest(Long loanId, String submittedOnDate, String rescheduleFromDate, String adjustedDueDate) { - return withRecalculateInterest(rescheduleRequest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate), true); + return rescheduleRequest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate).recalculateInterest(true); } public static PostCreateRescheduleLoansRequest rescheduleWithFixedEmiAndRecalculateInterest(Long loanId, String submittedOnDate, String rescheduleFromDate, String adjustedDueDate, BigDecimal emi, String emiEndDate) { - RescheduleRequestWithRecalculateInterest request = withRecalculateInterest( - rescheduleRequest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate), true); - request.setEmi(emi); - request.setEndDate(emiEndDate); - return request; - } - - private static RescheduleRequestWithRecalculateInterest withRecalculateInterest(PostCreateRescheduleLoansRequest base, - boolean recalculateInterest) { - RescheduleRequestWithRecalculateInterest request = new RescheduleRequestWithRecalculateInterest(); - request.setAdjustedDueDate(base.getAdjustedDueDate()); - request.setDateFormat(base.getDateFormat()); - request.setEmi(base.getEmi()); - request.setEndDate(base.getEndDate()); - request.setExtraTerms(base.getExtraTerms()); - request.setGraceOnInterest(base.getGraceOnInterest()); - request.setGraceOnPrincipal(base.getGraceOnPrincipal()); - request.setLoanId(base.getLoanId()); - request.setLocale(base.getLocale()); - request.setNewInterestRate(base.getNewInterestRate()); - request.setRescheduleFromDate(base.getRescheduleFromDate()); - request.setRescheduleReasonComment(base.getRescheduleReasonComment()); - request.setRescheduleReasonId(base.getRescheduleReasonId()); - request.setSubmittedOnDate(base.getSubmittedOnDate()); - request.setRecalculateInterest(recalculateInterest); - return request; - } - - /** - * Extends {@link PostCreateRescheduleLoansRequest} so {@code recalculateInterest} is included in JSON payloads. - */ - public static final class RescheduleRequestWithRecalculateInterest extends PostCreateRescheduleLoansRequest { - - @JsonProperty("recalculateInterest") - private Boolean recalculateInterest; - - public Boolean getRecalculateInterest() { - return recalculateInterest; - } - - public void setRecalculateInterest(Boolean recalculateInterest) { - this.recalculateInterest = recalculateInterest; - } + return rescheduleWithRecalculateInterest(loanId, submittedOnDate, rescheduleFromDate, adjustedDueDate)// + .emi(emi)// + .endDate(emiEndDate); } /** @@ -616,45 +538,4 @@ public static PostLoansRequest applyLP2ProgressiveLoanRequest(Long clientId, Lon return request; } - public static ApplyLoanWithLegacyDates applyLoanWithLegacyDates(PostLoansRequest base, String interestChargedFromDate, - String repaymentsStartingFromDate) { - ApplyLoanWithLegacyDates request = GSON.fromJson(GSON.toJson(base), ApplyLoanWithLegacyDates.class); - request.setInterestChargedFromDate(interestChargedFromDate); - request.setRepaymentsStartingFromDateForApply(repaymentsStartingFromDate); - return request; - } - - /** - * Carries legacy string date fields omitted from the OpenAPI loan apply model. - */ - public static final class ApplyLoanWithLegacyDates extends PostLoansRequest { - - @JsonProperty("interestChargedFromDate") - private String interestChargedFromDate; - - private String repaymentsStartingFromDateForApply; - - public String getInterestChargedFromDate() { - return interestChargedFromDate; - } - - public void setInterestChargedFromDate(String interestChargedFromDate) { - this.interestChargedFromDate = interestChargedFromDate; - } - - public void setRepaymentsStartingFromDateForApply(String repaymentsStartingFromDateForApply) { - this.repaymentsStartingFromDateForApply = repaymentsStartingFromDateForApply; - } - - @Override - @JsonIgnore - public LocalDate getRepaymentsStartingFromDate() { - return null; - } - - @JsonProperty("repaymentsStartingFromDate") - public String getRepaymentsStartingFromDateForApply() { - return repaymentsStartingFromDateForApply; - } - } } From 60a52a16e27564a5a11fded7feb33a496ee7740b Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:21:04 +0530 Subject: [PATCH 02/15] FINERACT-2779: build loan applications with PostLoansRequest instead of JSON Converts the first three applyForLoanFromJson callers to the typed model, now that PostLoansRequest carries the fields they need. LoanApplicationTestBuilder.build() is not the visible .withX() chain: it always emits maxOutstandingLoanBalance "36000", collateral [], a default transactionProcessingStrategyCode, loanType and locale "en_GB" - none of which appear at the call sites. Each conversion reproduces them, so the request body is unchanged. The jlg case in LoanReschedulingWithinCenterTest also stops round-tripping its tranches through HashMap, since the parameter was already typed. Its collateral list becomes PostLoansRequestCollateralData, which names the field quantity where the map said amount. That mismatch was harmless only because LoanApplicationValidator applies collateral to individual accounts alone and skips it for jlg; the typed name is what the server would read if that guard ever widens, and the helper says so. Signed-off-by: DeathGun44 --- ...ementToSavingsWithAutoDownPaymentTest.java | 36 ++++++--- ...nRescheduleOnDecliningBalanceLoanTest.java | 33 +++++--- .../LoanReschedulingWithinCenterTest.java | 79 ++++++++++--------- .../client/feign/modules/LoanTestData.java | 1 + 4 files changed, 91 insertions(+), 58 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java index 0bc6b866d0a..4784fa2df25 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java @@ -40,6 +40,7 @@ import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.SavingsAccountData; import org.apache.fineract.client.models.SavingsAccountTransactionData; import org.apache.fineract.infrastructure.core.service.MathUtil; @@ -49,6 +50,7 @@ import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsProductHelper; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.client.feign.modules.SavingsRequestBuilders; import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; import org.apache.fineract.integrationtests.common.accounting.FinancialActivityAccountHelper; @@ -90,16 +92,30 @@ public void loanDisbursementToSavingsWithAutoDownPaymentAndStandingInstructionsT mapLiabilityTransferFinancialActivity(loanProductId); - String loanApplicationJSON = new org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder() - .withPrincipal("1000").withLoanTermFrequency("45").withLoanTermFrequencyAsDays().withNumberOfRepayments("3") - .withRepaymentEveryAfter("15").withRepaymentFrequencyTypeAsDays().withInterestRatePerPeriod("0") - .withInterestTypeAsDecliningBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("01 March 2023") - .withSubmittedOnDate("01 March 2023").withLoanType("individual").withExternalId(loanExternalIdStr) - .withCreateStandingInstructionAtDisbursement() - .build(clientId.toString(), loanProductId.toString(), savingsAccountId.toString()); - - Long loanId = applyForLoanFromJson(loanApplicationJSON); + Long loanId = applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal("1000"))// + .loanTermFrequency(45)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .numberOfRepayments(3)// + .repaymentEvery(15)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .expectedDisbursementDate("01 March 2023")// + .submittedOnDate("01 March 2023")// + .loanType("individual")// + .externalId(loanExternalIdStr)// + .createStandingInstructionAtDisbursement(true)// + .linkAccountId(savingsAccountId)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat("dd MMMM yyyy")); approveLoan(loanId, LoanRequestBuilders.approveLoan(1000.0, "01 March 2023")); PostLoansLoanIdResponse responseLoanDisburseToSavings = disburseToSavings(loanId, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java index 707a9062db7..e77126cdd2e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; +import java.util.List; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; @@ -35,7 +36,6 @@ import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.junit.jupiter.api.AfterEach; @@ -383,14 +383,29 @@ private void disablePrincipalCompoundingConfig() { private void createLoanEntityWithScheduleGapWithInterestGreaterThanEMIAndPrincipalCompoundingOff() { LOG.info("---------------------------------NEW LOAN APPLICATION------------------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("15000").withLoanTermFrequency("24") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("24").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestCalculationPeriodTypeAsDays() - .withInterestRatePerPeriod("25").withInterestTypeAsDecliningBalance().withSubmittedOnDate(this.dateString) - .withExpectedDisbursementDate(this.dateString).withFirstRepaymentDate("01 January 2015") - .withinterestChargedFromDate(this.dateString).build(this.clientId.toString(), this.loanProductId.toString(), null); - - this.loanId = applyForLoanFromJson(loanApplicationJSON); + this.loanId = applyForLoan(new PostLoansRequest()// + .clientId(this.clientId)// + .productId(this.loanProductId)// + .principal(new BigDecimal("15000"))// + .loanTermFrequency(24)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(24)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.DAILY)// + .interestRatePerPeriod(new BigDecimal("25"))// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .loanType("individual")// + .submittedOnDate(this.dateString)// + .expectedDisbursementDate(this.dateString)// + .repaymentsStartingFromDate("01 January 2015")// + .interestChargedFromDate(this.dateString)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); LOG.info("Sucessfully created loan (ID: {} )", this.loanId); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java index ba9916c65bf..032588cec4f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java @@ -43,6 +43,8 @@ import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; +import org.apache.fineract.client.models.PostLoansRequest; +import org.apache.fineract.client.models.PostLoansRequestCollateralData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignCenterHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignGroupHelper; @@ -120,8 +122,8 @@ public void testCenterReschedulingLoansWithInterestRecalculationEnabled() { Long clientCollateralId = createClientCollateral(clientId, collateralId); assertNotNull(clientCollateralId); - List collaterals = new ArrayList<>(); - collaterals.add(collateral(clientCollateralId.intValue(), BigDecimal.valueOf(1))); + List collaterals = new ArrayList<>(); + collaterals.add(collateral(clientCollateralId, BigDecimal.valueOf(1))); Long loanProductId = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY, LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE, @@ -208,8 +210,8 @@ public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnab Long clientCollateralId = createClientCollateral(clientId, collateralId); assertNotNull(clientCollateralId); - List collaterals = new ArrayList<>(); - collaterals.add(collateral(clientCollateralId.intValue(), BigDecimal.valueOf(1))); + List collaterals = new ArrayList<>(); + collaterals.add(collateral(clientCollateralId, BigDecimal.valueOf(1))); Long loanId = applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, loanProductId, disbursementDate, recalculationRestFrequencyDate, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, createTranches, collaterals); @@ -255,11 +257,12 @@ private Long createClient(int officeId, String activationDate) { } @SuppressWarnings("rawtypes") - private HashMap collateral(Integer collateralId, BigDecimal amount) { - HashMap collateral = new HashMap(2); - collateral.put("clientCollateralId", collateralId.toString()); - collateral.put("amount", amount.toString()); - return collateral; + /** + * The server only reads collateral for individual accounts (LoanApplicationValidator guards on + * {@code loanType.isIndividualAccount()}), so for the jlg loans here it is accepted and ignored. + */ + private PostLoansRequestCollateralData collateral(Long collateralId, BigDecimal quantity) { + return new PostLoansRequestCollateralData().clientCollateralId(collateralId).quantity(quantity); } private static Long createCollateralProduct() { @@ -321,43 +324,41 @@ private Long createLoanProductWithInterestRecalculation(final String repaymentSt private Long applyForLoanApplicationForInterestRecalculation(final Long clientId, Long groupId, Long calendarId, final Long loanProductId, final String disbursementDate, final String restStartDate, final String repaymentStrategy, - List collaterals) { + List collaterals) { return applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, loanProductId, disbursementDate, restStartDate, repaymentStrategy, null, collaterals); } - @SuppressWarnings({ "rawtypes", "unchecked" }) private Long applyForLoanApplicationForInterestRecalculation(final Long clientId, Long groupId, Long calendarId, final Long loanProductId, final String disbursementDate, final String restStartDate, final String repaymentStrategy, - List tranches, List collaterals) { + List tranches, List collaterals) { LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - List trancheMaps = null; - if (tranches != null) { - trancheMaps = tranches.stream().map(tranche -> { - HashMap map = new HashMap(); - map.put("expectedDisbursementDate", tranche.getExpectedDisbursementDate()); - map.put("principal", tranche.getPrincipal().toPlainString()); - return map; - }).toList(); - } - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal("10000.00") // - .withLoanTermFrequency("24") // - .withLoanTermFrequencyAsWeeks() // - .withNumberOfRepayments("12") // - .withRepaymentEveryAfter("2") // - .withRepaymentFrequencyTypeAsWeeks() // - .withInterestRatePerPeriod("2").withLoanType("jlg") // - .withCalendarID(calendarId.toString()).withAmortizationTypeAsEqualInstallments() // - .withFixedEmiAmount("") // - .withTranches(trancheMaps).withInterestTypeAsDecliningBalance() // - .withInterestCalculationPeriodTypeAsDays() // - .withExpectedDisbursementDate(disbursementDate) // - .withSubmittedOnDate(disbursementDate) // - .withRepaymentStrategy(repaymentStrategy) // - .withCollaterals(collaterals).withCharges(new ArrayList<>())// - .build(clientId.toString(), groupId.toString(), loanProductId.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .groupId(groupId)// + .productId(loanProductId)// + .principal(new BigDecimal("10000.00"))// + .loanTermFrequency(24)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.WEEKS)// + .numberOfRepayments(12)// + .repaymentEvery(2)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.WEEKS)// + .interestRatePerPeriod(new BigDecimal("2"))// + .loanType("jlg")// + .calendarId(calendarId)// + .syncDisbursementWithMeeting(false)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .disbursementData(tranches)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.DAILY)// + .expectedDisbursementDate(disbursementDate)// + .submittedOnDate(disbursementDate)// + .transactionProcessingStrategyCode(repaymentStrategy)// + .collateral(collaterals)// + .charges(List.of())// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); } private static LocalDate toLocalDate(Calendar calendar) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanTestData.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanTestData.java index 5d1994e8f9f..0c7d6349e6b 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanTestData.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanTestData.java @@ -201,6 +201,7 @@ private InterestRateFrequencyType() {} public static final class TransactionProcessingStrategyCode { public static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy"; + public static final String MIFOS_STANDARD_STRATEGY = "mifos-standard-strategy"; private TransactionProcessingStrategyCode() {} } From 2c58bcc95a71f51692ec91f18ee55b6270b2fbad Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:26:41 +0530 Subject: [PATCH 03/15] FINERACT-2779: type the advanced-payment-allocation loan applications Three more applyForLoanFromJson callers move to PostLoansRequest. Each keeps the defaults LoanApplicationTestBuilder.build() applied invisibly, including the amortizationType and interestCalculationPeriodType the chains never set, and strips the thousands separator from the 15,000.00 principal. Signed-off-by: DeathGun44 --- ...mentWithAdvancedPaymentAllocationTest.java | 35 ++++++++++++------ .../LoanReschedulingWithinCenterTest.java | 4 +-- ...ncedPaymentAllocationIntegrationTests.java | 34 +++++++++++++----- ...eOffWithAdvancedPaymentAllocationTest.java | 36 ++++++++++++++----- .../client/feign/helpers/FeignLoanHelper.java | 1 - 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java index 3e9988cf4fa..2238d312122 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java @@ -36,17 +36,18 @@ import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; import org.apache.fineract.client.models.PostFinancialActivityAccountsResponse; import org.apache.fineract.client.models.PostLoansLoanIdRequest; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsProductHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsTransactionHelper; import org.apache.fineract.integrationtests.client.feign.modules.ChargeRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.client.feign.modules.SavingsRequestBuilders; import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.FinancialActivityAccountHelper; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; @@ -208,15 +209,29 @@ private Long applyForLoanApplication(final Long clientId, final Long loanProduct final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate, final String expectedDisbursementDate, final String submittedOnDate) { log.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000.00").withLoanTermFrequency("45") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("3").withRepaymentEveryAfter("15").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0") - .withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) - .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString()).withAmortizationTypeAsEqualInstallments() - .withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate(expectedDisbursementDate).withSubmittedOnDate(submittedOnDate) - .build(clientId.toString(), loanProductId.toString(), savingsId.toString()); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal("1000.00"))// + .loanTermFrequency(45)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .numberOfRepayments(3)// + .repaymentEvery(15)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .transactionProcessingStrategyCode(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)// + .loanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString())// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .loanType("individual")// + .expectedDisbursementDate(expectedDisbursementDate)// + .submittedOnDate(submittedOnDate)// + .linkAccountId(savingsId)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); } private void verifyNoAccrualTransactionForRepayment(Long loanId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java index 032588cec4f..e298cadae20 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java @@ -29,7 +29,6 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.Calendar; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -201,8 +200,7 @@ public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnab List createTranches = List.of(LoanRequestBuilders.applyTrancheDetail(disbursementDate, 5000.0), LoanRequestBuilders.applyTrancheDetail(secondDisbursement, 5000.0)); - List approveTranches = List.of( - LoanRequestBuilders.approveTrancheDetail(disbursementDate, 5000.0), + List approveTranches = List.of(LoanRequestBuilders.approveTrancheDetail(disbursementDate, 5000.0), LoanRequestBuilders.approveTrancheDetail(secondDisbursement, 5000.0)); Long collateralId = createCollateralProduct(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java index 67a7e121cdc..a2755ee6a74 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java @@ -20,6 +20,7 @@ import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY; +import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -27,10 +28,11 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PaymentAllocationOrder; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -108,14 +110,28 @@ private PutLoanProductsProductIdRequest updateLoanProductRequest(AdvancedPayment } private Long createLoanAccount(Long clientId, Long loanProductId, String operationDate) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("15,000.00").withLoanTermFrequency("4") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withExpectedDisbursementDate(operationDate) - .withInterestTypeAsDecliningBalance().withSubmittedOnDate(operationDate) - .withRepaymentStrategy(ADVANCED_PAYMENT_ALLOCATION_STRATEGY) - .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString()) - .build(clientId.toString(), loanProductId.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal("15000.00"))// + .loanTermFrequency(4)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(4)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY)// + .loanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString())// + .loanType("individual")// + .expectedDisbursementDate(operationDate)// + .submittedOnDate(operationDate)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); } private AdvancedPaymentData createRepaymentPaymentAllocation() { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java index fc425beb028..06920180473 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java @@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.math.BigDecimal; +import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; @@ -31,10 +32,11 @@ import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -160,14 +162,30 @@ private Long createApaLoanProduct() { } private Long createAndDisburseLoan(Long clientId, Long loanProductId, String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 September 2022") - .withSubmittedOnDate("01 September 2022").withLoanType("individual").withExternalId(externalId) - .withRepaymentStrategy(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).build(clientId.toString(), loanProductId.toString(), null); - - Long loanId = applyForLoanFromJson(loanApplicationJSON); + PostLoansRequest loanApplication = new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal("1000"))// + .loanTermFrequency(30)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .numberOfRepayments(1)// + .repaymentEvery(30)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .expectedDisbursementDate("03 September 2022")// + .submittedOnDate("01 September 2022")// + .loanType("individual")// + .externalId(externalId)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN); + + Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoan(loanId, BigDecimal.valueOf(1000), "03 September 2022"); return loanId; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java index 6aaeeed86f7..f1ce9ff0ddf 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java @@ -22,7 +22,6 @@ import static org.apache.fineract.client.feign.util.FeignCalls.fail; import static org.apache.fineract.client.feign.util.FeignCalls.ok; -import com.fasterxml.jackson.core.JsonProcessingException; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; From 9730d154d1dbcefcfb52813a9878569928d867f9 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:32:32 +0530 Subject: [PATCH 04/15] FINERACT-2779: type the single-repayment loan applications Four more applyForLoanFromJson callers move to PostLoansRequest. All four are the same one-month, one-repayment flat-balance shape, so they differ only in principal, rate and external id. Signed-off-by: DeathGun44 --- ...LoanAccountsContainsCurrencyFieldTest.java | 33 +++++++++++---- ...oanTransactionAuditingIntegrationTest.java | 42 +++++++++++-------- ...nTransactionReverseReplayRelationTest.java | 35 ++++++++++++---- .../RepaymentReverseExternalIdTest.java | 34 +++++++++++---- 4 files changed, 101 insertions(+), 43 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java index 29cc18d04f5..0512a7e9059 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java @@ -21,16 +21,19 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.math.BigDecimal; +import java.util.List; import java.util.Set; import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse; import org.apache.fineract.client.models.GetClientsLoanAccounts; import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.ClientRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.junit.jupiter.api.Test; @@ -72,13 +75,27 @@ public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() { } private Long createAndApproveLoan(Long clientId, Long loanProductId, String operationDate) { - final String loanApplicationJson = new LoanApplicationTestBuilder().withPrincipal(PRINCIPAL_AMOUNT).withLoanTermFrequency("1") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .build(clientId.toString(), loanProductId.toString(), null); - final Long loanId = applyForLoanFromJson(loanApplicationJson); + final Long loanId = applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal(PRINCIPAL_AMOUNT))// + .loanTermFrequency(1)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(1)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .expectedDisbursementDate("03 September 2022")// + .submittedOnDate("01 September 2022")// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); approveLoan(loanId, approveLoanRequest(Double.valueOf(PRINCIPAL_AMOUNT), operationDate)); return loanId; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java index 858aa16f6e1..bc5e9067e3c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java @@ -32,16 +32,19 @@ import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; +import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignRawHttpHelper; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.organisation.StaffHelper; import org.apache.fineract.integrationtests.useradministration.users.UserHelper; @@ -147,22 +150,27 @@ private Map getAuditFields(Long loanId, Long transactionId) { private Long applyForLoanApplication(final Long clientId, final Long loanProductId, String principal, final String submittedOnDate, final String disbursementDate) { - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal(principal) // - .withLoanTermFrequency("6") // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments("6") // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsFlatBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate(disbursementDate) // - .withSubmittedOnDate(submittedOnDate) // - .withRepaymentStrategy(LoanApplicationTestBuilder.DEFAULT_STRATEGY) // - .build(clientId.toString(), loanProductId.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal(principal))// + .loanTermFrequency(6)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(6)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(new BigDecimal("2"))// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .interestType(LoanTestData.InterestType.FLAT)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .expectedDisbursementDate(disbursementDate)// + .submittedOnDate(submittedOnDate)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); } private Long createLoanProduct(final String inMultiplesOf, final String digitsAfterDecimal, final String repaymentStrategy, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java index fc063e033a3..d4965e9df5a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java @@ -21,12 +21,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.math.BigDecimal; +import java.util.List; import java.util.UUID; import org.apache.fineract.client.models.GetLoanTransactionRelation; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,15 +57,28 @@ public void loanTransactionReverseReplayRelationTest() { .toJson(new org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder().build(null, delinquencyBucketId))); assertNotNull(productId); - String loanApplicationJSON = new org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder() - .withPrincipal("1000").withLoanTermFrequency("1").withLoanTermFrequencyAsMonths().withNumberOfRepayments("1") - .withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0") - .withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 September 2022") - .withSubmittedOnDate("01 September 2022").withLoanType("individual").withExternalId(loanExternalIdStr) - .build(clientId.toString(), productId.toString(), null); - - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(productId)// + .principal(new BigDecimal("1000"))// + .loanTermFrequency(1)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(1)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .expectedDisbursementDate("03 September 2022")// + .submittedOnDate("01 September 2022")// + .loanType("individual")// + .externalId(loanExternalIdStr)// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithNetDisbursalAmount(loanId, "03 September 2022", "1000"); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/RepaymentReverseExternalIdTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/RepaymentReverseExternalIdTest.java index 7ae82394ea3..e2d040beae3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/RepaymentReverseExternalIdTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/RepaymentReverseExternalIdTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -34,13 +35,14 @@ import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestAccounts; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.funds.FundsResourceHandler; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.Test; @@ -165,14 +167,28 @@ private PostLoanProductsRequest loanProductsRequest(String loanExternalId) { } private Long createLoanAccount(final Long clientId, final Long loanProductId, final String loanExternalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(loanAmount).withExternalId(loanExternalId) - .withLoanTermFrequency("1").withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("1").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate(startDate).withSubmittedOnDate(startDate).withLoanType("individual") - .build(clientId.toString(), loanProductId.toString(), null); - - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal(loanAmount))// + .externalId(loanExternalId)// + .loanTermFrequency(1)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(1)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(BigDecimal.ONE)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .expectedDisbursementDate(startDate)// + .submittedOnDate(startDate)// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN)); approveLoan(loanId, approveLoanRequest(Double.parseDouble(loanAmount), startDate)); disburseLoanWithNetDisbursalAmount(loanId, startDate, loanAmount); return loanId; From 53f14745fa66c2f82edee5d8d936864a6dca3673 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:43:23 +0530 Subject: [PATCH 05/15] FINERACT-2779: share the legacy loan application shape and type four more callers The four client-loan tests built the same equal-installment declining-balance application, so LoanRequestBuilders.legacyIndividualApplication carries it once, including the fields build() emitted invisibly. It takes the principal as a String and strips the grouping separator, because the JSON builder sent amounts like 12,000.00 for the server to parse under en_GB. The tranche variant also sends the fixedEmiAmount that build() attached whenever disbursementData was present, and its tranche details are now PostLoansDisbursementData rather than HashMap. Signed-off-by: DeathGun44 --- ...ientLoanChargeExternalIntegrationTest.java | 20 ++-------- ...RefundandRepaymentTypeIntegrationTest.java | 20 ++-------- ...nMultipleDisbursementsIntegrationTest.java | 38 ++++++------------- ...eMultipleDisbursementsIntegrationTest.java | 20 ++-------- .../feign/modules/LoanRequestBuilders.java | 31 +++++++++++++++ 5 files changed, 52 insertions(+), 77 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java index eaabe1a0b90..1ac65d815c4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java @@ -22,12 +22,13 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.math.BigDecimal; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.GetLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -108,20 +109,7 @@ private Long createLoanProduct(final boolean multiDisburseLoan, final String acc } private Long applyForLoanApplication(final Long clientId, final Long loanProductId, String principal) { - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal(principal) // - .withLoanTermFrequency("4") // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments("4") // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsDecliningBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate("20 September 2011") // - .withSubmittedOnDate("20 September 2011") // - .build(clientId.toString(), loanProductId.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(LoanRequestBuilders.legacyIndividualApplication(clientId, loanProductId, principal, 4, new BigDecimal("2"), + "20 September 2011")); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java index ff595355497..b70e467cfb9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java @@ -49,7 +49,6 @@ import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.JournalEntry; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.junit.jupiter.api.Assertions; @@ -110,22 +109,9 @@ private Long createLoanProduct(LoanProductTestBuilder loanProductTestBuilder, fi private Long applyForLoanApplication(final Long clientID, final Long loanProductID, String principal, String submitDate, String repaymentStrategy) { - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal(principal) // - .withLoanTermFrequency("4") // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments("4") // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsDecliningBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate(submitDate) // - .withSubmittedOnDate(submitDate) // - .withRepaymentStrategy(repaymentStrategy) // - .build(clientID.toString(), loanProductID.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan( + LoanRequestBuilders.legacyIndividualApplication(clientID, loanProductID, principal, 4, new BigDecimal("2"), submitDate) + .transactionProcessingStrategyCode(repaymentStrategy)); } private Long fromStartToDisburseLoan(LoanProductTestBuilder loanProductTestBuilder, String submitApproveDisburseDate, String principal, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java index 952c5ea58d5..169da54bc19 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java @@ -27,13 +27,13 @@ import com.google.gson.JsonParser; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignRawHttpHelper; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.junit.jupiter.api.Assertions; @@ -79,31 +79,15 @@ private Long createLoanProduct(final boolean multiDisburseLoan) { } private Long applyForLoanApplicationWithTranches(final Long clientId, final Long loanProductID, String principal, - List tranches, String submitDate) { + List tranches, String submitDate) { LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal(principal) // - .withLoanTermFrequency("4") // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments("4") // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("0") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsDecliningBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate(submitDate) // - .withTranches(tranches) // - .withSubmittedOnDate(submitDate) // - .build(clientId.toString(), loanProductID.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductID, principal, 4, BigDecimal.ZERO, submitDate).disbursementData(tranches)// + .fixedEmiAmount(new BigDecimal("10000"))); } - private HashMap createTrancheDetail(final String date, final String amount) { - HashMap detail = new HashMap(); - detail.put("expectedDisbursementDate", date); - detail.put("principal", amount); - return detail; + private PostLoansDisbursementData createTrancheDetail(final String date, final String amount) { + return new PostLoansDisbursementData().expectedDisbursementDate(date).principal(new BigDecimal(amount)); } /** @@ -144,7 +128,7 @@ public void checkThatAllMultiDisbursalsAppearOnLoanScheduleAndOutStandingBalance final String principal = "12,000.00"; LOG.info("-----------------------------------10 Tranches--------------------------------------"); - List tranches = new ArrayList<>(); + List tranches = new ArrayList<>(); tranches.add(createTrancheDetail("01 January 2021", "1")); tranches.add(createTrancheDetail("02 January 2021", "2")); tranches.add(createTrancheDetail("03 January 2021", "4")); @@ -223,7 +207,7 @@ public void checkThatAllMultiDisbursalsAppearOnLoanScheduleAndOutStandingBalance final String principal = "12,000.00"; LOG.info("-----------------------------------2 Tranches--------------------------------------"); - List tranches = new ArrayList<>(); + List tranches = new ArrayList<>(); tranches.add(createTrancheDetail("01 January 2021", "1")); tranches.add(createTrancheDetail("02 January 2021", "2")); String submitDate = "01 January 2021"; @@ -296,7 +280,7 @@ public void checkThatAllMultiDisbursalsAppearOnLoanScheduleAndOutStandingBalance final String principal = "12,000.00"; LOG.info("-----------------------------------2 Tranches--------------------------------------"); - List tranches = new ArrayList<>(); + List tranches = new ArrayList<>(); tranches.add(createTrancheDetail("01 January 2021", "1")); tranches.add(createTrancheDetail("02 January 2021", "2")); String submitDate = "01 January 2021"; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java index 5eb500b027a..29a16cc5019 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java @@ -23,7 +23,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.junit.jupiter.api.Assertions; @@ -92,22 +92,8 @@ private Long createLoanProduct(final boolean isInterestRecalculationEnabled) { private Long applyForLoanApplication(final Long clientId, final Long loanProductID, String principal, String submitDate, String repaymentsNo) { LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal(principal) // - .withLoanTermFrequency(repaymentsNo) // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments(repaymentsNo) // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsDecliningBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate(submitDate) // - .withTranches(null) // - .withSubmittedOnDate(submitDate) // - .build(clientId.toString(), loanProductID.toString(), null); - return applyForLoanFromJson(loanApplicationJSON); + return applyForLoan(LoanRequestBuilders.legacyIndividualApplication(clientId, loanProductID, principal, + Integer.parseInt(repaymentsNo), new BigDecimal("2"), submitDate)); } /*** diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java index 8884293d0df..feb29fcd5d5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java @@ -124,6 +124,37 @@ public static PostLoansLoanIdRequest disburseLoan(Double disbursedAmount, String .dateFormat(LoanTestData.DATETIME_PATTERN); } + /** + * The equal-installment declining-balance application that LoanApplicationTestBuilder produced, including the + * fields its build() always emitted but no call site named: maxOutstandingLoanBalance, an empty collateral list, + * the default strategy and the en_GB locale. + */ + public static PostLoansRequest legacyIndividualApplication(Long clientId, Long productId, String principal, int repayments, + BigDecimal interestRatePerPeriod, String date) { + return new PostLoansRequest()// + .clientId(clientId)// + .productId(productId)// + // the JSON builder sent grouped amounts like "12,000.00" for the server to parse under en_GB + .principal(new BigDecimal(principal.replace(",", "")))// + .loanTermFrequency(repayments)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .numberOfRepayments(repayments)// + .repaymentEvery(1)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)// + .interestRatePerPeriod(interestRatePerPeriod)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .expectedDisbursementDate(date)// + .submittedOnDate(date)// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN); + } + public static PostLoansLoanIdRequest disburseLoanWithRepaymentReschedule(String disbursedOnDate, String adjustRepaymentDate) { return new PostLoansLoanIdRequest()// .actualDisbursementDate(disbursedOnDate)// From cd2863cbeba9abff3e7bff453e27357ebe53e5f4 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:50:16 +0530 Subject: [PATCH 06/15] FINERACT-2779: share the days-based loan application shape Four advanced-payment-allocation tests built the same days-based equal-principal application, so legacyDaysBasedApplication carries it alongside the monthly one. Interest type defaults to flat and the reverse-replay test overrides it, which is the only way the four differed beyond dates and strategy. Signed-off-by: DeathGun44 --- ...eOffWithAdvancedPaymentAllocationTest.java | 15 +++++----- ...playWithAdvancedPaymentAllocationTest.java | 18 ++++++------ ...lingWithAdvancedPaymentAllocationTest.java | 14 ++++------ ...ocessForAdvancedPaymentAllocationTest.java | 16 +++++------ .../feign/modules/LoanRequestBuilders.java | 28 +++++++++++++++++++ 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java index 952b113f1f4..99a92d60c2e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeOffWithAdvancedPaymentAllocationTest.java @@ -46,7 +46,9 @@ import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.PaymentTypeHelper; @@ -54,7 +56,6 @@ import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.JournalEntry; import org.apache.fineract.integrationtests.common.funds.FundsResourceHandler; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -560,14 +561,12 @@ private void verifyTransaction(final LocalDate transactionDate, final Float tran private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 September 2022") - .withSubmittedOnDate("01 September 2022").withLoanType("individual").withExternalId(externalId) - .withRepaymentStrategy("advanced-payment-allocation-strategy").build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyDaysBasedApplication(clientId, loanProductId, "1000", 30, 1, 30, "03 September 2022", "01 September 2022") + .externalId(externalId)// + .transactionProcessingStrategyCode("advanced-payment-allocation-strategy"); - Long loanId = applyForLoanFromJson(loanApplicationJSON); + Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithAmount(loanId, "03 September 2022", 1000.0); return loanId; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeReveseReplayWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeReveseReplayWithAdvancedPaymentAllocationTest.java index 9af833b91c3..313fb1c1137 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeReveseReplayWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountChargeReveseReplayWithAdvancedPaymentAllocationTest.java @@ -37,13 +37,14 @@ import org.apache.fineract.client.models.PaymentTypeCreateRequest; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.PaymentTypeHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.funds.FundsResourceHandler; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -218,15 +219,14 @@ public void testObligationMetDateIsNotMetOnExtraInstallment() { private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId, final boolean advancedPaymentStrategy, String approveDate, String disbursementDate) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsDecliningBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 September 2022") - .withSubmittedOnDate("01 September 2022").withLoanType("individual").withExternalId(externalId) - .withRepaymentStrategy(advancedPaymentStrategy ? "advanced-payment-allocation-strategy" : "mifos-standard-strategy") - .build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyDaysBasedApplication(clientId, loanProductId, "1000", 30, 1, 30, "03 September 2022", "01 September 2022") + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .externalId(externalId)// + .transactionProcessingStrategyCode( + advancedPaymentStrategy ? "advanced-payment-allocation-strategy" : "mifos-standard-strategy"); - Long loanId = applyForLoanFromJson(loanApplicationJSON); + Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, approveDate)); disburseLoanWithAmount(loanId, disbursementDate, 1000.0); return loanId; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java index 865efcebc7a..c88da726b0c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java @@ -26,11 +26,11 @@ import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.ChargeRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.junit.jupiter.api.Disabled; @@ -83,14 +83,12 @@ private Long createLoanProduct(final Account... accounts) { private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("60") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("4").withRepaymentEveryAfter("15").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("15 February 2023") - .withSubmittedOnDate("15 February 2023").withLoanType("individual").withExternalId(externalId) - .withRepaymentStrategy("advanced-payment-allocation-strategy").build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyDaysBasedApplication(clientId, loanProductId, "1000", 60, 4, 15, "15 February 2023", "15 February 2023") + .externalId(externalId)// + .transactionProcessingStrategyCode("advanced-payment-allocation-strategy"); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, LoanRequestBuilders.approveLoan(1000.0, "15 February 2023")); return loanId; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java index 39051ce26b5..bca0b7b4adc 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java @@ -26,13 +26,13 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.junit.jupiter.api.Test; @@ -98,14 +98,12 @@ private Long createLoanProduct(Account... accounts) { } private Long createLoanAccount(Long clientId, Long loanProductId, String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("60") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("4").withRepaymentEveryAfter("15").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("15 February 2023") - .withSubmittedOnDate("15 February 2023").withLoanType("individual").withExternalId(externalId) - .withRepaymentStrategy(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).build(clientId.toString(), loanProductId.toString(), null); - - Long loanId = applyForLoanFromJson(loanApplicationJSON); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyDaysBasedApplication(clientId, loanProductId, "1000", 60, 4, 15, "15 February 2023", "15 February 2023") + .externalId(externalId)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY); + + Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "15 February 2023")); return loanId; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java index feb29fcd5d5..d927d44b76e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java @@ -155,6 +155,34 @@ public static PostLoansRequest legacyIndividualApplication(Long clientId, Long p .dateFormat(LoanTestData.DATETIME_PATTERN); } + /** + * The days-based equal-principal application the JSON builder produced, with the same invisible build() defaults as + * {@link #legacyIndividualApplication}. Interest type defaults to flat; override it on the returned request. + */ + public static PostLoansRequest legacyDaysBasedApplication(Long clientId, Long productId, String principal, int termDays, int repayments, + int repaymentEveryDays, String expectedDisbursementDate, String submittedOnDate) { + return new PostLoansRequest()// + .clientId(clientId)// + .productId(productId)// + .principal(new BigDecimal(principal.replace(",", "")))// + .loanTermFrequency(termDays)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .numberOfRepayments(repayments)// + .repaymentEvery(repaymentEveryDays)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.DAYS)// + .interestRatePerPeriod(BigDecimal.ZERO)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .expectedDisbursementDate(expectedDisbursementDate)// + .submittedOnDate(submittedOnDate)// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN); + } + public static PostLoansLoanIdRequest disburseLoanWithRepaymentReschedule(String disbursedOnDate, String adjustRepaymentDate) { return new PostLoansLoanIdRequest()// .actualDisbursementDate(disbursedOnDate)// From 1d82cc7ac01675611c12e22ed65d3ce29ca77356 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 13:57:27 +0530 Subject: [PATCH 07/15] FINERACT-2779: type the down-payment loan applications Three more callers reuse legacyIndividualApplication, overriding the interest and amortization types where they differ from its equal-installment declining balance default. Signed-off-by: DeathGun44 --- ...OverlappingDownPaymentInstallmentTest.java | 18 ++++++++-------- .../LoanDownPaymentTransactionTypeTest.java | 19 ++++++++++------- ...paymentWithDownPaymentIntegrationTest.java | 21 +++++++++++-------- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java index 79f06366d3b..91a34507da9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java @@ -34,10 +34,12 @@ import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; import org.junit.jupiter.api.Test; @@ -759,15 +761,13 @@ private void verifyPeriodDetails(GetLoansLoanIdRepaymentPeriod period, Integer p private Long createLoanAccountMultipleRepaymentsDisbursement(final Long clientId, final Long loanProductId, final String externalId, final String repaymentStrategy) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("2") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("2").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsDecliningBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 March 2023").withSubmittedOnDate("03 March 2023").withLoanType("individual") - .withExternalId(externalId).withRepaymentStrategy(repaymentStrategy) - .build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "1000", 2, BigDecimal.ZERO, "03 March 2023") + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId)// + .transactionProcessingStrategyCode(repaymentStrategy); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "03 March 2023")); return loanId; } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java index 42961511408..d454674eb72 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java @@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -31,9 +32,11 @@ 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.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.Test; @@ -113,14 +116,14 @@ private GetLoanProductsProductIdResponse createLoanProduct(final Long delinquenc private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .withExternalId(externalId).build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "1000", 1, BigDecimal.ZERO, "03 September 2022") + .submittedOnDate("01 September 2022")// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithNetDisbursalAmount(loanId, "03 September 2022", "1000"); return loanId; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoRepaymentWithDownPaymentIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoRepaymentWithDownPaymentIntegrationTest.java index 2b4689d8184..9366c8fa114 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoRepaymentWithDownPaymentIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/UndoRepaymentWithDownPaymentIntegrationTest.java @@ -37,11 +37,13 @@ import org.apache.fineract.client.models.PostLoanProductsRequest; 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.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.PaymentTypeHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.funds.FundsResourceHandler; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -244,15 +246,16 @@ private Long createLoanProductWithPeriodicAccrualAccounting() { private Long createApproveAndDisburseLoanAccount(final Long clientId, final Long loanProductId, final String externalId, final String numberOfRepayments, final String interestRate) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency(numberOfRepayments) - .withLoanTermFrequencyAsMonths().withNumberOfRepayments(numberOfRepayments).withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod(interestRate).withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .withRepaymentStrategy(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).withExternalId(externalId) - .build(clientId.toString(), loanProductId.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "1000", Integer.parseInt(numberOfRepayments), + new BigDecimal(interestRate), "03 September 2022") + .submittedOnDate("01 September 2022")// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithAmount(loanId, "03 September 2022", 1000.0); return loanId; From f1f03efc2cd1b8917e916d9300bbb5cbc8dc805c Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 14:07:27 +0530 Subject: [PATCH 08/15] FINERACT-2779: type the down-payment repayment schedule applications Converts the last four applyForLoanFromJson sites in the file. Also gives legacyDaysBasedApplication the default transactionProcessingStrategyCode that build() always emitted; its earlier callers all set a strategy explicitly, so the omission only surfaced here as a mandatory-parameter 400. Signed-off-by: DeathGun44 --- ...nRepaymentScheduleWithDownPaymentTest.java | 59 ++++++++++--------- .../feign/modules/LoanRequestBuilders.java | 1 + 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java index e3f3ff2d4a1..5418af5ce4a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java @@ -46,10 +46,11 @@ import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.JournalEntry; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor; @@ -1704,14 +1705,13 @@ private void checkDownPaymentTransaction(final LocalDate transactionDate, final private Integer createLoanAccountMultipleRepaymentsDisbursement(final Integer clientID, final Long loanProductID, final String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("30") - .withLoanTermFrequencyAsDays().withNumberOfRepayments("1").withRepaymentEveryAfter("30").withRepaymentFrequencyTypeAsDays() - .withInterestRatePerPeriod("0").withInterestTypeAsDecliningBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 March 2023") - .withSubmittedOnDate("03 March 2023").withLoanType("individual").withExternalId(externalId) - .build(clientID.toString(), loanProductID.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyDaysBasedApplication(clientID.longValue(), loanProductID.longValue(), "1000", 30, 1, 30, "03 March 2023", + "03 March 2023") + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "03 March 2023")); return loanId.intValue(); } @@ -1731,14 +1731,15 @@ private GetLoanProductsProductIdResponse createLoanProductWithDownPaymentConfigu private Integer createApproveAndDisburseLoanAccount(final Integer clientID, final Long loanProductID, final String externalId) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientID.longValue(), loanProductID.longValue(), "1000", 1, BigDecimal.ZERO, + "03 September 2022") + .submittedOnDate("01 September 2022")// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithNetDisbursalAmount(loanId, "03 September 2022", "1000"); return loanId.intValue(); @@ -1779,14 +1780,14 @@ private Integer createLoanProductWithDownPaymentConfiguration(final Long delinqu private Integer createAndApproveLoanAccount(final Integer clientID, final Long loanProductID, final String externalId, final String numberOfRepayments, final String interestRate) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency(numberOfRepayments) - .withLoanTermFrequencyAsMonths().withNumberOfRepayments(numberOfRepayments).withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod(interestRate).withInterestTypeAsDecliningBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientID.longValue(), loanProductID.longValue(), "1000", Integer.parseInt(numberOfRepayments), + new BigDecimal(interestRate), "03 September 2022") + .submittedOnDate("01 September 2022")// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); return loanId.intValue(); } @@ -1802,14 +1803,14 @@ private Integer createApproveAndDisburseLoanAccount(final Integer clientID, fina private Integer createApproveAndDisburseTwiceLoanAccount(final Integer clientID, final Long loanProductID, final String externalId, final String numberOfRepayments, final String interestRate) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency(numberOfRepayments) - .withLoanTermFrequencyAsMonths().withNumberOfRepayments(numberOfRepayments).withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod(interestRate).withInterestTypeAsDecliningBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("04 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") - .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); + PostLoansRequest loanApplication = LoanRequestBuilders + .legacyIndividualApplication(clientID.longValue(), loanProductID.longValue(), "1000", Integer.parseInt(numberOfRepayments), + new BigDecimal(interestRate), "04 September 2022") + .submittedOnDate("01 September 2022")// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId); - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + final Long loanId = applyForLoan(loanApplication); approveLoan(loanId, approveLoanRequest(1000.0, "02 September 2022")); disburseLoanWithAmount(loanId, "03 September 2022", 700.0); disburseLoanWithAmount(loanId, "04 September 2022", 300.0); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java index d927d44b76e..489ee5542d8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/LoanRequestBuilders.java @@ -174,6 +174,7 @@ public static PostLoansRequest legacyDaysBasedApplication(Long clientId, Long pr .interestType(LoanTestData.InterestType.FLAT)// .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// .expectedDisbursementDate(expectedDisbursementDate)// .submittedOnDate(submittedOnDate)// .loanType("individual")// From ea621cb0b12bdc7217c40987c28c90be09bdaf57 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 14:11:40 +0530 Subject: [PATCH 09/15] FINERACT-2779: type the tranche reschedule loan application Drops the HashMap round-trip for the tranche details, which the method already received as PostLoansDisbursementData. The empty fixedEmiAmount the JSON builder sent has no typed equivalent and is omitted; the schedule assertions are unchanged. Signed-off-by: DeathGun44 --- ...RepaymentRescheduleAtDisbursementTest.java | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java index 7835617ab72..7760ca0fdc0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java @@ -20,19 +20,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.math.BigDecimal; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestValidators; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.junit.jupiter.api.Test; @@ -57,7 +57,7 @@ public void testLoanRepaymentRescheduleAtDisbursement() { List approveTranches = List.of(LoanRequestBuilders.approveTrancheDetail("01 March 2015", 5000.0), LoanRequestBuilders.approveTrancheDetail("01 May 2015", 5000.0)); - Long loanId = applyForLoanFromJson(buildLoanApplicationJson(clientId, loanProductId, disbursementDate, createTranches)); + Long loanId = applyForLoan(buildLoanApplication(clientId, loanProductId, disbursementDate, createTranches)); verifyLoanStatus(loanId, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL); @@ -91,22 +91,30 @@ private String buildLoanProductJson() { .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).build(null); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - private String buildLoanApplicationJson(Long clientId, Long loanProductId, String disbursementDate, + private PostLoansRequest buildLoanApplication(Long clientId, Long loanProductId, String disbursementDate, List tranches) { - List trancheMaps = tranches.stream().map(tranche -> { - HashMap map = new HashMap(); - map.put("expectedDisbursementDate", tranche.getExpectedDisbursementDate()); - map.put("principal", tranche.getPrincipal().toPlainString()); - return map; - }).toList(); - - return new LoanApplicationTestBuilder().withPrincipal("10000.00").withLoanTermFrequency("24").withLoanTermFrequencyAsWeeks() - .withNumberOfRepayments("12").withRepaymentEveryAfter("2").withRepaymentFrequencyTypeAsWeeks() - .withInterestRatePerPeriod("2").withAmortizationTypeAsEqualInstallments().withTranches(trancheMaps).withFixedEmiAmount("") - .withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeAsDays() - .withExpectedDisbursementDate(disbursementDate).withSubmittedOnDate(disbursementDate) - .withRepaymentStrategy(LoanApplicationTestBuilder.RBI_INDIA_STRATEGY).withCharges(new ArrayList<>()) - .build(clientId.toString(), loanProductId.toString(), null); + return new PostLoansRequest()// + .clientId(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal("10000.00"))// + .loanTermFrequency(24)// + .loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.WEEKS)// + .numberOfRepayments(12)// + .repaymentEvery(2)// + .repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.WEEKS)// + .interestRatePerPeriod(new BigDecimal("2"))// + .amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)// + .disbursementData(tranches)// + .interestType(LoanTestData.InterestType.DECLINING_BALANCE)// + .interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.DAILY)// + .expectedDisbursementDate(disbursementDate)// + .submittedOnDate(disbursementDate)// + .transactionProcessingStrategyCode(LoanProductTestBuilder.RBI_INDIA_STRATEGY)// + .charges(List.of())// + .loanType("individual")// + .maxOutstandingLoanBalance(new BigDecimal("36000"))// + .collateral(List.of())// + .locale("en_GB")// + .dateFormat(LoanTestData.DATETIME_PATTERN); } } From 2877731bde6b2f4cd2011072e5b786856b3a5103 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 9 Aug 2026 14:35:52 +0530 Subject: [PATCH 10/15] FINERACT-2779: retire applyForLoanFromJson and the last REST-assured plumbing The floating-rate test was the only caller that could not be expressed typed: it stripped interestRatePerPeriod and added interestRateDifferential and isFloatingInterestRate, neither of which was on PostLoansRequest. Both are accepted by LoanApplicationValidator, so they are added to the DTO rather than left as a reason to keep the JSON path. With the last caller converted, applyForLoanFromJson, jsonRequestSpec, APPLY_LOAN_URL and the io.restassured imports are deleted. FeignLoanHelper no longer references REST-assured at all. getLoanIdFromApplication, which built a PostLoansResponse from a bare loan id, becomes applyForLoanResponse taking a typed request. Signed-off-by: DeathGun44 --- .../api/LoansApiResourceSwagger.java | 4 ++ .../ExternalIdSupportIntegrationTest.java | 20 +++++----- ...FloatingRateInterestRecalculationTest.java | 22 +++-------- .../client/feign/FeignLoanTestBase.java | 37 +++++++++---------- .../client/feign/helpers/FeignLoanHelper.java | 21 ----------- 5 files changed, 38 insertions(+), 66 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index cf30c550d68..0a621d120f5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -1408,6 +1408,10 @@ private PostLoansRequest() {} public String daysInYearCustomStrategy; @Schema(example = "individual") public String loanType; + @Schema(example = "false", description = "Take the rate from the product's floating rate instead of interestRatePerPeriod") + public Boolean isFloatingInterestRate; + @Schema(example = "0", description = "Added to the floating rate when isFloatingInterestRate is true") + public BigDecimal interestRateDifferential; @Schema(example = "1", description = "Meeting calendar to attach the loan to; required for jlg loans") public Long calendarId; @Schema(example = "true", description = "Sync the disbursement date with the attached meeting") diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java index 34076e63f8e..a8ad3878615 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java @@ -66,10 +66,11 @@ import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignStaffHelper; import org.apache.fineract.integrationtests.client.feign.modules.ChargeRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; @@ -410,14 +411,15 @@ loanExternalIdStr, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM final Integer savingsId = openSavingsAccount(clientId, "10000.0", "01 August 2022"); loanExternalIdStr = UUID.randomUUID().toString(); - final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("10000.0").withLoanTermFrequency("10") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("2") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("1").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate(formattedDate).withSubmittedOnDate(formattedDate).withLoanType("individual") - .withExternalId(loanExternalIdStr) - .build(clientId.toString(), loanProductWithInterestID.toString(), savingsId.toString()); - final PostLoansResponse loanWithInterest = getLoanIdFromApplication(loanApplicationJSON); + final PostLoansResponse loanWithInterest = applyForLoanResponse(LoanRequestBuilders + .legacyIndividualApplication(clientId.longValue(), loanProductWithInterestID.longValue(), "10000.0", 5, + new BigDecimal("1"), formattedDate) + .loanTermFrequency(10)// + .repaymentEvery(2)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(loanExternalIdStr)// + .linkAccountId(savingsId.longValue())); Integer loanWithInterestId = loanWithInterest.getResourceId().intValue(); String chargeExternalId = UUID.randomUUID().toString(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FloatingRateInterestRecalculationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FloatingRateInterestRecalculationTest.java index 42f71cd9460..8e79a9f914c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FloatingRateInterestRecalculationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FloatingRateInterestRecalculationTest.java @@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.math.BigDecimal; import java.util.HashMap; @@ -33,9 +32,9 @@ import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignRawHttpHelper; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.junit.jupiter.api.Test; @@ -162,20 +161,11 @@ private Integer createCumulativeFloatingRateLoanProduct(Long floatingRateId, Acc } private Long createAndDisburseLoan(Long clientId, Integer loanProductId, String disburseDateStr) { - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("10000").withLoanTermFrequency("12") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withInterestTypeAsDecliningBalance() - .withExpectedDisbursementDate(disburseDateStr).withSubmittedOnDate(disburseDateStr).withLoanType("individual") - .build(clientId.toString(), loanProductId.toString(), null); - - JsonObject jsonObject = JsonParser.parseString(loanApplicationJSON).getAsJsonObject(); - jsonObject.remove("interestRatePerPeriod"); - jsonObject.addProperty("interestRateDifferential", "0"); - jsonObject.addProperty("isFloatingInterestRate", true); - loanApplicationJSON = jsonObject.toString(); - - final Long loanId = applyForLoanFromJson(loanApplicationJSON); + // the product supplies the rate, so the application sends no interestRatePerPeriod + final Long loanId = applyForLoan( + LoanRequestBuilders.legacyIndividualApplication(clientId, loanProductId.longValue(), "10000", 12, null, disburseDateStr) + .isFloatingInterestRate(true)// + .interestRateDifferential(BigDecimal.ZERO)); approveLoan(loanId, approveLoanRequest(10000.0, disburseDateStr)); disburseLoanWithNetDisbursalAmount(loanId, disburseDateStr, "10000"); return loanId; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java index db9b51edc53..e46e5383eee 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java @@ -336,10 +336,6 @@ protected PostLoansResponse calculateLoanSchedule(PostLoansRequest request) { return loanHelper.calculateLoanSchedule(request); } - protected Long applyForLoanFromJson(String loanApplicationJson) { - return loanHelper.applyForLoanFromJson(loanApplicationJson); - } - protected PostLoansLoanIdResponse approveLoan(Long loanId, PostLoansLoanIdRequest request) { return loanHelper.approveLoan(loanId, request); } @@ -1074,22 +1070,23 @@ protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer lo } protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer loanProductId, String externalId, String linkAccountId) { - final String loanApplicationJSON = new org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder() - .withPrincipal("1000").withLoanTermFrequency("1").withLoanTermFrequencyAsMonths().withNumberOfRepayments("1") - .withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0") - .withInterestTypeAsDecliningBalance().withAmortizationTypeAsEqualPrincipalPayments() - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate("03 September 2022") - .withSubmittedOnDate("01 September 2022").withLoanType("individual").withInArrearsTolerance("1001") - .withExternalId(externalId).build(clientId.toString(), loanProductId.toString(), linkAccountId); - return getLoanIdFromApplication(loanApplicationJSON); - } - - protected PostLoansResponse getLoanIdFromApplication(String loanApplicationJson) { - Long loanId = applyForLoanFromJson(loanApplicationJson); - PostLoansResponse result = new PostLoansResponse(); - result.setResourceId(loanId); - result.setResourceExternalId(getLoanDetails(loanId).getExternalId()); - return result; + PostLoansRequest request = LoanRequestBuilders + .legacyIndividualApplication(clientId.longValue(), loanProductId.longValue(), "1000", 1, BigDecimal.ZERO, + "03 September 2022") + .submittedOnDate("01 September 2022")// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .inArrearsTolerance(new BigDecimal("1001"))// + .externalId(externalId); + if (linkAccountId != null) { + request.linkAccountId(Long.valueOf(linkAccountId)); + } + return applyForLoanResponse(request); + } + + /** Mirrors the old JSON path, which returned only an id and then read the external id back. */ + protected PostLoansResponse applyForLoanResponse(PostLoansRequest request) { + Long loanId = applyForLoan(request); + return new PostLoansResponse().resourceId(loanId).resourceExternalId(getLoanDetails(loanId).getExternalId()); } protected PostLoansLoanIdResponse disburseLoan(String date, Integer loanId, String transactionAmount, String externalId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java index f1ce9ff0ddf..02bf86fe99d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java @@ -22,11 +22,6 @@ import static org.apache.fineract.client.feign.util.FeignCalls.fail; import static org.apache.fineract.client.feign.util.FeignCalls.ok; -import io.restassured.builder.RequestSpecBuilder; -import io.restassured.builder.ResponseSpecBuilder; -import io.restassured.http.ContentType; -import io.restassured.specification.RequestSpecification; -import io.restassured.specification.ResponseSpecification; import java.math.BigDecimal; import java.util.List; import java.util.Map; @@ -86,7 +81,6 @@ public class FeignLoanHelper { private static final String CREATE_LOAN_PRODUCT_URL = "/fineract-provider/api/v1/loanproducts?" + Utils.TENANT_IDENTIFIER; - private static final String APPLY_LOAN_URL = "/fineract-provider/api/v1/loans?" + Utils.TENANT_IDENTIFIER; private final FineractFeignClient fineractClient; @@ -203,13 +197,6 @@ public List getAdvancedPaymentAllocationRules(Long loanId) return ok(() -> fineractClient.defaultApi().getAdvancedPaymentAllocationRulesOfLoan(loanId)); } - // TODO: Rewrite to use fineract-client instead! - public Long applyForLoanFromJson(String loanApplicationJson) { - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - Integer loanId = Utils.performServerPost(jsonRequestSpec(), responseSpec, APPLY_LOAN_URL, loanApplicationJson, "loanId"); - return loanId.longValue(); - } - public GetLoanProductsProductIdResponse retrieveLoanProduct(Long productId) { return ok(() -> fineractClient.loanProducts().retrieveOneLoanProduct(productId)); } @@ -523,14 +510,6 @@ public CallFailedRuntimeException createRescheduleRequestExpectingError(PostCrea return fail(() -> fineractClient.rescheduleLoans().createRescheduleLoan(request)); } - // TODO: Rewrite to use fineract-client instead! - private static RequestSpecification jsonRequestSpec() { - Utils.initializeRESTAssured(); - return new RequestSpecBuilder().setContentType(ContentType.JSON) - .addHeader("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()) - .addHeader("Fineract-Platform-TenantId", "default").build(); - } - public PostUpdateRescheduleLoansResponse approveRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) { return ok(() -> fineractClient.rescheduleLoans().updateRescheduleLoan(scheduleId, request, "approve")); } From 62c05750503f08882034da9ee942347b25a0ca54 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Mon, 24 Aug 2026 13:20:46 +0530 Subject: [PATCH 11/15] FINERACT-2779: build loan products with PostLoanProductsRequest instead of JSON LoanProductTestBuilder only spoke JSON, so every Feign test that needed a loan product handed a string to createLoanProductFromJson, which parsed it straight back into PostLoanProductsRequest. Add buildRequest(), the typed counterpart of build(), so callers can skip the round trip. Six of the map's keys have no counterpart on the request model: syncExpectedWithDisbursementDate, mandatoryGuarantee, minimumGuaranteeFromGuarantor, minimumGuaranteeFromOwnFunds, minimumGap and maximumGap. The JSON path dropped them as unknown properties, so leaving them unset sends the same body and needs no schema change. LoanProductTestBuilderParityTest pins the two builders together: 31 builder configurations are serialised and deserialised the way the JSON path did, and the result must equal the typed request. Signed-off-by: DeathGun44 --- .../common/loans/LoanProductTestBuilder.java | 305 ++++++++++++++++++ .../LoanProductTestBuilderParityTest.java | 166 ++++++++++ 2 files changed, 471 insertions(+) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilderParityTest.java diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index 57926bec6a4..91e17870b31 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -20,6 +20,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -28,7 +29,12 @@ import java.util.Optional; import lombok.Builder; import org.apache.fineract.client.models.AdvancedPaymentData; +import org.apache.fineract.client.models.AllowAttributeOverrides; import org.apache.fineract.client.models.CreditAllocationData; +import org.apache.fineract.client.models.LoanProductChargeData; +import org.apache.fineract.client.models.LoanProductChargeToGLAccountMapper; +import org.apache.fineract.client.models.PostChargeOffReasonToExpenseAccountMappings; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; @@ -361,6 +367,281 @@ public HashMap build(final String chargeId, final Long delinquen return map; } + public PostLoanProductsRequest buildRequest() { + return buildRequest(null, null); + } + + public PostLoanProductsRequest buildRequest(final String chargeId) { + return buildRequest(chargeId, null); + } + + /** + * Typed counterpart of {@link #build(String, Long)}, for callers on the Feign client. + * + * Six keys the map carries have no counterpart on {@link PostLoanProductsRequest}: + * {@code syncExpectedWithDisbursementDate}, {@code mandatoryGuarantee}, {@code minimumGuaranteeFromGuarantor}, + * {@code minimumGuaranteeFromOwnFunds}, {@code minimumGap} and {@code maximumGap}. Deserialising the map's JSON + * into the request model dropped them as unknown properties, so leaving them unset here sends the same body. + */ + public PostLoanProductsRequest buildRequest(final String chargeId, final Long delinquencyBucketId) { + final PostLoanProductsRequest request = new PostLoanProductsRequest(); + + if (chargeId != null) { + request.charges(new ArrayList<>(List.of(new LoanProductChargeData().id(toLong(chargeId))))); + } + request.name(this.nameOfLoanProduct); + request.shortName(this.shortName); + request.externalId(this.externalId); + request.currencyCode(this.currencyCode); + request.locale(LOCALE); + request.dateFormat("dd MMMM yyyy"); + request.digitsAfterDecimal(toInteger(this.digitsAfterDecimal)); + request.inMultiplesOf(toInteger(this.inMultiplesOf)); + request.principal(toDouble(this.principal)); + request.numberOfRepayments(toInteger(this.numberOfRepayments)); + request.repaymentEvery(toInteger(this.repaymentPeriod)); + request.repaymentFrequencyType(toLong(this.repaymentFrequency)); + request.interestRatePerPeriod(toDouble(this.interestRatePerPeriod)); + request.interestRateFrequencyType(toInteger(this.interestRateFrequencyType)); + request.amortizationType(toInteger(this.amortizationType)); + request.fixedPrincipalPercentagePerInstallment(toBigDecimal(this.fixedPrincipalPercentagePerInstallment)); + request.interestType(toInteger(this.interestType)); + request.interestCalculationPeriodType(toInteger(this.interestCalculationPeriodType)); + request.inArrearsTolerance(toInteger(this.inArrearsTolerance)); + request.transactionProcessingStrategyCode(this.transactionProcessingStrategyCode); + request.paymentAllocation(this.advancedPaymentAllocations); + request.creditAllocation(this.creditAllocations); + request.accountingRule(toInteger(this.accountingRule)); + request.minPrincipal(toDouble(this.minPrincipal)); + request.maxPrincipal(toDouble(this.maxPrincipal)); + request.isEqualAmortization(this.isEqualAmortization); + request.overdueDaysForNPA(toInteger(this.overdueDaysForNPA)); + request.loanScheduleType(this.loanScheduleType); + request.loanScheduleProcessingType(this.loanScheduleProcessingType); + + if (this.minimumDaysBetweenDisbursalAndFirstRepayment != null) { + request.minimumDaysBetweenDisbursalAndFirstRepayment(toInteger(this.minimumDaysBetweenDisbursalAndFirstRepayment)); + } + if (this.multiDisburseLoan) { + request.multiDisburseLoan(this.multiDisburseLoan); + request.allowFullTermForTranche(this.allowFullTermForTranche); + request.maxTrancheCount(toInteger(this.maxTrancheCount)); + request.outstandingLoanBalance(toDouble(this.outstandingLoanBalance)); + request.disallowExpectedDisbursements(this.disallowExpectedDisbursements); + if (this.disallowExpectedDisbursements) { + request.allowApprovedDisbursedAmountsOverApplied(this.allowApprovedDisbursedAmountsOverApplied); + request.overAppliedCalculationType(this.overAppliedCalculationType); + request.overAppliedNumber(this.overAppliedNumber); + } + } + if (this.canDefineInstallmentAmount) { + request.canDefineInstallmentAmount(this.canDefineInstallmentAmount); + } + // Always send allowFullTermForTranche when it's true (for validation testing of single-disburse scenarios) + if (this.allowFullTermForTranche && !this.multiDisburseLoan) { + request.allowFullTermForTranche(this.allowFullTermForTranche); + } + + if (this.fullAccountingConfig != null) { + this.fullAccountingConfig.applyTo(request); + } else if (this.accountingRule.equals(ACCRUAL_UPFRONT) || this.accountingRule.equals(ACCRUAL_PERIODIC)) { + applyAccountMappingForAccrualBased(request, this.feeAndPenaltyAssetAccount); + } else if (this.accountingRule.equals(CASH_BASED)) { + applyAccountMappingForCashBased(request); + } + request.daysInMonthType(toInteger(this.daysInMonthType)); + request.daysInYearType(toInteger(this.daysInYearType)); + request.isInterestRecalculationEnabled(this.isInterestRecalculationEnabled); + if (this.isInterestRecalculationEnabled) { + request.interestRecalculationCompoundingMethod(toInteger(this.interestRecalculationCompoundingMethod)); + request.rescheduleStrategyMethod(toInteger(this.rescheduleStrategyMethod)); + request.recalculationRestFrequencyType(toInteger(this.recalculationRestFrequencyType)); + request.recalculationRestFrequencyInterval(toInteger(this.recalculationRestFrequencyInterval)); + if (!RECALCULATION_COMPOUNDING_METHOD_NONE.equals(this.interestRecalculationCompoundingMethod)) { + request.recalculationCompoundingFrequencyType(toInteger(this.recalculationCompoundingFrequencyType)); + request.recalculationCompoundingFrequencyInterval(toInteger(this.recalculationCompoundingFrequencyInterval)); + } + request.preClosureInterestCalculationStrategy(toInteger(this.preCloseInterestCalculationStrategy)); + if (this.isArrearsBasedOnOriginalSchedule != null) { + request.isArrearsBasedOnOriginalSchedule(Boolean.valueOf(this.isArrearsBasedOnOriginalSchedule)); + } + request.recalculationCompoundingFrequencyOnDayType(this.recalculationCompoundingFrequencyOnDayType); + request.recalculationCompoundingFrequencyDayOfWeekType(this.recalculationCompoundingFrequencyDayOfWeekType); + request.recalculationRestFrequencyOnDayType(this.recalculationRestFrequencyOnDayType); + request.recalculationRestFrequencyDayOfWeekType(this.recalculationRestFrequencyDayOfWeekType); + } + if (this.holdGuaranteeFunds != null) { + request.holdGuaranteeFunds(this.holdGuaranteeFunds); + } + request.graceOnPrincipalPayment(toInteger(this.graceOnPrincipalPayment)); + request.graceOnInterestPayment(toInteger(this.graceOnInterestPayment)); + if (this.allowAttributeOverrides != null) { + request.allowAttributeOverrides(toAllowAttributeOverrides(this.allowAttributeOverrides)); + } + request.allowPartialPeriodInterestCalculation(this.allowPartialPeriodInterestCalculation); + request.allowVariableInstallments(this.allowVariableInstallments); + if (this.installmentAmountInMultiplesOf != null) { + request.installmentAmountInMultiplesOf(toInteger(this.installmentAmountInMultiplesOf)); + } + + // Delinquency Bucket + if (delinquencyBucketId != null) { + request.delinquencyBucketId(delinquencyBucketId); + } + if (this.delinquencyBucketId != null) { + request.delinquencyBucketId(this.delinquencyBucketId); + } + + if (this.feeToIncomeAccountMappings != null) { + request.feeToIncomeAccountMappings(toChargeToGLAccountMappers(this.feeToIncomeAccountMappings)); + } + if (this.penaltyToIncomeAccountMappings != null) { + request.penaltyToIncomeAccountMappings(toChargeToGLAccountMappers(this.penaltyToIncomeAccountMappings)); + } + if (this.chargeOffReasonToExpenseAccountMappings != null) { + request.chargeOffReasonToExpenseAccountMappings(toChargeOffReasonMappings(this.chargeOffReasonToExpenseAccountMappings)); + } + if (this.dueDaysForRepaymentEvent != null) { + request.dueDaysForRepaymentEvent(this.dueDaysForRepaymentEvent); + } + if (this.overDueDaysForRepaymentEvent != null) { + request.overDueDaysForRepaymentEvent(this.overDueDaysForRepaymentEvent); + } + request.enableDownPayment(this.enableDownPayment); + if (this.disbursedAmountPercentageForDownPayment != null) { + request.disbursedAmountPercentageForDownPayment(toBigDecimal(this.disbursedAmountPercentageForDownPayment)); + } + if (this.enableAutoRepaymentForDownPayment) { + request.enableAutoRepaymentForDownPayment(this.enableAutoRepaymentForDownPayment); + } + if (this.interestRecognitionOnDisbursementDate) { + request.interestRecognitionOnDisbursementDate(this.interestRecognitionOnDisbursementDate); + } + if (this.repaymentStartDateType != null) { + request.repaymentStartDateType(this.repaymentStartDateType); + } + if (this.supportedInterestRefundTypes != null) { + request.supportedInterestRefundTypes(this.supportedInterestRefundTypes); + } + if (this.chargeOffBehaviour != null) { + request.chargeOffBehaviour(this.chargeOffBehaviour); + } + if (this.enableBuyDownFee != null) { + request.enableBuyDownFee(this.enableBuyDownFee); + } + if (this.merchantBuyDownFee != null) { + request.merchantBuyDownFee(this.merchantBuyDownFee); + } + return request; + } + + /** + * The map form carries every amount as a string, sometimes with thousands separators ("15,000.00"). Strip them the + * way the JSON path used to before parsing. + */ + private static String stripThousandsSeparators(final String value) { + return value.replaceAll("(?<=\\d),(?=\\d{3}(?!\\d))", ""); + } + + private static boolean isBlank(final String value) { + return value == null || value.isEmpty(); + } + + private static Integer toInteger(final String value) { + return isBlank(value) ? null : Integer.valueOf(stripThousandsSeparators(value)); + } + + private static Long toLong(final String value) { + return isBlank(value) ? null : Long.valueOf(stripThousandsSeparators(value)); + } + + private static Double toDouble(final String value) { + return isBlank(value) ? null : Double.valueOf(stripThousandsSeparators(value)); + } + + private static BigDecimal toBigDecimal(final String value) { + return isBlank(value) ? null : new BigDecimal(stripThousandsSeparators(value)); + } + + private static AllowAttributeOverrides toAllowAttributeOverrides(final JsonObject overrides) { + final AllowAttributeOverrides result = new AllowAttributeOverrides(); + result.amortizationType(readBoolean(overrides, "amortizationType")); + result.graceOnArrearsAgeing(readBoolean(overrides, "graceOnArrearsAgeing")); + result.graceOnPrincipalAndInterestPayment(readBoolean(overrides, "graceOnPrincipalAndInterestPayment")); + result.inArrearsTolerance(readBoolean(overrides, "inArrearsTolerance")); + result.interestCalculationPeriodType(readBoolean(overrides, "interestCalculationPeriodType")); + result.interestType(readBoolean(overrides, "interestType")); + result.repaymentEvery(readBoolean(overrides, "repaymentEvery")); + result.transactionProcessingStrategyCode(readBoolean(overrides, "transactionProcessingStrategyCode")); + return result; + } + + private static Boolean readBoolean(final JsonObject source, final String member) { + return (source.has(member) && !source.get(member).isJsonNull()) ? source.get(member).getAsBoolean() : null; + } + + private static List toChargeToGLAccountMappers(final List> mappings) { + final List mappers = new ArrayList<>(); + for (Map mapping : mappings) { + mappers.add(new LoanProductChargeToGLAccountMapper().chargeId(mapping.get("chargeId")) + .incomeAccountId(mapping.get("incomeAccountId"))); + } + return mappers; + } + + private static List toChargeOffReasonMappings(final List> mappings) { + final List result = new ArrayList<>(); + for (Map mapping : mappings) { + result.add( + new PostChargeOffReasonToExpenseAccountMappings().chargeOffReasonCodeValueId(mapping.get("chargeOffReasonCodeValueId")) + .expenseAccountId(mapping.get("expenseAccountId"))); + } + return result; + } + + private void applyAccountMappingForCashBased(final PostLoanProductsRequest request) { + for (Account account : this.accountList) { + final Long id = account.getAccountID().longValue(); + switch (account.getAccountType()) { + case ASSET -> request.fundSourceAccountId(id).loanPortfolioAccountId(id).transfersInSuspenseAccountId(id); + case INCOME -> applyIncomeAccounts(request, id); + case EXPENSE -> applyExpenseAccounts(request, id); + case LIABILITY -> request.overpaymentLiabilityAccountId(id); + default -> { + } + } + } + } + + private void applyAccountMappingForAccrualBased(final PostLoanProductsRequest request, final Account feeAndPenaltyAssetAccount) { + for (Account account : this.accountList) { + final Long id = account.getAccountID().longValue(); + switch (account.getAccountType()) { + case ASSET -> { + request.fundSourceAccountId(id).loanPortfolioAccountId(id).transfersInSuspenseAccountId(id); + final Long receivableId = feeAndPenaltyAssetAccount != null ? feeAndPenaltyAssetAccount.getAccountID().longValue() : id; + request.receivableFeeAccountId(receivableId).receivablePenaltyAccountId(receivableId).receivableInterestAccountId(id); + } + case INCOME -> applyIncomeAccounts(request, id); + case EXPENSE -> applyExpenseAccounts(request, id); + case LIABILITY -> request.overpaymentLiabilityAccountId(id); + default -> { + } + } + } + } + + private static void applyIncomeAccounts(final PostLoanProductsRequest request, final Long id) { + request.interestOnLoanAccountId(id).incomeFromFeeAccountId(id).incomeFromPenaltyAccountId(id).incomeFromRecoveryAccountId(id) + .incomeFromChargeOffInterestAccountId(id).incomeFromChargeOffFeesAccountId(id).incomeFromChargeOffPenaltyAccountId(id) + .incomeFromGoodwillCreditInterestAccountId(id).incomeFromGoodwillCreditFeesAccountId(id) + .incomeFromGoodwillCreditPenaltyAccountId(id); + } + + private static void applyExpenseAccounts(final PostLoanProductsRequest request, final Long id) { + request.writeOffAccountId(id).goodwillCreditAccountId(id).chargeOffExpenseAccountId(id).chargeOffFraudExpenseAccountId(id); + } + public LoanProductTestBuilder withExternalId(String externalId) { this.externalId = externalId; return this; @@ -926,6 +1207,30 @@ public Map toMap() { .put("incomeFromChargeOffPenaltyAccountId", Long.toString(incomeFromChargeOffPenaltyAccountId))); return map; } + + public void applyTo(final PostLoanProductsRequest request) { + request.fundSourceAccountId(fundSourceAccountId); + request.loanPortfolioAccountId(loanPortfolioAccountId); + request.transfersInSuspenseAccountId(transfersInSuspenseAccountId); + request.interestOnLoanAccountId(interestOnLoanAccountId); + request.incomeFromFeeAccountId(incomeFromFeeAccountId); + request.incomeFromPenaltyAccountId(incomeFromPenaltyAccountId); + request.incomeFromRecoveryAccountId(incomeFromRecoveryAccountId); + request.writeOffAccountId(writeOffAccountId); + request.overpaymentLiabilityAccountId(overpaymentLiabilityAccountId); + request.receivableInterestAccountId(receivableInterestAccountId); + request.receivableFeeAccountId(receivableFeeAccountId); + request.receivablePenaltyAccountId(receivablePenaltyAccountId); + request.goodwillCreditAccountId(goodwillCreditAccountId); + request.incomeFromGoodwillCreditInterestAccountId(incomeFromGoodwillCreditInterestAccountId); + request.incomeFromGoodwillCreditFeesAccountId(incomeFromGoodwillCreditFeesAccountId); + request.incomeFromGoodwillCreditPenaltyAccountId(incomeFromGoodwillCreditPenaltyAccountId); + request.incomeFromChargeOffInterestAccountId(incomeFromChargeOffInterestAccountId); + request.incomeFromChargeOffFeesAccountId(incomeFromChargeOffFeesAccountId); + request.chargeOffExpenseAccountId(chargeOffExpenseAccountId); + request.chargeOffFraudExpenseAccountId(chargeOffFraudExpenseAccountId); + request.incomeFromChargeOffPenaltyAccountId(incomeFromChargeOffPenaltyAccountId); + } } public LoanProductTestBuilder withEnableBuyDownFee(final Boolean enableBuyDownFee) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilderParityTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilderParityTest.java new file mode 100644 index 00000000000..cc37244cc8b --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilderParityTest.java @@ -0,0 +1,166 @@ +/** + * 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.common.loans; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; +import org.apache.fineract.client.feign.ObjectMapperFactory; +import org.apache.fineract.client.models.AdvancedPaymentData; +import org.apache.fineract.client.models.CreditAllocationData; +import org.apache.fineract.client.models.PaymentAllocationOrder; +import org.apache.fineract.client.models.PostLoanProductsRequest; +import org.apache.fineract.integrationtests.common.accounting.Account; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +/** + * Pins {@link LoanProductTestBuilder#buildRequest(String, Long)} to {@link LoanProductTestBuilder#build(String, Long)}: + * the map is serialised and deserialised into the request model the way the retired JSON path did, and the result must + * equal the typed request. Any drift between the two builders fails here rather than in a loan product test. + */ +public class LoanProductTestBuilderParityTest { + + private static final Account ASSET = new Account(11, Account.AccountType.ASSET); + private static final Account INCOME = new Account(22, Account.AccountType.INCOME); + private static final Account EXPENSE = new Account(33, Account.AccountType.EXPENSE); + private static final Account LIABILITY = new Account(44, Account.AccountType.LIABILITY); + private static final Account[] ACCOUNTS = { ASSET, INCOME, EXPENSE, LIABILITY }; + + private static AdvancedPaymentData defaultAllocation() { + AdvancedPaymentData data = new AdvancedPaymentData(); + data.setTransactionType("DEFAULT"); + data.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT"); + List orders = new ArrayList<>(); + PaymentAllocationOrder order = new PaymentAllocationOrder(); + order.setPaymentAllocationRule("PAST_DUE_PENALTY"); + order.setOrder(1); + orders.add(order); + data.setPaymentAllocationOrder(orders); + return data; + } + + private static CreditAllocationData chargebackAllocation() { + CreditAllocationData data = new CreditAllocationData(); + data.setTransactionType("CHARGEBACK"); + return data; + } + + private record Case(String name, Supplier builder, String chargeId, Long delinquencyBucketId) { + } + + private static List cases() { + List cases = new ArrayList<>(); + cases.add(new Case("defaults", LoanProductTestBuilder::new, null, null)); + cases.add(new Case("charge + bucket", LoanProductTestBuilder::new, "7", 9L)); + cases.add(new Case("thousands separators", + () -> new LoanProductTestBuilder().withPrincipal("15,000.00").withMinPrincipal("1,000.00").withMaxPrincipal("100,000.00"), + null, null)); + cases.add(new Case("empty moratorium", () -> new LoanProductTestBuilder().withMoratorium("", ""), null, null)); + cases.add(new Case("zero moratorium", () -> new LoanProductTestBuilder().withMoratorium("0", "0"), null, null)); + cases.add(new Case("declining balance monthly", + () -> new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4").withRepaymentAfterEvery("1") + .withRepaymentTypeAsMonth().withinterestRatePerPeriod("1").withInterestRateFrequencyTypeAsMonths() + .withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() + .withInterestCalculationPeriodTypeAsRepaymentPeriod(true), + null, null)); + cases.add(new Case("flat interest days", () -> new LoanProductTestBuilder().withInterestTypeAsFlat().withRepaymentTypeAsDays() + .withInterestCalculationPeriodTypeAsDays().withInterestRateFrequencyTypeAsYear(), null, null)); + cases.add(new Case("weekly", () -> new LoanProductTestBuilder().withRepaymentTypeAsWeek(), null, null)); + cases.add( + new Case("equal principal", () -> new LoanProductTestBuilder().withAmortizationTypeAsEqualPrincipalPayment(), null, null)); + cases.add(new Case("multi disburse", () -> new LoanProductTestBuilder().withMultiDisburse().withMaxTrancheCount("5"), null, null)); + cases.add(new Case("multi disburse disallow expected", + () -> new LoanProductTestBuilder().withMultiDisburse().withDisallowExpectedDisbursements(true), null, null)); + cases.add(new Case("tranches", () -> new LoanProductTestBuilder().withTranches(true), null, null)); + cases.add(new Case("periodic accrual accounting", () -> new LoanProductTestBuilder().withAccountingRulePeriodicAccrual(ACCOUNTS), + null, null)); + cases.add(new Case("periodic accrual with fee/penalty asset account", () -> new LoanProductTestBuilder() + .withAccountingRulePeriodicAccrual(ACCOUNTS).withFeeAndPenaltyAssetAccount(new Account(55, Account.AccountType.ASSET)), + null, null)); + cases.add(new Case("cash based accounting", + () -> new LoanProductTestBuilder().withAccounting(LoanProductTestBuilder.CASH_BASED, ACCOUNTS), null, null)); + cases.add(new Case("full accounting config", () -> new LoanProductTestBuilder().withFullAccountingConfig( + LoanProductTestBuilder.ACCRUAL_PERIODIC, + LoanProductTestBuilder.FullAccountingConfig.builder().fundSourceAccountId(1L).loanPortfolioAccountId(2L) + .transfersInSuspenseAccountId(3L).interestOnLoanAccountId(4L).incomeFromFeeAccountId(5L) + .incomeFromPenaltyAccountId(6L).incomeFromRecoveryAccountId(7L).writeOffAccountId(8L) + .overpaymentLiabilityAccountId(9L).receivableInterestAccountId(10L).receivableFeeAccountId(11L) + .receivablePenaltyAccountId(12L).goodwillCreditAccountId(13L).incomeFromGoodwillCreditInterestAccountId(14L) + .incomeFromGoodwillCreditFeesAccountId(15L).incomeFromGoodwillCreditPenaltyAccountId(16L) + .incomeFromChargeOffInterestAccountId(17L).incomeFromChargeOffFeesAccountId(18L).chargeOffExpenseAccountId(19L) + .chargeOffFraudExpenseAccountId(20L).incomeFromChargeOffPenaltyAccountId(21L).build()), + null, null)); + cases.add(new Case("advanced payment allocation", + () -> new LoanProductTestBuilder().withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) + .withLoanScheduleType(LoanScheduleType.PROGRESSIVE) + .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL) + .addAdvancedPaymentAllocation(defaultAllocation()), + null, null)); + cases.add(new Case("credit allocations", + () -> new LoanProductTestBuilder().withRepaymentStrategy(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) + .addAdvancedPaymentAllocation(defaultAllocation()).addCreditAllocations(chargebackAllocation()), + null, null)); + cases.add(new Case("down payment", () -> new LoanProductTestBuilder().withEnableDownPayment(true, "25", true), null, null)); + cases.add(new Case("down payment no auto repayment", () -> new LoanProductTestBuilder().withEnableDownPayment(true, "12.5", false), + null, null)); + cases.add(new Case("interest recalculation", () -> new LoanProductTestBuilder() + .withInterestRecalculationDetails(LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST, + LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN, + LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE) + .withInterestRecalculationRestFrequencyDetails(LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", null, null) + .withInterestRecalculationCompoundingFrequencyDetails(LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_MONTHLY, "1", + null, null), + null, null)); + cases.add( + new Case("days in month/year", () -> new LoanProductTestBuilder().withDaysInMonth("30").withDaysInYear("365"), null, null)); + cases.add(new Case("supported interest refund types", + () -> new LoanProductTestBuilder().withSupportedInterestRefundTypes("PAYOUT_REFUND", "MERCHANT_ISSUED_REFUND"), null, + null)); + cases.add(new Case("short name", () -> new LoanProductTestBuilder().withShortName("ABCD"), null, null)); + cases.add(new Case("null number of repayments", () -> new LoanProductTestBuilder().withNumberOfRepayments(null), null, null)); + cases.add(new Case("null interest rate", () -> new LoanProductTestBuilder().withinterestRatePerPeriod(null), null, null)); + cases.add(new Case("down payment with null percentage", () -> new LoanProductTestBuilder().withEnableDownPayment(true, null, false), + null, null)); + cases.add(new Case("down payment percentage with six decimals", + () -> new LoanProductTestBuilder().withEnableDownPayment(true, "12.55555555", false), null, null)); + cases.add(new Case("auto repayment without down payment", + () -> new LoanProductTestBuilder().withEnableDownPayment(false, null, true), null, null)); + cases.add(new Case("in arrears tolerance", () -> new LoanProductTestBuilder().withInArrearsTolerance("1001"), null, null)); + cases.add(new Case("no accounting accounts", () -> new LoanProductTestBuilder().withAccounting("1", null), null, null)); + return cases; + } + + @TestFactory + List mapAndTypedRequestAgree() { + return cases().stream().map(testCase -> DynamicTest.dynamicTest(testCase.name(), () -> { + LoanProductTestBuilder builder = testCase.builder().get(); + String json = new com.google.gson.Gson().toJson(builder.build(testCase.chargeId(), testCase.delinquencyBucketId())); + String sanitized = json.replaceAll("(?<=\\d),(?=\\d{3}(?!\\d))", ""); + PostLoanProductsRequest fromJson = ObjectMapperFactory.getShared().readValue(sanitized, PostLoanProductsRequest.class); + PostLoanProductsRequest typed = builder.buildRequest(testCase.chargeId(), testCase.delinquencyBucketId()); + assertEquals(ObjectMapperFactory.getShared().writeValueAsString(fromJson), + ObjectMapperFactory.getShared().writeValueAsString(typed), testCase.name()); + })).toList(); + } +} From ec00c9ec58a7de73f2a391768a0d839db8925040 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Mon, 24 Aug 2026 13:20:56 +0530 Subject: [PATCH 12/15] FINERACT-2779: type the loan product creations in the Feign loan tests Replace every createLoanProductFromJson / getLoanProductError / getLoanProductId call that took a hand-built JSON string with the typed request from LoanProductTestBuilder.buildRequest(). The Utils.convertToJson and Gson().toJson wrappers around the builder's map go with them. Three helpers now return what they actually build: loanProductJson() -> loanProductRequest(), buildLoanProductJson() -> buildLoanProductRequest(), createLoanJSON() -> createLoanProductRequest(), and loanProductTestBuilder() -> customizedLoanProduct(), which returns a request rather than a builder. Signed-off-by: DeathGun44 --- ...ntAllocationLoanRepaymentScheduleTest.java | 24 ++++---- ...ientLoanChargeExternalIntegrationTest.java | 5 +- ...RefundandRepaymentTypeIntegrationTest.java | 5 +- ...nMultipleDisbursementsIntegrationTest.java | 5 +- ...eMultipleDisbursementsIntegrationTest.java | 5 +- .../ExternalIdSupportIntegrationTest.java | 29 +++++----- .../GroupLoanIntegrationTest.java | 9 +-- .../fineract/integrationtests/GroupTest.java | 4 +- ...OverlappingDownPaymentInstallmentTest.java | 13 +++-- ...LoanAccountsContainsCurrencyFieldTest.java | 7 ++- ...mentWithAdvancedPaymentAllocationTest.java | 7 ++- ...lingWithAdvancedPaymentAllocationTest.java | 9 +-- .../LoanDownPaymentTransactionTypeTest.java | 7 +-- ...ncedPaymentAllocationIntegrationTests.java | 57 ++++++++++--------- ...WithCreditAllocationsIntegrationTests.java | 40 +++++++------ ...oductWithDownPaymentConfigurationTest.java | 27 ++++----- ...RepaymentRescheduleAtDisbursementTest.java | 7 ++- ...nRepaymentScheduleWithDownPaymentTest.java | 25 ++++---- ...nRescheduleOnDecliningBalanceLoanTest.java | 8 +-- .../LoanReschedulingWithinCenterTest.java | 9 +-- ...oanTransactionAuditingIntegrationTest.java | 7 ++- .../LoanTransactionChargebackTest.java | 6 +- ...nTransactionInterestPaymentWaiverTest.java | 6 +- ...ocessForAdvancedPaymentAllocationTest.java | 9 +-- ...nTransactionReverseReplayRelationTest.java | 4 +- ...ncedPaymentAllocationIntegrationTests.java | 9 +-- ...eOffWithAdvancedPaymentAllocationTest.java | 9 +-- ...oansWithAdvancedPaymentAllocationTest.java | 7 ++- 28 files changed, 190 insertions(+), 169 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java index aaf75cdd2e9..f0b31f9dfd8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java @@ -6302,7 +6302,7 @@ private static Long createLoanProduct(final String principal, final String repay boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, LoanScheduleProcessingType loanScheduleProcessingType, AdvancedPaymentData allocationRuleData, final Account... accounts) { LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths() @@ -6311,14 +6311,14 @@ private static Long createLoanProduct(final String principal, final String repay .addAdvancedPaymentAllocation(allocationRuleData).withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .withInterestTypeAsDecliningBalance().withMultiDisburse().withDisallowExpectedDisbursements(true) .withLoanScheduleType(loanScheduleType).withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30") - .withDaysInYear("365").withMoratorium("0", "0").build(null); - return loanHelper.createLoanProductFromJson(loanProductJSON); + .withDaysInYear("365").withMoratorium("0", "0").buildRequest(null); + return loanHelper.createLoanProduct(loanProductRequest).getResourceId(); } private static Long createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments, boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, final Account... accounts) { LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths() @@ -6326,15 +6326,15 @@ private static Long createLoanProduct(final String principal, final String repay .withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts) .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withInterestTypeAsDecliningBalance().withMultiDisburse() .withDisallowExpectedDisbursements(true).withLoanScheduleType(loanScheduleType).withDaysInMonth("30").withDaysInYear("365") - .withMoratorium("0", "0").build(null); - return loanHelper.createLoanProductFromJson(loanProductJSON); + .withMoratorium("0", "0").buildRequest(null); + return loanHelper.createLoanProduct(loanProductRequest).getResourceId(); } private static ArrayList> createLoanProductGetError(final String principal, final String repaymentAfterEvery, final String numberOfRepayments, boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, LoanScheduleProcessingType loanScheduleProcessingType, AdvancedPaymentData allocationRuleData, final Account... accounts) { LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths() @@ -6343,8 +6343,8 @@ private static ArrayList> createLoanProductGetError(fina .addAdvancedPaymentAllocation(allocationRuleData).withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .withInterestTypeAsDecliningBalance().withMultiDisburse().withDisallowExpectedDisbursements(true) .withLoanScheduleType(loanScheduleType).withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30") - .withDaysInYear("365").withMoratorium("0", "0").build(null); - return loanHelper.getLoanProductError(loanProductJSON, CommonConstants.RESPONSE_ERROR); + .withDaysInYear("365").withMoratorium("0", "0").buildRequest(null); + return loanHelper.getLoanProductError(loanProductRequest, CommonConstants.RESPONSE_ERROR); } private static Long createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments, @@ -6355,7 +6355,7 @@ private static Long createLoanProduct(final String principal, final String repay AdvancedPaymentData merchantIssuedRefundAllocation = createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"); AdvancedPaymentData payoutRefundAllocation = createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT"); LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(downPaymentEnabled, downPaymentPercentage, autoPayForDownPayment).withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths() @@ -6366,8 +6366,8 @@ private static Long createLoanProduct(final String principal, final String repay .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withInterestTypeAsDecliningBalance().withMultiDisburse() .withDisallowExpectedDisbursements(true).withLoanScheduleType(loanScheduleType) .withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30").withDaysInYear("365") - .withMoratorium("0", "0").build(null); - return loanHelper.createLoanProductFromJson(loanProductJSON); + .withMoratorium("0", "0").buildRequest(null); + return loanHelper.createLoanProduct(loanProductRequest).getResourceId(); } private static void validatePeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, LocalDate paidDate, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java index 1ac65d815c4..2a975c95b86 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java @@ -25,6 +25,7 @@ import java.math.BigDecimal; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.GetLoansLoanIdChargesChargeIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; @@ -104,8 +105,8 @@ private Long createLoanProduct(final boolean multiDisburseLoan, final String acc if (multiDisburseLoan) { builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true); } - final String loanProductJSON = builder.build(null); - return createLoanProductFromJson(loanProductJSON); + final PostLoanProductsRequest loanProductRequest = builder.buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplication(final Long clientId, final Long loanProductId, String principal) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java index b70e467cfb9..0fc43c02eb3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java @@ -39,6 +39,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdSummary; import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; @@ -103,8 +104,8 @@ private Long createLoanProduct(LoanProductTestBuilder loanProductTestBuilder, fi loanProductTestBuilder = loanProductTestBuilder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true); loanProductTestBuilder = loanProductTestBuilder.withMaxTrancheCount("30"); } - final String loanProductJSON = loanProductTestBuilder.build(null); - return createLoanProductFromJson(loanProductJSON); + final PostLoanProductsRequest loanProductRequest = loanProductTestBuilder.buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplication(final Long clientID, final Long loanProductID, String principal, String submitDate, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java index 169da54bc19..21c6e64718d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java @@ -30,6 +30,7 @@ import java.util.List; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignRawHttpHelper; @@ -74,8 +75,8 @@ private Long createLoanProduct(final boolean multiDisburseLoan) { builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true); builder = builder.withMaxTrancheCount("30"); } - final String loanProductJSON = builder.build(null); - return createLoanProductFromJson(loanProductJSON); + final PostLoanProductsRequest loanProductRequest = builder.buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplicationWithTranches(final Long clientId, final Long loanProductID, String principal, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java index 29a16cc5019..0fc995bf636 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java @@ -22,6 +22,7 @@ import java.util.List; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; @@ -85,8 +86,8 @@ private Long createLoanProduct(final boolean isInterestRecalculationEnabled) { recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType); } - final String loanProductJSON = builder.build(null); - return createLoanProductFromJson(loanProductJSON); + final PostLoanProductsRequest loanProductRequest = builder.buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplication(final Long clientId, final Long loanProductID, String principal, String submitDate, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java index a8ad3878615..203281db33c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java @@ -45,6 +45,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.PostDelinquencyBucketResponse; import org.apache.fineract.client.models.PostDelinquencyRangeResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; @@ -97,13 +98,13 @@ public void test() { Long penalty2 = chargesHelper.createCharge(ChargeRequestBuilders.loanSpecifiedDueDateAccountTransferFee(10.0, true)) .getResourceId(); - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat() .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0") - .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).build(null); - final Integer loanProductID = getLoanProductId(loanProductJSON); + .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).buildRequest(null); + final Integer loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); @@ -399,11 +400,11 @@ loanExternalIdStr, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM // Create a loan with interest and test the rest of the transactions - final String loanProductWithInterestJSON = new LoanProductTestBuilder().withPrincipal("10000.0").withRepaymentTypeAsMonth() - .withRepaymentAfterEvery("2").withNumberOfRepayments("5").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") - .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat() - .withAccounting("1", null).build(null); - final Integer loanProductWithInterestID = getLoanProductId(loanProductWithInterestJSON); + final PostLoanProductsRequest loanProductWithInterestRequest = new LoanProductTestBuilder().withPrincipal("10000.0") + .withRepaymentTypeAsMonth().withRepaymentAfterEvery("2").withNumberOfRepayments("5").withRepaymentTypeAsMonth() + .withinterestRatePerPeriod("1").withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment() + .withInterestTypeAsFlat().withAccounting("1", null).buildRequest(null); + final Integer loanProductWithInterestID = getLoanProductId(loanProductWithInterestRequest); LocalDate aMonthBefore = LocalDate.of(2022, 8, 7); String formattedDate = dateFormatter.format(aMonthBefore); @@ -666,13 +667,13 @@ public void negativeTest() { final Account expenseAccount = accountHelper.createExpenseAccount("extIdExpense"); final Account overpaymentAccount = accountHelper.createLiabilityAccount("extIdOverpayment"); - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat() .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0") - .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).build(null); - final Integer loanProductID = getLoanProductId(loanProductJSON); + .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).buildRequest(null); + final Integer loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); @@ -826,14 +827,14 @@ public void loan() { PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper .createBucket(new DelinquencyBucketRequest().name(Utils.randomStringGenerator("DLQ_B_", 10)).ranges(rangeIds)); - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment() .withInterestTypeAsDecliningBalance().withAccountingRuleAsNone() .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365") .withMoratorium("0", "0").withDelinquencyBucket(delinquencyBucketResponse.getResourceId()) - .withInArrearsTolerance("1001").withMultiDisburse().withDisallowExpectedDisbursements(true).build(null); - final Integer loanProductID = getLoanProductId(loanProductJSON); + .withInArrearsTolerance("1001").withMultiDisburse().withDisallowExpectedDisbursements(true).buildRequest(null); + final Integer loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java index ae951108a8a..9486832e906 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupLoanIntegrationTest.java @@ -31,6 +31,7 @@ import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdStatus; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.helpers.FeignGlimHelper; @@ -80,7 +81,7 @@ public void checkGroupLoanCreateAndDisburseFlow() { final Long groupId = groupHelper.createActiveGroup().getResourceId(); groupHelper.associateClient(groupId, clientId); - final Long loanProductId = createLoanProductFromJson(loanProductJson()); + final Long loanProductId = createLoanProduct(loanProductRequest()); final Long loanId = applyGroupLoan(groupId, loanProductId); final List periods = getLoanDetails(loanId).getRepaymentSchedule().getPeriods(); @@ -131,7 +132,7 @@ private FeignGlimHelper.GlimApplication applyGlim() { final Long clientId = createClient(); currentGroupId = groupHelper.createActiveGroup().getResourceId(); groupHelper.associateClient(currentGroupId, clientId); - final Long loanProductId = createLoanProductFromJson(loanProductJson()); + final Long loanProductId = createLoanProduct(loanProductRequest()); return glimHelper.applyGlim(loanApplication(loanProductId)// .groupId(currentGroupId)// @@ -163,14 +164,14 @@ private PostLoansRequest loanApplication(Long loanProductId) { .dateFormat(LoanTestData.DATETIME_PATTERN); } - private String loanProductJson() { + private PostLoanProductsRequest loanProductRequest() { return new LoanProductTestBuilder()// .withPrincipal(PRODUCT_PRINCIPAL)// .withNumberOfRepayments(PRODUCT_NUMBER_OF_REPAYMENTS)// .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth()// .withinterestRatePerPeriod(PRODUCT_INTEREST_RATE).withInterestRateFrequencyTypeAsMonths()// .withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance()// - .build(null); + .buildRequest(null); } private GetLoansLoanIdStatus loanStatus(Long loanId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java index d239237c056..a82268d628e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java @@ -148,9 +148,9 @@ public void assignStaffToGroup() { "Verify assigned staff id is the same as id sent"); // create a client loan and disburse it (loan officer starts unset) - final Long loanProductId = createLoanProductFromJson( + final Long loanProductId = createLoanProduct( new LoanProductTestBuilder().withPrincipal(PRINCIPAL).withNumberOfRepayments(NUMBER_OF_REPAYMENTS) - .withinterestRatePerPeriod(INTEREST_RATE_PER_PERIOD).withInterestRateFrequencyTypeAsYear().build(null)); + .withinterestRatePerPeriod(INTEREST_RATE_PER_PERIOD).withInterestRateFrequencyTypeAsYear().buildRequest(null)); final Long loanId = applyForLoan(LoanRequestBuilders.applyLoan(clientId, loanProductId, LOAN_DATE, 10000.0, 4)); approveLoan(LOAN_DATE, loanId.intValue()); disburseLoanWithNetDisbursalAmount(loanId, LOAN_DATE, getLoanDetails(loanId).getNetDisbursalAmount().toPlainString()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java index 91a34507da9..96cb3b2bb38 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java @@ -32,6 +32,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdTransactions; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansRequest; @@ -774,14 +775,14 @@ private Long createLoanAccountMultipleRepaymentsDisbursement(final Long clientId private GetLoanProductsProductIdResponse createLoanProductWithEnableDownPaymentAndMultipleDisbursements(Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, boolean enableAutoRepaymentForDownPayment) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("2").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365") .withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true) .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) - .build(null); - final Long loanProductId = createLoanProductFromJson(loanProductJSON); + .buildRequest(null); + final Long loanProductId = createLoanProduct(loanProductRequest); return retrieveLoanProduct(loanProductId); } @@ -789,14 +790,14 @@ private GetLoanProductsProductIdResponse createLoanProductWithAdvancedPaymentStr Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, boolean enableAutoRepaymentForDownPayment, AdvancedPaymentData... advancedPaymentData) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("2").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365") .withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true) .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) - .addAdvancedPaymentAllocation(advancedPaymentData).withLoanScheduleType(LoanScheduleType.PROGRESSIVE).build(null); - final Long loanProductId = createLoanProductFromJson(loanProductJSON); + .addAdvancedPaymentAllocation(advancedPaymentData).withLoanScheduleType(LoanScheduleType.PROGRESSIVE).buildRequest(null); + final Long loanProductId = createLoanProduct(loanProductRequest); return retrieveLoanProduct(loanProductId); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java index 0512a7e9059..a7aaaa7784e 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java @@ -27,6 +27,7 @@ import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse; import org.apache.fineract.client.models.GetClientsLoanAccounts; import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; @@ -59,7 +60,7 @@ public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() { globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_AUTO_GENERATED_EXTERNAL_ID, new PutGlobalConfigurationsRequest().enabled(false)); - final Long loanProductId = createLoanProductFromJson(buildLoanProductJson()); + final Long loanProductId = createLoanProduct(buildLoanProductRequest()); // Create Loan Account final Long loanId = createAndApproveLoan(clientId, loanProductId, activationDate); assertNotNull(loanId); @@ -100,10 +101,10 @@ private Long createAndApproveLoan(Long clientId, Long loanProductId, String oper return loanId; } - private String buildLoanProductJson() { + private PostLoanProductsRequest buildLoanProductRequest() { return new LoanProductTestBuilder().withPrincipal("12,000.00").withNumberOfRepayments("4").withRepaymentAfterEvery("1") .withRepaymentTypeAsMonth().withinterestRatePerPeriod("1").withInterestRateFrequencyTypeAsMonths() .withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance().withTranches(false) - .withAccounting(NONE, new Account[] {}).build(null); + .withAccounting(NONE, new Account[] {}).buildRequest(null); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java index 2238d312122..4df5f056ea1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargePaymentWithAdvancedPaymentAllocationTest.java @@ -35,6 +35,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; import org.apache.fineract.client.models.PostFinancialActivityAccountsResponse; +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.integrationtests.client.feign.FeignLoanTestBase; @@ -192,7 +193,7 @@ private Long createLoanProduct(final String principal, final String repaymentAft AdvancedPaymentData merchantIssuedRefundAllocation = createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"); AdvancedPaymentData payoutRefundAllocation = createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT"); log.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(true, "25", true).withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsMonths() .withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) @@ -201,8 +202,8 @@ private Long createLoanProduct(final String principal, final String repaymentAft .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) .addAdvancedPaymentAllocation(defaultAllocation, goodwillCreditAllocation, merchantIssuedRefundAllocation, payoutRefundAllocation) - .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0").build(null); - return createLoanProductFromJson(loanProductJSON); + .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0").buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplication(final Long clientId, final Long loanProductId, final Long savingsId, final Long principal, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java index c88da726b0c..cc0e11f5dda 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java @@ -25,6 +25,7 @@ import java.util.UUID; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.AdvancedPaymentData; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; @@ -72,13 +73,13 @@ public void addingLoanChargeTypeInstallmentFeeForAdvancedPaymentAllocationGivesE private Long createLoanProduct(final Account... accounts) { String futureInstallmentAllocationRule = "NEXT_INSTALLMENT"; AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation(futureInstallmentAllocationRule); - String loanProductCreateJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") - .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") + PostLoanProductsRequest loanProductCreateRequest = new LoanProductTestBuilder().withPrincipal("15,000.00") + .withNumberOfRepayments("4").withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .addAdvancedPaymentAllocation(defaultAllocation).withLoanScheduleType(LoanScheduleType.PROGRESSIVE).withMultiDisburse() - .withDisallowExpectedDisbursements(true).build(); - return createLoanProductFromJson(loanProductCreateJSON); + .withDisallowExpectedDisbursements(true).buildRequest(); + return createLoanProduct(loanProductCreateRequest); } private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java index d454674eb72..a829b77b480 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java @@ -25,10 +25,10 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; -import java.util.HashMap; import java.util.UUID; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; @@ -36,7 +36,6 @@ import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; -import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.Test; @@ -109,8 +108,8 @@ public void loanDownPaymentTransactionTypeTest() { } private GetLoanProductsProductIdResponse createLoanProduct(final Long delinquencyBucketId) { - final HashMap loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId); - final Long loanProductId = createLoanProductFromJson(Utils.convertToJson(loanProductMap)); + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().buildRequest(null, delinquencyBucketId); + final Long loanProductId = createLoanProduct(loanProductRequest); return retrieveLoanProduct(loanProductId); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithAdvancedPaymentAllocationIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithAdvancedPaymentAllocationIntegrationTests.java index 7d3f45f7766..cb92d4b916a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithAdvancedPaymentAllocationIntegrationTests.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithAdvancedPaymentAllocationIntegrationTests.java @@ -32,6 +32,7 @@ import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PaymentAllocationOrder; import org.apache.fineract.client.models.PostFinancialActivityAccountsRequest; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.accounting.Account; @@ -75,7 +76,7 @@ public void testCreateAndReadLoanProductWithAdvancedPayment() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - Long loanProductId = createLoanProductFromJson(loanProductTestBuilder( + Long loanProductId = createLoanProduct(customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -99,7 +100,7 @@ public void testUpdateLoanProductOneAllocationIsRemoved() { // given a loan with two allocations AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocationRule(); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - Long loanProductId = createLoanProductFromJson(loanProductTestBuilder( + Long loanProductId = createLoanProduct(customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -121,8 +122,8 @@ public void testUpdateLoanProductOneAllocationIsAdded() { // given a loan with one allocation AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocationRule(); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - Long loanProductId = createLoanProductFromJson( - loanProductTestBuilder(customization -> customization.addAdvancedPaymentAllocation(defaultAllocation))); + Long loanProductId = createLoanProduct( + customizedLoanProduct(customization -> customization.addAdvancedPaymentAllocation(defaultAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); @@ -151,7 +152,7 @@ public void testUpdateShouldFailWhenNoDefaultAllocationIsProvided() { // given a loan with two allocations AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocationRule(); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - Long loanProductId = createLoanProductFromJson(loanProductTestBuilder( + Long loanProductId = createLoanProduct(customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -171,7 +172,7 @@ public void testUpdateShouldFailWhenStrategyIsChangedBackButPaymentAllocationsAr // given a loan with two allocations AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocationRule(); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - Long loanProductId = createLoanProductFromJson(loanProductTestBuilder( + Long loanProductId = createLoanProduct(customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -189,11 +190,12 @@ public void testUpdateShouldFailWhenStrategyIsChangedBackButPaymentAllocationsAr @Test public void testCreateShouldFailWhenNoAllocationRuleIsProvided() { // given - String loanProduct = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") + PostLoanProductsRequest loanProduct = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withAccountingRulePeriodicAccrual(new Account[] { ASSET_ACCOUNT, EXPENSE_ACCOUNT, INCOME_ACCOUNT, OVERPAYMENT_ACCOUNT }) .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() - .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).withRepaymentStrategy("advanced-payment-allocation-strategy").build(); + .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).withRepaymentStrategy("advanced-payment-allocation-strategy") + .buildRequest(); // when List> loanProductError = getLoanProductError(loanProduct, "errors"); @@ -208,7 +210,7 @@ public void testCreateShouldFailWhenNoDefaultAllocationIsProvided() { // when List> loanProductError = getLoanProductError( - loanProductTestBuilder(customization -> customization.addAdvancedPaymentAllocation(repaymentPaymentAllocation)), "errors"); + customizedLoanProduct(customization -> customization.addAdvancedPaymentAllocation(repaymentPaymentAllocation)), "errors"); Assertions.assertEquals("Advanced-payment-allocation-strategy was selected but no DEFAULT payment allocation was provided", loanProductError.get(0).get("defaultUserMessage")); } @@ -220,7 +222,7 @@ public void testCreateAndReadLoanProductWithAdvancedPaymentAndInterestPaymentWai AdvancedPaymentData interestPaymentWaiverAllocation = createInterestPaymentWaiverAllocation(); // when - Long loanProductId = createLoanProductFromJson(loanProductTestBuilder( + Long loanProductId = createLoanProduct(customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, interestPaymentWaiverAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -244,8 +246,8 @@ public void testUpdateLoanProductInterestPaymentWaiverAllocationIsAdded() { // given a loan with one allocation AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocationRule(); AdvancedPaymentData interestPaymentWaiverAllocation = createInterestPaymentWaiverAllocation(); - Long loanProductId = createLoanProductFromJson( - loanProductTestBuilder(customization -> customization.addAdvancedPaymentAllocation(defaultAllocation))); + Long loanProductId = createLoanProduct( + customizedLoanProduct(customization -> customization.addAdvancedPaymentAllocation(defaultAllocation))); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); @@ -276,10 +278,10 @@ public void testCreateAndReadProgressiveLoanProductWithInterestRefund() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProductRequest = loanProductTestBuilder( + PostLoanProductsRequest loanProductRequest = customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation)); - Long loanProductId = createLoanProductFromJson(loanProductRequest); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -299,10 +301,10 @@ public void testCreateAndReadProgressiveLoanProductWithInterestRefund() { Assertions.assertEquals("MERCHANT_ISSUED_REFUND", loanProduct.getSupportedInterestRefundTypes().get(0).getId()); // Set both of them at creation - String loanProductRequest2 = loanProductTestBuilder( + PostLoanProductsRequest loanProductRequest2 = customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) .withSupportedInterestRefundTypes("PAYOUT_REFUND", "MERCHANT_ISSUED_REFUND")); - Long loanProductId2 = createLoanProductFromJson(loanProductRequest2); + Long loanProductId2 = createLoanProduct(loanProductRequest2); Assertions.assertNotNull(loanProductId2); GetLoanProductsProductIdResponse loanProduct2 = retrieveLoanProduct(loanProductId2); @@ -324,8 +326,9 @@ public void testCreateAndReadProgressiveLoanProductWithInterestRefund() { public void testCreateCumulativeLoanProductWithInterestRefund() { // given // when - String loanProductRequest = loanProductTestBuilder(customization -> customization.withSupportedInterestRefundTypes("PAYOUT_REFUND") - .withLoanScheduleType(LoanScheduleType.CUMULATIVE).withRepaymentStrategy("mifos-standard-strategy")); + PostLoanProductsRequest loanProductRequest = customizedLoanProduct( + customization -> customization.withSupportedInterestRefundTypes("PAYOUT_REFUND") + .withLoanScheduleType(LoanScheduleType.CUMULATIVE).withRepaymentStrategy("mifos-standard-strategy")); List> loanProductError = getLoanProductError(loanProductRequest, "errors"); Assertions.assertEquals( "validation.msg.loanproduct.supportedInterestRefundTypes.supported.only.for.progressive.loan.schedule.handling", @@ -339,12 +342,12 @@ public void testCreateShouldFailWhenNoNumberOfRepaymentsIsProvided() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProduct = loanProductTestBuilder(customization -> customization + PostLoanProductsRequest loanProduct = customizedLoanProduct(customization -> customization .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation).withPrincipal("15,000.00") .withNumberOfRepayments(null).withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withAccountingRulePeriodicAccrual(new Account[] { ASSET_ACCOUNT, EXPENSE_ACCOUNT, INCOME_ACCOUNT, OVERPAYMENT_ACCOUNT }) .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() - .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).build()); + .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT)); // when List> loanProductError = getLoanProductError(loanProduct, "errors"); @@ -359,12 +362,12 @@ public void testCreateShouldFailWhenNoInterestRateIsProvided() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProduct = loanProductTestBuilder(customization -> customization + PostLoanProductsRequest loanProduct = customizedLoanProduct(customization -> customization .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation).withPrincipal("15,000.00") .withNumberOfRepayments("4").withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod(null) .withAccountingRulePeriodicAccrual(new Account[] { ASSET_ACCOUNT, EXPENSE_ACCOUNT, INCOME_ACCOUNT, OVERPAYMENT_ACCOUNT }) .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() - .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).build()); + .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT)); // when List> loanProductError = getLoanProductError(loanProduct, "errors"); @@ -379,11 +382,11 @@ public void testCreateAndReadProgressiveLoanProductWithChargeOffBehaviour() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProductRequest = loanProductTestBuilder( + PostLoanProductsRequest loanProductRequest = customizedLoanProduct( customization -> customization.addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) .withChargeOffBehaviour(LoanChargeOffBehaviour.ZERO_INTEREST)); - Long loanProductId = createLoanProductFromJson(loanProductRequest); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -405,7 +408,7 @@ public void testCreateAndReadProgressiveLoanProductWithChargeOffBehaviour() { public void testCreateCumulativeLoanProductWithChargeOff() { // given // when - String loanProductRequest = loanProductTestBuilder( + PostLoanProductsRequest loanProductRequest = customizedLoanProduct( customization -> customization.withChargeOffBehaviour(LoanChargeOffBehaviour.ZERO_INTEREST) .withLoanScheduleType(LoanScheduleType.CUMULATIVE).withRepaymentStrategy("mifos-standard-strategy")); List> loanProductError = getLoanProductError(loanProductRequest, "errors"); @@ -413,7 +416,7 @@ public void testCreateCumulativeLoanProductWithChargeOff() { loanProductError.get(0).get("userMessageGlobalisationCode")); } - private String loanProductTestBuilder(Consumer customization) { + private PostLoanProductsRequest customizedLoanProduct(Consumer customization) { LoanProductTestBuilder builder = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withAccountingRulePeriodicAccrual(new Account[] { ASSET_ACCOUNT, EXPENSE_ACCOUNT, INCOME_ACCOUNT, OVERPAYMENT_ACCOUNT }) @@ -421,7 +424,7 @@ private String loanProductTestBuilder(Consumer customiza .withFeeAndPenaltyAssetAccount(FEE_PENALTY_ACCOUNT).withLoanScheduleType(LoanScheduleType.PROGRESSIVE) .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL); customization.accept(builder); - return builder.build(); + return builder.buildRequest(); } private PutLoanProductsProductIdRequest updateLoanProductRequest(AdvancedPaymentData... advancedPaymentData) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithCreditAllocationsIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithCreditAllocationsIntegrationTests.java index c9896f03b89..d8da7968bf5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithCreditAllocationsIntegrationTests.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithCreditAllocationsIntegrationTests.java @@ -29,6 +29,7 @@ import org.apache.fineract.client.models.CreditAllocationOrder; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PaymentAllocationOrder; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.accounting.Account; @@ -49,9 +50,10 @@ public void testCreateAndReadLoanProductWithAdvancedPaymentAndCreditAllocations( AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProductJSON = baseLoanProduct().addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) - .addCreditAllocations(createChargebackAllocation()).build(); - Long loanProductId = createLoanProductFromJson(loanProductJSON); + PostLoanProductsRequest loanProductRequest = baseLoanProduct() + .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) + .addCreditAllocations(createChargebackAllocation()).buildRequest(); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -68,8 +70,9 @@ public void testCreateLoanProductAndLaterAddCreditAllocation() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // create empty - String loanProductJSON = baseLoanProduct().addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation).build(); - Long loanProductId = createLoanProductFromJson(loanProductJSON); + PostLoanProductsRequest loanProductRequest = baseLoanProduct() + .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation).buildRequest(); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertEquals(0, loanProduct.getCreditAllocation().size()); @@ -90,9 +93,10 @@ public void testCreateAndUpdateCreditAllocation() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProductJSON = baseLoanProduct().addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) - .addCreditAllocations(createChargebackAllocation()).build(); - Long loanProductId = createLoanProductFromJson(loanProductJSON); + PostLoanProductsRequest loanProductRequest = baseLoanProduct() + .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) + .addCreditAllocations(createChargebackAllocation()).buildRequest(); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getCreditAllocation()); @@ -117,9 +121,10 @@ public void testCreateAndDeleteCreditAllocation() { AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); // when - String loanProductJSON = baseLoanProduct().addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) - .addCreditAllocations(createChargebackAllocation()).build(); - Long loanProductId = createLoanProductFromJson(loanProductJSON); + PostLoanProductsRequest loanProductRequest = baseLoanProduct() + .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) + .addCreditAllocations(createChargebackAllocation()).buildRequest(); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getCreditAllocation()); @@ -135,11 +140,11 @@ public void testCreateAndDeleteCreditAllocation() { @Test public void testCreditAllocationIsNotAllowedWhenPaymentStrategyIsNotAdvancedPaymentStrategy() { // given - String loanProductJSON = baseLoanProduct().withRepaymentStrategy("mifos-standard-strategy") - .withLoanScheduleType(LoanScheduleType.CUMULATIVE).addCreditAllocations(createChargebackAllocation()).build(); + PostLoanProductsRequest loanProductRequest = baseLoanProduct().withRepaymentStrategy("mifos-standard-strategy") + .withLoanScheduleType(LoanScheduleType.CUMULATIVE).addCreditAllocations(createChargebackAllocation()).buildRequest(); // when - List> loanProductError = getLoanProductError(loanProductJSON, "errors"); + List> loanProductError = getLoanProductError(loanProductRequest, "errors"); // then Assertions.assertEquals("In case 'mifos-standard-strategy' payment strategy, creditAllocation must not be provided", @@ -151,9 +156,10 @@ public void testCreateLoanProductWithCreditAllocationThenUpdatePaymentStrategySh // given AdvancedPaymentData defaultAllocation = createCustomDefaultPaymentAllocation(); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - String loanProductJSON = baseLoanProduct().addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) - .addCreditAllocations(createChargebackAllocation()).build(); - Long loanProductId = createLoanProductFromJson(loanProductJSON); + PostLoanProductsRequest loanProductRequest = baseLoanProduct() + .addAdvancedPaymentAllocation(defaultAllocation, repaymentPaymentAllocation) + .addCreditAllocations(createChargebackAllocation()).buildRequest(); + Long loanProductId = createLoanProduct(loanProductRequest); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getCreditAllocation()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java index e100d1c3f2a..fca27fed0c4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithDownPaymentConfigurationTest.java @@ -29,7 +29,6 @@ import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.CommonConstants; -import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.Test; @@ -77,44 +76,42 @@ public void loanProductEnableDownPaymentConfigurationValidationTests() { Boolean enableDownPayment = true; ArrayList> loanProductErrorData = getLoanProductError( - Utils.convertToJson( - new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "0", false).build(null, delinquencyBucketId)), + new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "0", false).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.is.less.than.min", loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - loanProductErrorData = getLoanProductError(Utils.convertToJson( - new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "101", false).build(null, delinquencyBucketId)), + loanProductErrorData = getLoanProductError( + new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, "101", false).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.is.greater.than.max", loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - loanProductErrorData = getLoanProductError(Utils.convertToJson(new LoanProductTestBuilder() - .withEnableDownPayment(enableDownPayment, "12.55555555", false).build(null, delinquencyBucketId)), + loanProductErrorData = getLoanProductError(new LoanProductTestBuilder() + .withEnableDownPayment(enableDownPayment, "12.55555555", false).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.scale.is.greater.than.6", loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); loanProductErrorData = getLoanProductError( - Utils.convertToJson( - new LoanProductTestBuilder().withEnableDownPayment(false, "12.5", false).build(null, delinquencyBucketId)), + new LoanProductTestBuilder().withEnableDownPayment(false, "12.5", false).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.supported.only.for.enable.down.payment.true", loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - loanProductErrorData = getLoanProductError(Utils.convertToJson( - new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, null, false).build(null, delinquencyBucketId)), + loanProductErrorData = getLoanProductError( + new LoanProductTestBuilder().withEnableDownPayment(enableDownPayment, null, false).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.disbursedAmountPercentageForDownPayment.required.for.enable.down.payment.true", loanProductErrorData.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); loanProductErrorData = getLoanProductError( - Utils.convertToJson(new LoanProductTestBuilder().withEnableDownPayment(false, null, true).build(null, delinquencyBucketId)), + new LoanProductTestBuilder().withEnableDownPayment(false, null, true).buildRequest(null, delinquencyBucketId), CommonConstants.RESPONSE_ERROR); assertNotNull(loanProductErrorData); assertEquals("validation.msg.loanproduct.enableAutoRepaymentForDownPayment.supported.only.for.enable.down.payment.true", @@ -122,14 +119,14 @@ public void loanProductEnableDownPaymentConfigurationValidationTests() { } private GetLoanProductsProductIdResponse createLoanProductWithoutDownPayment(final Long delinquencyBucketId) { - Long loanProductId = createLoanProductFromJson(Utils.convertToJson(new LoanProductTestBuilder().build(null, delinquencyBucketId))); + Long loanProductId = createLoanProduct(new LoanProductTestBuilder().buildRequest(null, delinquencyBucketId)); return retrieveLoanProduct(loanProductId); } private Long createLoanProductWithDownPaymentConfiguration(final Long delinquencyBucketId, Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, Boolean enableAutoRepaymentForDownPayment) { - return createLoanProductFromJson(Utils.convertToJson(new LoanProductTestBuilder() + return createLoanProduct(new LoanProductTestBuilder() .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) - .build(null, delinquencyBucketId))); + .buildRequest(null, delinquencyBucketId)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java index 7760ca0fdc0..fa3c17cacf0 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentRescheduleAtDisbursementTest.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; import org.apache.fineract.client.models.PostLoansRequest; @@ -49,7 +50,7 @@ public void testLoanRepaymentRescheduleAtDisbursement() { Long clientId = createClient("01 January 2014"); - Long loanProductId = createLoanProductFromJson(buildLoanProductJson()); + Long loanProductId = createLoanProduct(buildLoanProductRequest()); List createTranches = List.of(LoanRequestBuilders.applyTrancheDetail("01 March 2015", 5000.0), LoanRequestBuilders.applyTrancheDetail("01 May 2015", 5000.0)); @@ -79,7 +80,7 @@ public void testLoanRepaymentRescheduleAtDisbursement() { assertEquals(884.03, Utils.getDoubleValue(firstInstallment.getTotalDueForPeriod())); } - private String buildLoanProductJson() { + private PostLoanProductsRequest buildLoanProductRequest() { return new LoanProductTestBuilder().withPrincipal("10000.00").withNumberOfRepayments("12").withRepaymentAfterEvery("2") .withRepaymentTypeAsWeek().withinterestRatePerPeriod("2").withInterestRateFrequencyTypeAsMonths().withTranches(true) .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withRepaymentStrategy(LoanProductTestBuilder.RBI_INDIA_STRATEGY) @@ -88,7 +89,7 @@ private String buildLoanProductJson() { LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE) .withInterestRecalculationRestFrequencyDetails(LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", null, null) - .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).build(null); + .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).buildRequest(null); } private PostLoansRequest buildLoanApplication(Long clientId, Long loanProductId, String disbursementDate, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java index 5418af5ce4a..46cf72303b8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRepaymentScheduleWithDownPaymentTest.java @@ -25,7 +25,6 @@ import java.math.BigDecimal; import java.time.LocalDate; -import java.util.HashMap; import java.util.List; import java.util.UUID; import org.apache.fineract.client.models.DelinquencyBucketResponse; @@ -1718,14 +1717,14 @@ private Integer createLoanAccountMultipleRepaymentsDisbursement(final Integer cl private GetLoanProductsProductIdResponse createLoanProductWithDownPaymentConfigurationAndAccrualAccounting(Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, boolean enableAutoRepaymentForDownPayment, final Account... accounts) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() .withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30") .withDaysInYear("365").withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true) .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) - .build(null); - final Long loanProductId = createLoanProductFromJson(loanProductJSON); + .buildRequest(null); + final Long loanProductId = createLoanProduct(loanProductRequest); return retrieveLoanProduct(loanProductId); } @@ -1747,34 +1746,34 @@ private Integer createApproveAndDisburseLoanAccount(final Integer clientID, fina private GetLoanProductsProductIdResponse createLoanProductWithEnableDownPaymentAndMultipleDisbursementsWithDisableRepaymentConfiguration( Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, boolean enableAutoRepaymentForDownPayment) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() .withRepaymentAfterEvery("1").withNumberOfRepayments("3").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365") .withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true) .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) - .build(null); - final Long loanProductId = createLoanProductFromJson(loanProductJSON); + .buildRequest(null); + final Long loanProductId = createLoanProduct(loanProductRequest); return retrieveLoanProduct(loanProductId); } private Integer createLoanProductWithDownPaymentConfiguration(final Long delinquencyBucketId, Boolean enableDownPayment, String disbursedAmountPercentageForDownPayment, Boolean enableAutoRepaymentForDownPayment, boolean multiDisbursement) { - HashMap loanProductMap; + PostLoanProductsRequest loanProductRequest; if (multiDisbursement) { - loanProductMap = new LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments() // + loanProductRequest = new LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments() // .withInterestTypeAsDecliningBalance().withMoratorium("", "").withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .withInterestTypeAsDecliningBalance() // .withMultiDisburse() // .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) // .withDisallowExpectedDisbursements(true) // - .build(null, delinquencyBucketId); + .buildRequest(null, delinquencyBucketId); } else { - loanProductMap = new LoanProductTestBuilder() // + loanProductRequest = new LoanProductTestBuilder() // .withEnableDownPayment(enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment) // - .build(null, delinquencyBucketId); + .buildRequest(null, delinquencyBucketId); } - return createLoanProductFromJson(Utils.convertToJson(loanProductMap)).intValue(); + return createLoanProduct(loanProductRequest).intValue(); } private Integer createAndApproveLoanAccount(final Integer clientID, final Long loanProductID, final String externalId, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java index e77126cdd2e..30fd51e5b78 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java @@ -109,17 +109,17 @@ private void createLoanProductWithInterestRecalculation() { LOG.info( "---------------------------------CREATING LOAN PRODUCT WITH RECALULATION ENABLED ------------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(String.valueOf((int) loanPrincipalAmount)) - .withNumberOfRepayments(String.valueOf(numberOfRepayments)) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder() + .withPrincipal(String.valueOf((int) loanPrincipalAmount)).withNumberOfRepayments(String.valueOf(numberOfRepayments)) .withinterestRatePerPeriod(String.valueOf((int) interestRatePerPeriod)).withInterestRateFrequencyTypeAsYear() .withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeAsDays() .withInterestRecalculationDetails(LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE, LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE) .withInterestRecalculationRestFrequencyDetails(LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", null, null) - .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).build(null); + .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).buildRequest(null); - this.loanProductId = createLoanProductFromJson(loanProductJSON); + this.loanProductId = createLoanProduct(loanProductRequest); assertTrue(Boolean.TRUE.equals(retrieveLoanProduct(this.loanProductId).getIsInterestRecalculationEnabled())); LOG.info("Successfully created loan product (ID:{}) ", this.loanProductId); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java index e298cadae20..f5cc6f9ff48 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java @@ -40,6 +40,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostClientsRequest; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; import org.apache.fineract.client.models.PostLoansRequest; @@ -307,8 +308,8 @@ private Long createLoanProductWithInterestRecalculation(final String repaymentSt final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval, final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final boolean isMultiTrancheLoan) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("10000.00").withNumberOfRepayments("12") - .withRepaymentAfterEvery("2").withRepaymentTypeAsWeek().withinterestRatePerPeriod("2") + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withPrincipal("10000.00") + .withNumberOfRepayments("12").withRepaymentAfterEvery("2").withRepaymentTypeAsWeek().withinterestRatePerPeriod("2") .withInterestRateFrequencyTypeAsMonths().withTranches(isMultiTrancheLoan) .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withRepaymentStrategy(repaymentStrategy) .withInterestTypeAsDecliningBalance() @@ -316,8 +317,8 @@ private Long createLoanProductWithInterestRecalculation(final String repaymentSt preCloseInterestCalculationStrategy) .withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval, null, null) - .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).build(null); - return createLoanProductFromJson(loanProductJSON); + .withInterestRecalculationCompoundingFrequencyDetails(null, null, null, null).buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplicationForInterestRecalculation(final Long clientId, Long groupId, Long calendarId, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java index bc5e9067e3c..aa61ef96aa9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; @@ -180,7 +181,7 @@ private Long createLoanProduct(final String inMultiplesOf, final String digitsAf final org.apache.fineract.integrationtests.common.accounting.Account expenseAccount = getAccounts().getChargeOffExpenseAccount(); final org.apache.fineract.integrationtests.common.accounting.Account overpaymentAccount = getAccounts().getOverpaymentAccount(); - final String loanProductJSON = new LoanProductTestBuilder() // + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder() // .withPrincipal("10000000.00") // .withNumberOfRepayments("24") // .withRepaymentAfterEvery("1") // @@ -193,7 +194,7 @@ private Long createLoanProduct(final String inMultiplesOf, final String digitsAf .currencyDetails(digitsAfterDecimal, inMultiplesOf) .withAccounting(accountingRule, new org.apache.fineract.integrationtests.common.accounting.Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) - .build(null); - return createLoanProductFromJson(loanProductJSON); + .buildRequest(null); + return createLoanProduct(loanProductRequest); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java index a955f919d0c..194abda1149 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionChargebackTest.java @@ -1339,7 +1339,7 @@ private Long createChargebackLoanProduct(String strategyCode, boolean advancedAl if (withJournalEntries) { LoanTestAccounts accounts = getAccounts(); - return createLoanProductFromJson(Utils.convertToJson(builder + return createLoanProduct(builder .withFullAccountingConfig(ACCRUAL_PERIODIC, LoanProductTestBuilder.FullAccountingConfig.builder() .fundSourceAccountId(accounts.getFundSource().getAccountID().longValue()) @@ -1354,9 +1354,9 @@ private Long createChargebackLoanProduct(String strategyCode, boolean advancedAl .receivableInterestAccountId(accounts.getInterestReceivableAccount().getAccountID().longValue()) .receivableFeeAccountId(accounts.getInterestReceivableAccount().getAccountID().longValue()) .receivablePenaltyAccountId(accounts.getInterestReceivableAccount().getAccountID().longValue()).build()) - .build(null, delinquencyBucketId))); + .buildRequest(null, delinquencyBucketId)); } - return createLoanProductFromJson(Utils.convertToJson(builder.build(null, delinquencyBucketId))); + return createLoanProduct(builder.buildRequest(null, delinquencyBucketId)); } private Long createLoanAccount(final Long clientId, final Long loanProductId, final String operationDate, final String principalAmount, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java index 01db1cbb783..556b4f97ff5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java @@ -743,7 +743,7 @@ public void testInterestPaymentWaiverUC17c() { @Test public void shouldReturnOkStatusForBatchInterestPaymentWaiver() { - final String loanProductJSON = new LoanProductTestBuilder() // + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder() // .withPrincipal("1000.00") // .withNumberOfRepayments("24") // .withRepaymentAfterEvery("1") // @@ -752,7 +752,7 @@ public void shouldReturnOkStatusForBatchInterestPaymentWaiver() { .withInterestRateFrequencyTypeAsMonths() // .withAmortizationTypeAsEqualPrincipalPayment() // .withInterestTypeAsDecliningBalance() // - .currencyDetails("0", "100").build(null); + .currencyDetails("0", "100").buildRequest(null); final Long clientId = createClient(); assertNotNull(clientId); @@ -762,7 +762,7 @@ public void shouldReturnOkStatusForBatchInterestPaymentWaiver() { final Long clientCollateralId = collateralHelper.createClientCollateral(clientId, collateralId).getResourceId(); assertNotNull(clientCollateralId); - final Integer productId = getLoanProductId(loanProductJSON); + final Integer productId = getLoanProductId(loanProductRequest); final Long createActiveClientRequestId = 4730L; final Long applyLoanRequestId = createActiveClientRequestId + 1; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java index bca0b7b4adc..528a934fab5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReprocessForAdvancedPaymentAllocationTest.java @@ -26,6 +26,7 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; @@ -88,13 +89,13 @@ public void loanTransactionReprocessForAddChargeTest() { private Long createLoanProduct(Account... accounts) { AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT"); - String loanProductCreateJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") - .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") + PostLoanProductsRequest loanProductCreateRequest = new LoanProductTestBuilder().withPrincipal("15,000.00") + .withNumberOfRepayments("4").withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .addAdvancedPaymentAllocation(defaultAllocation).withLoanScheduleType(LoanScheduleType.PROGRESSIVE).withMultiDisburse() - .withDisallowExpectedDisbursements(true).build(); - return createLoanProductFromJson(loanProductCreateJSON); + .withDisallowExpectedDisbursements(true).buildRequest(); + return createLoanProduct(loanProductCreateRequest); } private Long createLoanAccount(Long clientId, Long loanProductId, String externalId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java index d4965e9df5a..e4ab3fdcc28 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java @@ -31,6 +31,7 @@ import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; +import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,8 +54,7 @@ public void loanTransactionReverseReplayRelationTest() { final Long delinquencyBucketId = DelinquencyBucketsHelper.createDefaultBucket(); // Client and Loan account creation - final Long productId = createLoanProductFromJson(new com.google.gson.Gson() - .toJson(new org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder().build(null, delinquencyBucketId))); + final Long productId = createLoanProduct(new LoanProductTestBuilder().buildRequest(null, delinquencyBucketId)); assertNotNull(productId); final Long loanId = applyForLoan(new PostLoansRequest()// diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java index a2755ee6a74..471612c8de3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java @@ -28,6 +28,7 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PaymentAllocationOrder; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; @@ -54,7 +55,7 @@ public void testCreateAndReadLoanProductWithAdvancedPayment() { AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT"); AdvancedPaymentData repaymentPaymentAllocation = createRepaymentPaymentAllocation(); - Long loanProductId = createLoanProductFromJson(createLoanJSON(assetAccount, expenseAccount, incomeAccount, overpaymentAccount, + Long loanProductId = createLoanProduct(createLoanProductRequest(assetAccount, expenseAccount, incomeAccount, overpaymentAccount, feePenaltyAccount, defaultAllocation, repaymentPaymentAllocation)); Assertions.assertNotNull(loanProductId); GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); @@ -92,15 +93,15 @@ public void testCreateAndReadLoanProductWithAdvancedPayment() { }); } - private String createLoanJSON(Account assetAccount, Account expenseAccount, Account incomeAccount, Account overpaymentAccount, - Account feePenaltyAccount, AdvancedPaymentData... advancedPaymentData) { + private PostLoanProductsRequest createLoanProductRequest(Account assetAccount, Account expenseAccount, Account incomeAccount, + Account overpaymentAccount, Account feePenaltyAccount, AdvancedPaymentData... advancedPaymentData) { return new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4").withRepaymentAfterEvery("1") .withRepaymentTypeAsMonth().withinterestRatePerPeriod("1").withRepaymentStrategy(ADVANCED_PAYMENT_ALLOCATION_STRATEGY) .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, expenseAccount, incomeAccount, overpaymentAccount }) .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .withFeeAndPenaltyAssetAccount(feePenaltyAccount).addAdvancedPaymentAllocation(advancedPaymentData) .withLoanScheduleType(LoanScheduleType.PROGRESSIVE).withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL) - .build(); + .buildRequest(); } private PutLoanProductsProductIdRequest updateLoanProductRequest(AdvancedPaymentData... advancedPaymentData) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java index 06920180473..661931a54d4 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWriteOffWithAdvancedPaymentAllocationTest.java @@ -30,6 +30,7 @@ import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; import org.apache.fineract.client.models.PostLoansRequest; @@ -153,12 +154,12 @@ public void loanUndoWriteOffShouldGiveErrorTest() { private Long createApaLoanProduct() { AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT"); - String loanProductCreateJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") - .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") + PostLoanProductsRequest loanProductCreateRequest = new LoanProductTestBuilder().withPrincipal("15,000.00") + .withNumberOfRepayments("4").withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .addAdvancedPaymentAllocation(defaultAllocation).withLoanScheduleType(LoanScheduleType.PROGRESSIVE) - .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).build(); - return createLoanProductFromJson(loanProductCreateJSON); + .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).buildRequest(); + return createLoanProduct(loanProductCreateRequest); } private Long createAndDisburseLoan(Long clientId, Long loanProductId, String externalId) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/RefundForActiveLoansWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/RefundForActiveLoansWithAdvancedPaymentAllocationTest.java index 73a737ec86a..e713cf1ad79 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/RefundForActiveLoansWithAdvancedPaymentAllocationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/RefundForActiveLoansWithAdvancedPaymentAllocationTest.java @@ -28,6 +28,7 @@ import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +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.integrationtests.client.feign.FeignLoanTestBase; @@ -403,15 +404,15 @@ private Long createLoanProduct(final String principal, final String repaymentAft LoanScheduleProcessingType loanScheduleProcessingType, final Account... accounts) { AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation(); log.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) + final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal) .withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments) .withEnableDownPayment(true, "25", true).withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsMonths() .withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) .withLoanScheduleType(LoanScheduleType.PROGRESSIVE).withLoanScheduleProcessingType(loanScheduleProcessingType) .withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts) .addAdvancedPaymentAllocation(defaultAllocation).withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL) - .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0").build(null); - return createLoanProductFromJson(loanProductJSON); + .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0").buildRequest(null); + return createLoanProduct(loanProductRequest); } private Long applyForLoanApplication(final Long clientId, final Long loanProductId, final Long principal, final int loanTermFrequency, From 7b45fae7d813383c57f3bbd895e9e163f57afe92 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Mon, 24 Aug 2026 13:21:02 +0530 Subject: [PATCH 13/15] FINERACT-2779: retire the JSON loan product paths With no callers left, drop createLoanProductFromJson from FeignLoanHelper and FeignLoanTestBase, and take PostLoanProductsRequest on getLoanProductError and getLoanProductId. That removes the last places a Feign loan test parsed a JSON string back into a request model, along with the "silences unknown property errors" warning that came with it. Signed-off-by: DeathGun44 --- .../client/feign/FeignLoanTestBase.java | 12 +++------ .../client/feign/helpers/FeignLoanHelper.java | 26 +++---------------- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java index e46e5383eee..54237c6f926 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java @@ -216,10 +216,6 @@ protected Long createLoanProduct(PostLoanProductsRequest request) { return loanHelper.createLoanProduct(request).getResourceId(); } - protected Long createLoanProductFromJson(String loanProductJson) { - return loanHelper.createLoanProductFromJson(loanProductJson); - } - protected GetLoanProductsProductIdResponse retrieveLoanProduct(Long productId) { return loanHelper.retrieveLoanProduct(productId); } @@ -1061,8 +1057,8 @@ protected void verifyBusinessEvents(BusinessEvent... businessEvents) { }); } - protected Integer getLoanProductId(String loanProductJson) { - return createLoanProductFromJson(loanProductJson).intValue(); + protected Integer getLoanProductId(PostLoanProductsRequest request) { + return createLoanProduct(request).intValue(); } protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer loanProductId, String externalId) { @@ -1861,8 +1857,8 @@ protected List getAdvancedPaymentAllocationRules(Long loanI return loanHelper.getAdvancedPaymentAllocationRules(loanId); } - protected T getLoanProductError(String loanProductJson, String jsonAttributeToGetBack) { - return loanHelper.getLoanProductError(loanProductJson, jsonAttributeToGetBack); + protected T getLoanProductError(PostLoanProductsRequest request, String jsonAttributeToGetBack) { + return loanHelper.getLoanProductError(request, jsonAttributeToGetBack); } protected PostLoansLoanIdTransactionsResponse makeRefundByCash(Long loanId, String date, Double amount) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java index 02bf86fe99d..a38fbbe5416 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java @@ -151,20 +151,6 @@ public PostLoanProductsResponse createLoanProduct(PostLoanProductsRequest reques return ok(() -> fineractClient.loanProducts().createLoanProduct(request)); } - /** - * WARNING: This method uses ObjectMapperFactory which silences unknown property errors. Do not use this method in - * tests expecting strict deserialization. - */ - public Long createLoanProductFromJson(String loanProductJson) { - try { - String sanitizedJson = loanProductJson.replaceAll("(?<=\\d),(?=\\d{3}(?!\\d))", ""); - PostLoanProductsRequest request = ObjectMapperFactory.getShared().readValue(sanitizedJson, PostLoanProductsRequest.class); - return createLoanProduct(request).getResourceId(); - } catch (com.fasterxml.jackson.core.JsonProcessingException e) { - throw new IllegalArgumentException("Invalid loan product json", e); - } - } - @SuppressWarnings("unchecked") private T extractErrorAttribute(CallFailedRuntimeException exception, String jsonAttributeToGetBack) { if (!(exception.getCause() instanceof org.apache.fineract.client.feign.FeignException feignException)) { @@ -178,15 +164,9 @@ private T extractErrorAttribute(CallFailedRuntimeException exception, String } } - public T getLoanProductError(String loanProductJson, String jsonAttributeToGetBack) { - try { - String sanitizedJson = loanProductJson.replaceAll("(?<=\\d),(?=\\d{3}(?!\\d))", ""); - PostLoanProductsRequest request = ObjectMapperFactory.getShared().readValue(sanitizedJson, PostLoanProductsRequest.class); - CallFailedRuntimeException ex = fail(() -> fineractClient.loanProducts().createLoanProduct(request)); - return extractErrorAttribute(ex, jsonAttributeToGetBack); - } catch (com.fasterxml.jackson.core.JsonProcessingException e) { - throw new IllegalArgumentException("Invalid loan product json", e); - } + public T getLoanProductError(PostLoanProductsRequest request, String jsonAttributeToGetBack) { + CallFailedRuntimeException ex = fail(() -> fineractClient.loanProducts().createLoanProduct(request)); + return extractErrorAttribute(ex, jsonAttributeToGetBack); } public CallFailedRuntimeException addLoanChargeExpectingError(Long loanId, PostLoansLoanIdChargesRequest request) { From cd8250d9157eac4fef0b910f8e5d26183300064d Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Wed, 26 Aug 2026 20:33:48 +0530 Subject: [PATCH 14/15] FINERACT-2779: return the loan application response the server sent applyForLoanResponse kept only the id from the Feign response and rebuilt a PostLoansResponse by hand, paying for a second GET to recover the external id. POST /loans already answers a full response, so the synthetic object dropped every other field for no gain. Return the client's response. Type the loan-product id as Long while here: getLoanProductId existed only to downcast createLoanProduct, which already returns Long, and applyForLoanApplication converted both ids straight back with longValue(). --- .../client/feign/FeignLoanTestBase.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java index 54237c6f926..59acd16cb3f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignLoanTestBase.java @@ -1057,18 +1057,17 @@ protected void verifyBusinessEvents(BusinessEvent... businessEvents) { }); } - protected Integer getLoanProductId(PostLoanProductsRequest request) { - return createLoanProduct(request).intValue(); + protected Long getLoanProductId(PostLoanProductsRequest request) { + return createLoanProduct(request); } - protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer loanProductId, String externalId) { + protected PostLoansResponse applyForLoanApplication(Long clientId, Long loanProductId, String externalId) { return applyForLoanApplication(clientId, loanProductId, externalId, null); } - protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer loanProductId, String externalId, String linkAccountId) { + protected PostLoansResponse applyForLoanApplication(Long clientId, Long loanProductId, String externalId, String linkAccountId) { PostLoansRequest request = LoanRequestBuilders - .legacyIndividualApplication(clientId.longValue(), loanProductId.longValue(), "1000", 1, BigDecimal.ZERO, - "03 September 2022") + .legacyIndividualApplication(clientId, loanProductId, "1000", 1, BigDecimal.ZERO, "03 September 2022") .submittedOnDate("01 September 2022")// .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// .inArrearsTolerance(new BigDecimal("1001"))// @@ -1079,10 +1078,8 @@ protected PostLoansResponse applyForLoanApplication(Integer clientId, Integer lo return applyForLoanResponse(request); } - /** Mirrors the old JSON path, which returned only an id and then read the external id back. */ protected PostLoansResponse applyForLoanResponse(PostLoansRequest request) { - Long loanId = applyForLoan(request); - return new PostLoansResponse().resourceId(loanId).resourceExternalId(getLoanDetails(loanId).getExternalId()); + return loanHelper.applyForLoan(request); } protected PostLoansLoanIdResponse disburseLoan(String date, Integer loanId, String transactionAmount, String externalId) { From ac6061965a5d9c3da795e067232eca2d7fb10791 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Wed, 26 Aug 2026 20:33:48 +0530 Subject: [PATCH 15/15] FINERACT-2779: carry loan ids as Long through the loan tests Follows the base helpers to Long: the loan-product locals lose their Integer declarations and nineteen call sites lose the clientId.intValue() downcast. Renaming one method is not cosmetic. ClientLoanChargeExternalIntegrationTest declared a private applyForLoanApplication(Long, Long, String) whose third argument is a principal, while the base method of the same shape takes an external id. On Integer ids the signatures differed and the collision was invisible; it is now applyForLoanWithPrincipal. Also drops a redundant String cast on getResourceExternalId, which the generated model has returned as String for a while. --- ...ientLoanChargeExternalIntegrationTest.java | 6 +-- .../ExternalIdSupportIntegrationTest.java | 48 +++++++++---------- ...nTransactionInterestPaymentWaiverTest.java | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java index 2a975c95b86..9b6c4dfccb6 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanChargeExternalIntegrationTest.java @@ -50,7 +50,7 @@ public void checkNewClientLoanChargeSavesExternalId() { final Long loanProductId = createLoanProduct(false, NONE); - final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00"); + final Long loanId = applyForLoanWithPrincipal(clientId, loanProductId, "12,000.00"); approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011")); disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); @@ -72,7 +72,7 @@ public void checkNewClientLoanChargeFindsDuplicateExternalId() { final Long loanProductId = createLoanProduct(false, NONE); - final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00"); + final Long loanId = applyForLoanWithPrincipal(clientId, loanProductId, "12,000.00"); approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011")); disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); @@ -109,7 +109,7 @@ private Long createLoanProduct(final boolean multiDisburseLoan, final String acc return createLoanProduct(loanProductRequest); } - private Long applyForLoanApplication(final Long clientId, final Long loanProductId, String principal) { + private Long applyForLoanWithPrincipal(final Long clientId, final Long loanProductId, String principal) { return applyForLoan(LoanRequestBuilders.legacyIndividualApplication(clientId, loanProductId, principal, 4, new BigDecimal("2"), "20 September 2011")); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java index 203281db33c..d08fc7e2312 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java @@ -104,12 +104,12 @@ public void test() { .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0") .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).buildRequest(null); - final Integer loanProductID = getLoanProductId(loanProductRequest); + final Long loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); String loanExternalIdStr = UUID.randomUUID().toString(); - final PostLoansResponse loan = applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr); + final PostLoansResponse loan = applyForLoanApplication(clientId, loanProductID, loanExternalIdStr); Integer loanId = loan.getResourceId().intValue(); approveLoan("02 September 2022", loanId); @@ -404,7 +404,7 @@ loanExternalIdStr, new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM .withRepaymentTypeAsMonth().withRepaymentAfterEvery("2").withNumberOfRepayments("5").withRepaymentTypeAsMonth() .withinterestRatePerPeriod("1").withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment() .withInterestTypeAsFlat().withAccounting("1", null).buildRequest(null); - final Integer loanProductWithInterestID = getLoanProductId(loanProductWithInterestRequest); + final Long loanProductWithInterestID = getLoanProductId(loanProductWithInterestRequest); LocalDate aMonthBefore = LocalDate.of(2022, 8, 7); String formattedDate = dateFormatter.format(aMonthBefore); @@ -673,12 +673,12 @@ public void negativeTest() { .withAccountingRulePeriodicAccrual(new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0") .withFeeAndPenaltyAssetAccount(assetFeeAndPenaltyAccount).buildRequest(null); - final Integer loanProductID = getLoanProductId(loanProductRequest); + final Long loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); String loanExternalIdStr = UUID.randomUUID().toString(); - final PostLoansResponse loan = applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr); + final PostLoansResponse loan = applyForLoanApplication(clientId, loanProductID, loanExternalIdStr); Integer loanId = loan.getResourceId().intValue(); approveLoan("02 September 2022", loanId); @@ -689,7 +689,7 @@ public void negativeTest() { assertEquals(txnExternalIdStr, disbursedLoanResult.getSubResourceExternalId()); // Second loan - final PostLoansResponse loan2 = applyForLoanApplication(clientId.intValue(), loanProductID, null); + final PostLoansResponse loan2 = applyForLoanApplication(clientId, loanProductID, null); Integer loan2Id = loan2.getResourceId().intValue(); approveLoan("02 September 2022", loan2Id); final PostLoansLoanIdResponse disbursedLoan2Result = disburseLoan("03 September 2022", loan2Id, "1000", null); @@ -834,14 +834,14 @@ public void loan() { .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30").withDaysInYear("365") .withMoratorium("0", "0").withDelinquencyBucket(delinquencyBucketResponse.getResourceId()) .withInArrearsTolerance("1001").withMultiDisburse().withDisallowExpectedDisbursements(true).buildRequest(null); - final Integer loanProductID = getLoanProductId(loanProductRequest); + final Long loanProductID = getLoanProductId(loanProductRequest); final Long clientId = createClient(); String loanExternalIdStr = UUID.randomUUID().toString(); - final PostLoansResponse loan = applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr); + final PostLoansResponse loan = applyForLoanApplication(clientId, loanProductID, loanExternalIdStr); Integer loanId = loan.getResourceId().intValue(); - String resourceExternalId = (String) loan.getResourceExternalId(); + String resourceExternalId = loan.getResourceExternalId(); assertEquals(loanExternalIdStr, resourceExternalId); LocalDate actualDate = LocalDate.of(2022, 10, 10); @@ -887,7 +887,7 @@ public void loan() { assertEquals((long) loanId, delinquencyTagHistoryResponseResult.get(0).getLoanId()); String loanExternalIdStr2 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr2); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr2); PutLoansLoanIdResponse modifyLoanApplicationResult = modifyLoanApplication(loanExternalIdStr2, "modify", new PutLoansLoanIdRequest().submittedOnDate("31 August 2022").dateFormat("dd MMMM yyyy").locale("en") @@ -903,19 +903,19 @@ public void loan() { assertEquals(loanExternalIdStr2, deleteLoanApplicationResult.getResourceExternalId()); String loanExternalIdStr3 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr3); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr3); PostLoansLoanIdResponse result = rejectLoan(loanExternalIdStr3, new PostLoansLoanIdRequest().rejectedOnDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr3, result.getResourceExternalId()); String loanExternalIdStr4 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr4); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr4); result = withdrawnByApplicantLoan(loanExternalIdStr4, new PostLoansLoanIdRequest().withdrawnOnDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); assertEquals(loanExternalIdStr4, result.getResourceExternalId()); String loanExternalIdStr5 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr5); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr5); approveLoan(loanExternalIdStr5, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -925,7 +925,7 @@ public void loan() { // assertEquals(loanExternalIdStr5, result.getResourceExternalId()); String loanExternalIdStr6 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr6); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr6); approveLoan(loanExternalIdStr6, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -935,7 +935,7 @@ public void loan() { final Integer savingsId = openSavingsAccount(clientId, "10000.0", "02 September 2022"); String loanExternalIdStr7 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr7, savingsId.toString()); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr7, savingsId.toString()); approveLoan(loanExternalIdStr7, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -944,7 +944,7 @@ public void loan() { assertEquals(loanExternalIdStr7, result.getResourceExternalId()); String loanExternalIdStr8 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr8); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr8); approveLoan(loanExternalIdStr8, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -954,7 +954,7 @@ public void loan() { assertEquals(loanExternalIdStr8, result.getResourceExternalId()); String loanExternalIdStr9 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr9); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr9); approveLoan(loanExternalIdStr9, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -968,7 +968,7 @@ public void loan() { Integer loanOfficerId = new FeignStaffHelper(FineractFeignClientHelper.getFineractFeignClient()) .createStaff(1L, "20 September 2011").getResourceId().intValue(); String loanExternalIdStr10 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr10); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr10); result = assignLoanOfficerLoan(loanExternalIdStr10, new PostLoansLoanIdRequest().assignmentDate("2 September 2022").locale("en") .dateFormat("dd MMMM yyyy").toLoanOfficerId(loanOfficerId.longValue())); assertEquals(loanExternalIdStr10, result.getResourceExternalId()); @@ -977,17 +977,17 @@ public void loan() { assertEquals(loanExternalIdStr10, result.getResourceExternalId()); String loanExternalIdStr11 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr11); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr11); result = recoverGuaranteesLoan(loanExternalIdStr11, new PostLoansLoanIdRequest()); assertEquals(loanExternalIdStr11, result.getResourceExternalId()); String loanExternalIdStr12 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr12); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr12); result = assignDelinquencyLoan(loanExternalIdStr12, new PostLoansLoanIdRequest()); assertEquals(loanExternalIdStr12, result.getResourceExternalId()); String loanExternalIdStr13 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr13); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr13); result = approveLoan(loanExternalIdStr13, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -998,7 +998,7 @@ public void loan() { assertEquals(loanExternalIdStr13, closeRescheduleResult.getResourceExternalId()); String loanExternalIdStr14 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr14); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr14); String transactionExternalId = UUID.randomUUID().toString(); result = approveLoan(loanExternalIdStr14, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) @@ -1012,7 +1012,7 @@ public void loan() { String loanExternalIdStr15 = UUID.randomUUID().toString(); String transactionExternalId2 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr15); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr15); result = approveLoan(loanExternalIdStr15, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); @@ -1026,7 +1026,7 @@ public void loan() { String loanExternalIdStr16 = UUID.randomUUID().toString(); String transactionExternalId3 = UUID.randomUUID().toString(); - applyForLoanApplication(clientId.intValue(), loanProductID, loanExternalIdStr16); + applyForLoanApplication(clientId, loanProductID, loanExternalIdStr16); approveLoan(loanExternalIdStr16, new PostLoansLoanIdRequest().approvedOnDate("2 September 2022").approvedLoanAmount(new BigDecimal("1000")) .expectedDisbursementDate("2 September 2022").locale("en").dateFormat("dd MMMM yyyy")); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java index 556b4f97ff5..2e34614bedb 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionInterestPaymentWaiverTest.java @@ -762,7 +762,7 @@ public void shouldReturnOkStatusForBatchInterestPaymentWaiver() { final Long clientCollateralId = collateralHelper.createClientCollateral(clientId, collateralId).getResourceId(); assertNotNull(clientCollateralId); - final Integer productId = getLoanProductId(loanProductRequest); + final Long productId = getLoanProductId(loanProductRequest); final Long createActiveClientRequestId = 4730L; final Long applyLoanRequestId = createActiveClientRequestId + 1;