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..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,14 @@ 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") + public Boolean syncDisbursementWithMeeting; @Schema(example = "20 September 2011") public String submittedOnDate; @Schema(example = "786444UUUYYH7") @@ -1418,10 +1426,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 +1477,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 +1815,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/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 7ca6ad7eb3d..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 @@ -22,12 +22,14 @@ 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.PostLoanProductsRequest; 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; @@ -48,9 +50,9 @@ 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", "12,000.00"); + disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId(); @@ -70,9 +72,9 @@ 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", "12,000.00"); + disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00"); final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId(); @@ -103,25 +105,12 @@ 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) { - 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); + 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/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest.java index ff595355497..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; @@ -49,7 +50,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; @@ -104,28 +104,15 @@ 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, 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/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/ClientLoanMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanMultipleDisbursementsIntegrationTest.java index 952c5ea58d5..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 @@ -27,13 +27,14 @@ 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.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; -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; @@ -74,36 +75,20 @@ 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, - 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 +129,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 +208,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 +281,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..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,8 +22,9 @@ 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.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; @@ -85,29 +86,15 @@ 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, 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/ExternalIdSupportIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ExternalIdSupportIntegrationTest.java index 34076e63f8e..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 @@ -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; @@ -66,10 +67,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; @@ -96,18 +98,18 @@ 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 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); @@ -398,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 Long loanProductWithInterestID = getLoanProductId(loanProductWithInterestRequest); LocalDate aMonthBefore = LocalDate.of(2022, 8, 7); String formattedDate = dateFormatter.format(aMonthBefore); @@ -410,14 +412,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(); @@ -664,18 +667,18 @@ 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 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); @@ -686,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); @@ -824,21 +827,21 @@ 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 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); @@ -884,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") @@ -900,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")); @@ -922,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")); @@ -932,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")); @@ -941,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")); @@ -951,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")); @@ -965,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()); @@ -974,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")); @@ -995,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")) @@ -1009,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")); @@ -1023,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/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/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/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/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountDisbursementToSavingsWithAutoDownPaymentTest.java index bed75243c31..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,21 +92,35 @@ 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, 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/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountPaymentAllocationWithOverlappingDownPaymentInstallmentTest.java index 79f06366d3b..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,12 +32,15 @@ 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; 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,29 +762,27 @@ 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; } 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 29cc18d04f5..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 @@ -21,16 +21,20 @@ 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.PostLoanProductsRequest; +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; @@ -56,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); @@ -72,21 +76,35 @@ 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; } - 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 3e9988cf4fa..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,18 +35,20 @@ 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; 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; @@ -191,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) @@ -200,23 +202,37 @@ 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, 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/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanChargeTypeInstallmentFeeErrorHandlingWithAdvancedPaymentAllocationTest.java index 865efcebc7a..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,12 +25,13 @@ 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; 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; @@ -72,25 +73,23 @@ 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) { - 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/LoanDownPaymentTransactionTypeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDownPaymentTransactionTypeTest.java index 42961511408..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 @@ -21,19 +21,21 @@ 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; -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; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; -import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +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.Test; @@ -106,21 +108,21 @@ 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); } 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/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/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 f65a300a606..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 @@ -20,18 +20,20 @@ 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.PostLoanProductsRequest; 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; @@ -48,19 +50,19 @@ 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)); - 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)); + Long loanId = applyForLoan(buildLoanApplication(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); @@ -78,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) @@ -87,25 +89,33 @@ 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); } - @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); } } 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..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; @@ -46,10 +45,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,41 +1704,41 @@ 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(); } 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); } 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(); @@ -1746,47 +1746,47 @@ 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, 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 +1802,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/LoanRescheduleOnDecliningBalanceLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java index a7475c4312f..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 @@ -23,7 +23,7 @@ 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; @@ -36,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; @@ -110,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); } @@ -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) @@ -384,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/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..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 @@ -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; @@ -41,7 +40,11 @@ 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; +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; @@ -119,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, @@ -198,16 +201,16 @@ 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); 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); @@ -215,8 +218,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())); @@ -254,11 +256,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() { @@ -305,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() @@ -314,49 +317,47 @@ 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, 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/LoanTransactionAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionAuditingIntegrationTest.java index 858aa16f6e1..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 @@ -32,16 +32,20 @@ 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.PostLoanProductsRequest; +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 +151,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, @@ -172,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") // @@ -185,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..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 @@ -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 Long 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 39051ce26b5..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,13 +26,14 @@ 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; 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; @@ -88,24 +89,22 @@ 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) { - 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/LoanTransactionReverseReplayRelationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionReverseReplayRelationTest.java index fc063e033a3..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 @@ -21,12 +21,17 @@ 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.loans.LoanProductTestBuilder; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,19 +54,31 @@ 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); - 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/LoanWithAdvancedPaymentAllocationIntegrationTests.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanWithAdvancedPaymentAllocationIntegrationTests.java index 67a7e121cdc..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 @@ -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,12 @@ 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; +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; @@ -52,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); @@ -90,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) { @@ -108,14 +111,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..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 @@ -24,17 +24,20 @@ 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; 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; 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; @@ -151,23 +154,39 @@ 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) { - 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/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, 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; 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; 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..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 @@ -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); } @@ -336,10 +332,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); } @@ -1065,31 +1057,29 @@ protected void verifyBusinessEvents(BusinessEvent... businessEvents) { }); } - protected Integer getLoanProductId(String loanProductJson) { - return createLoanProductFromJson(loanProductJson).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) { - 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 applyForLoanApplication(Long clientId, Long loanProductId, String externalId, String linkAccountId) { + PostLoansRequest request = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "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); } - protected PostLoansResponse getLoanIdFromApplication(String loanApplicationJson) { - Long loanId = applyForLoanFromJson(loanApplicationJson); - PostLoansResponse result = new PostLoansResponse(); - result.setResourceId(loanId); - result.setResourceExternalId(getLoanDetails(loanId).getExternalId()); - return result; + protected PostLoansResponse applyForLoanResponse(PostLoansRequest request) { + return loanHelper.applyForLoan(request); } protected PostLoansLoanIdResponse disburseLoan(String date, Integer loanId, String transactionAmount, String externalId) { @@ -1651,15 +1641,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) { @@ -1868,8 +1854,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 31ad9426794..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 @@ -22,16 +22,7 @@ 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 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 +76,11 @@ 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; @@ -167,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)) { @@ -194,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) { @@ -213,13 +177,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)); } @@ -269,24 +226,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,79 +483,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(); - } - - // 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(); - } - - // 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 CallFailedRuntimeException createRescheduleRequestExpectingError(PostCreateRescheduleLoansRequest request) { + return fail(() -> fineractClient.rescheduleLoans().createRescheduleLoan(request)); } public PostUpdateRescheduleLoansResponse approveRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) { 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..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 @@ -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,81 @@ 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); + /** + * 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 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); + /** + * 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)// + .transactionProcessingStrategyCode(LoanTestData.TransactionProcessingStrategyCode.MIFOS_STANDARD_STRATEGY)// + .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)// + .adjustRepaymentDate(adjustRepaymentDate)// + .note(DISBURSE_NOTE)// + .locale(LoanTestData.LOCALE)// + .dateFormat(LoanTestData.DATETIME_PATTERN); + } + + 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 +209,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 +219,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 +297,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 +598,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; - } - } } 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() {} } 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(); + } +}