diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index 917ae10e668..605fd2c0eae 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -1426,6 +1426,8 @@ private GetWriteOffReasonToExpenseAccountMappings() {} public Boolean useBorrowerCycle; @Schema(example = "loanProduct.active") public String status; + @Schema(example = "2075e308-d4a8-44d9-8203-f5a947b8c2f4") + public String externalId; public GetLoanProductsResponse.GetLoanProductsCurrency currency; @Schema(example = "10000.000000") public Double principal; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ConcurrencyIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ConcurrencyIntegrationTest.java index 0b1cd78c3c0..94f7bf802ed 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ConcurrencyIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ConcurrencyIntegrationTest.java @@ -18,79 +18,57 @@ */ package org.apache.fineract.integrationtests; -import io.restassured.builder.RequestSpecBuilder; -import io.restassured.builder.ResponseSpecBuilder; -import io.restassured.http.ContentType; -import io.restassured.path.json.JsonPath; -import io.restassured.specification.RequestSpecification; -import io.restassured.specification.ResponseSpecification; import java.math.BigDecimal; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Calendar; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.CollateralManagementHelper; -import org.apache.fineract.integrationtests.common.Utils; +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.FeignCollateralHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignTransactionHelper; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; +import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; 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.LoanTestLifecycleExtension; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@ExtendWith(LoanTestLifecycleExtension.class) -public class ConcurrencyIntegrationTest { +public class ConcurrencyIntegrationTest extends FeignLoanTestBase { private static final Logger LOG = LoggerFactory.getLogger(ConcurrencyIntegrationTest.class); - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; private static final String NO_ACCOUNTING = "1"; static final int MYTHREADS = 30; - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - } + private final FeignCollateralHelper collateralHelper = new FeignCollateralHelper(FineractFeignClientHelper.getFineractFeignClient()); @Test public void verifyConcurrentLoanRepayments() { - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); - ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); - final Integer loanProductID = createLoanProduct(false, NO_ACCOUNTING); - final Integer loanID = applyForLoanApplication(clientID, loanProductID, "12,000.00"); - this.loanTransactionHelper.approveLoan("20 September 2011", loanID); - String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, loanID); - this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("20 September 2011", loanID, "12,000.00", - JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); + final Long clientId = createClient(); + Assertions.assertNotNull(clientHelper.getClient(clientId)); + final Long loanProductId = createLoanProduct(false, NO_ACCOUNTING); + final Long loanId = applyForLoanApplicationWithCollateral(clientId, loanProductId, "12,000.00"); + // the loanHelper.approveLoan(date, loanId) shorthand pins the approved amount at 1000; this loan is for 12000 + approveLoan(loanId, LoanRequestBuilders.approveLoan(12000.0, "20 September 2011")); + BigDecimal netDisbursalAmount = getLoanDetails(loanId).getNetDisbursalAmount(); + disburseLoan(loanId, LoanRequestBuilders.disburseLoan(12000.0, "20 September 2011").netDisbursalAmount(netDisbursalAmount)); ExecutorService executor = Executors.newFixedThreadPool(MYTHREADS); Calendar date = Calendar.getInstance(); date.set(2011, 9, 20); - Float repaymentAmount = 100.0f; + Double repaymentAmount = 100.0; for (int i = 0; i < 10; i++) { LOG.info("Starting concurrent transaction number {}", i); date.add(Calendar.DAY_OF_MONTH, 1); repaymentAmount = repaymentAmount + 100; - Runnable worker = new LoanRepaymentExecutor(loanTransactionHelper, loanID, repaymentAmount, date); + Runnable worker = new LoanRepaymentExecutor(transactionHelper, loanId, repaymentAmount, date); executor.execute(worker); } @@ -103,7 +81,7 @@ public void verifyConcurrentLoanRepayments() { } - private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { + private Long createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); LoanProductTestBuilder builder = new LoanProductTestBuilder() // .withPrincipal("12,000.00") // @@ -120,67 +98,41 @@ private Integer createLoanProduct(final boolean multiDisburseLoan, final String if (multiDisburseLoan) { builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true); } - final String loanProductJSON = builder.build(null); - return this.loanTransactionHelper.getLoanProductId(loanProductJSON); + return createLoanProduct(builder.buildRequest(null)); } - private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, String principal) { + private Long applyForLoanApplicationWithCollateral(final Long clientId, final Long loanProductId, String principal) { LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - List collaterals = new ArrayList<>(); - final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); + final Long collateralId = collateralHelper.createCollateralProduct().getResourceId(); Assertions.assertNotNull(collateralId); - final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, - clientID.toString(), collateralId); + final Long clientCollateralId = collateralHelper.createClientCollateral(clientId, collateralId).getResourceId(); Assertions.assertNotNull(clientCollateralId); - addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); - 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") // - .withCollaterals(collaterals).build(clientID.toString(), loanProductID.toString(), null); - return this.loanTransactionHelper.getLoanId(loanApplicationJSON); - } - - private void addCollaterals(List collaterals, Integer collateralId, BigDecimal quantity) { - collaterals.add(collaterals(collateralId, quantity)); - } - - private HashMap collaterals(Integer collateralId, BigDecimal quantity) { - HashMap collateral = new HashMap(2); - collateral.put("clientCollateralId", collateralId.toString()); - collateral.put("quantity", quantity.toString()); - return collateral; + final PostLoansRequest application = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, principal, 4, BigDecimal.valueOf(2), "20 September 2011")// + .collateral(List.of(new PostLoansRequestCollateralData().clientCollateralId(clientCollateralId).quantity(BigDecimal.ONE))); + return applyForLoan(application); } public static class LoanRepaymentExecutor implements Runnable { - private final Integer loanId; - private final Float repaymentAmount; + private final Long loanId; + private final Double repaymentAmount; private final String repaymentDate; - private final LoanTransactionHelper loanTransactionHelper; + private final FeignTransactionHelper transactionHelper; DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); - LoanRepaymentExecutor(LoanTransactionHelper loanTransactionHelper, Integer loanId, Float repaymentAmount, Calendar repaymentDate) { + LoanRepaymentExecutor(FeignTransactionHelper transactionHelper, Long loanId, Double repaymentAmount, Calendar repaymentDate) { this.loanId = loanId; this.repaymentAmount = repaymentAmount; this.repaymentDate = dateFormat.format(repaymentDate.getTime()); - this.loanTransactionHelper = loanTransactionHelper; + this.transactionHelper = transactionHelper; } @Override public void run() { try { - this.loanTransactionHelper.makeRepayment(repaymentDate, repaymentAmount, loanId); + this.transactionHelper.makeLoanRepayment(loanId, LoanRequestBuilders.repayLoan(repaymentAmount, repaymentDate)); } catch (Exception e) { LOG.info("Found an exception {}", e.getMessage()); LOG.info("Details of failed concurrent transaction (date, amount, loanId) are {},{},{}", repaymentDate, repaymentAmount, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java index 190b241d2aa..a46f9490660 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationApprovalTest.java @@ -19,53 +19,32 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; -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.ArrayList; -import java.util.HashMap; import java.util.List; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.CollateralManagementHelper; -import org.apache.fineract.integrationtests.common.CommonConstants; -import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoansDisbursementData; +import org.apache.fineract.client.models.PostLoansLoanIdDisbursementData; +import org.apache.fineract.client.models.PostLoansRequest; +import org.apache.fineract.client.models.PostLoansRequestCollateralData; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignCollateralHelper; +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.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker; -import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -@SuppressWarnings("rawtypes") -@ExtendWith(LoanTestLifecycleExtension.class) @Slf4j -public class LoanApplicationApprovalTest { - - private ResponseSpecification responseSpec; - private ResponseSpecification responseSpecForStatusCode403; - private ResponseSpecification responseSpecForStatusCode400; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.responseSpecForStatusCode403 = new ResponseSpecBuilder().expectStatusCode(403).build(); - this.responseSpecForStatusCode400 = new ResponseSpecBuilder().expectStatusCode(400).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - } +public class LoanApplicationApprovalTest extends FeignLoanTestBase { + + private final FeignCollateralHelper collateralHelper = new FeignCollateralHelper(FineractFeignClientHelper.getFineractFeignClient()); /* * Positive test case: Approved amount non zero is less than proposed amount @@ -74,21 +53,17 @@ public void setup() { public void loanApplicationApprovedAmountLessThanProposedAmount() { final String proposedAmount = "8000"; - final String approvalAmount = "5000"; + final Double approvalAmount = 5000.0; final String approveDate = "20 September 2012"; - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012"); - final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build(null)); - final Integer loanID = applyForLoanApplication(clientID, loanProductID, proposedAmount); + final Long clientId = createClient("01 January 2012"); + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder().buildRequest(null)); + final Long loanId = applyForLoanApplicationWithCollateral(clientId, loanProductId, proposedAmount); - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifyLoanStatus(getLoanDetails(loanId), status -> status.getPendingApproval()); - final String expectedDisbursementDate = null; - List approveTranches = null; - loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, expectedDisbursementDate, approvalAmount, - loanID, approveTranches); - LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + approveLoan(loanId, LoanRequestBuilders.approveLoan(approvalAmount, approveDate)); + verifyLoanStatus(getLoanDetails(loanId), status -> status.getWaitingForDisbursal()); } @@ -99,222 +74,174 @@ public void loanApplicationApprovedAmountLessThanProposedAmount() { public void loanApplicationApprovedAmountGreaterThanProposedAmount() { final String proposedAmount = "5000"; - final String approvalAmount = "9000"; + final Double approvalAmount = 9000.0; final String approveDate = "2 April 2012"; - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2012"); - final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build(null)); - final Integer loanID = applyForLoanApplication(clientID, loanProductID, proposedAmount); + final Long clientId = createClient("01 January 2012"); + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder().buildRequest(null)); + final Long loanId = applyForLoanApplicationWithCollateral(clientId, loanProductId, proposedAmount); - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifyLoanStatus(getLoanDetails(loanId), status -> status.getPendingApproval()); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403); + CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, + () -> approveLoan(loanId, LoanRequestBuilders.approveLoan(approvalAmount, approveDate))); - @SuppressWarnings("unchecked") - List error = (List) this.loanTransactionHelper.approveLoan(approveDate, approvalAmount, loanID, - CommonConstants.RESPONSE_ERROR); - - assertEquals("error.msg.loan.approval.amount.can't.be.greater.than.loan.amount.demanded", - error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + assertEquals(403, exception.getStatus()); + assertErrorGlobalisationCode(exception, "error.msg.loan.approval.amount.can't.be.greater.than.loan.amount.demanded"); } - public HashMap createTrancheDetail(final String date, final String amount) { - HashMap detail = new HashMap<>(); - detail.put("expectedDisbursementDate", date); - detail.put("principal", amount); + public PostLoansDisbursementData createTrancheDetail(final String date, final double amount) { + return LoanRequestBuilders.applyTrancheDetail(date, amount); + } - return detail; + public PostLoansLoanIdDisbursementData approveTrancheDetail(final String date, final double amount) { + return LoanRequestBuilders.approveTrancheDetail(date, amount); } @Test public void loanApplicationApprovalAndValidationForMultiDisburseLoans() { - List createTranches = new ArrayList<>(); - createTranches.add(createTrancheDetail("01 March 2014", "1000")); - createTranches.add(createTrancheDetail("23 March 2014", "4000")); + List createTranches = List.of(// + createTrancheDetail("01 March 2014", 1000), // + createTrancheDetail("23 March 2014", 4000)); - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); - log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientID); + final Long clientId = createClient("01 January 2014"); + log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientId); - final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() // + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder() // .withInterestTypeAsDecliningBalance() // .withTranches(true) // .withInterestCalculationPeriodTypeAsRepaymentPeriod(true) // - .build(null)); + .buildRequest(null)); log.info("----------------------------------LOAN PRODUCT CREATED WITH ID------------------------------------------- {}", - loanProductID); + loanProductId); - trancheLoansApprovedAmountLesserThanProposedAmount(clientID, loanProductID, createTranches); - trancheLoansApprovalValidation(clientID, loanProductID, createTranches); + trancheLoansApprovedAmountLesserThanProposedAmount(clientId, loanProductId, createTranches); + trancheLoansApprovalValidation(clientId, loanProductId, createTranches); } @Test public void loanApplicationShouldFailIfTransactionProcessingStrategyIsAdvancedPaymentAllocationButItIsNotConfiguredOnProduct() { - final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); + final Long clientId = createClient("01 January 2014"); log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientId); - final Integer loanProductId = this.loanTransactionHelper - .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(false) - .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null)); + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(false) + .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).buildRequest(null)); log.info("----------------------------------LOAN PRODUCT CREATED WITH ID------------------------------------------- {}", loanProductId); - loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403); - final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("01 March 2022").withSubmittedOnDate("01 March 2022").withLoanType("individual") - .withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY) - .build(clientId.toString(), loanProductId.toString(), null); - List error = (List) loanTransactionHelper.createLoanAccount(loanApplicationJSON, CommonConstants.RESPONSE_ERROR); - assertEquals("strategy.cannot.be.advanced.payment.allocation.if.not.configured", - error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, + () -> applyForLoan(LoanRequestBuilders.applyLoan(clientId, loanProductId, "01 March 2022", 1000.0, 1)// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .transactionProcessingStrategyCode( + AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY))); + + assertEquals(403, exception.getStatus()); + assertErrorGlobalisationCode(exception, "strategy.cannot.be.advanced.payment.allocation.if.not.configured"); } - private void trancheLoansApprovedAmountLesserThanProposedAmount(Integer clientID, Integer loanProductID, List createTranches) { + private void trancheLoansApprovedAmountLesserThanProposedAmount(Long clientId, Long loanProductId, + List createTranches) { final String proposedAmount = "5000"; - final String approvalAmount = "2000"; + final Double approvalAmount = 2000.0; final String approveDate = "01 March 2014"; final String expectedDisbursementDate = "01 March 2014"; - List approveTranches = new ArrayList<>(); - approveTranches.add(createTrancheDetail("01 March 2014", "1000")); - approveTranches.add(createTrancheDetail("23 March 2014", "1000")); + List approveTranches = List.of(// + approveTrancheDetail("01 March 2014", 1000), // + approveTrancheDetail("23 March 2014", 1000)); - final Integer loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches); - log.info("-----------------------------------LOAN CREATED WITH LOANID------------------------------------------------- {}", loanID); + final Long loanId = applyForLoanApplicationWithTranches(clientId, loanProductId, proposedAmount, createTranches); + log.info("-----------------------------------LOAN CREATED WITH LOANID------------------------------------------------- {}", loanId); - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifyLoanStatus(getLoanDetails(loanId), status -> status.getPendingApproval()); log.info("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, expectedDisbursementDate, approvalAmount, - loanID, approveTranches); - LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); - LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + approveLoan(loanId, + LoanRequestBuilders.approveLoanWithTranches(approvalAmount, approveDate, expectedDisbursementDate, approveTranches)); + GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); + assertFalse(loanDetails.getStatus().getPendingApproval()); + verifyLoanStatus(loanDetails, status -> status.getWaitingForDisbursal()); log.info("-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); } - private void trancheLoansApprovalValidation(Integer clientID, Integer loanProductID, List createTranches) { + private void trancheLoansApprovalValidation(Long clientId, Long loanProductId, List createTranches) { final String proposedAmount = "5000"; - final String approvalAmount1 = "10000"; - final String approvalAmount3 = "400"; - final String approvalAmount4 = "200"; + final Double approvalAmount1 = 10000.0; + final Double approvalAmount3 = 400.0; + final Double approvalAmount4 = 200.0; final String approveDate = "01 March 2014"; final String expectedDisbursementDate = "01 March 2014"; - List approveTranche1 = new ArrayList<>(); - approveTranche1.add(createTrancheDetail("01 March 2014", "5000")); - approveTranche1.add(createTrancheDetail("23 March 2014", "5000")); + List approveTranche1 = List.of(// + approveTrancheDetail("01 March 2014", 5000), // + approveTrancheDetail("23 March 2014", 5000)); - List approveTranche3 = new ArrayList<>(); - approveTranche3.add(createTrancheDetail("01 March 2014", "100")); - approveTranche3.add(createTrancheDetail("23 March 2014", "100")); - approveTranche3.add(createTrancheDetail("24 March 2014", "100")); - approveTranche3.add(createTrancheDetail("25 March 2014", "100")); + List approveTranche3 = List.of(// + approveTrancheDetail("01 March 2014", 100), // + approveTrancheDetail("23 March 2014", 100), // + approveTrancheDetail("24 March 2014", 100), // + approveTrancheDetail("25 March 2014", 100)); - List approveTranche4 = new ArrayList<>(); - approveTranche4.add(createTrancheDetail("01 March 2014", "100")); - approveTranche4.add(createTrancheDetail("23 March 2014", "100")); - approveTranche4.add(createTrancheDetail("24 March 2014", "100")); + List approveTranche4 = List.of(// + approveTrancheDetail("01 March 2014", 100), // + approveTrancheDetail("23 March 2014", 100), // + approveTrancheDetail("24 March 2014", 100)); - final Integer loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches); - log.info("-----------------------------------LOAN CREATED WITH LOANID------------------------------------------------- {}", loanID); + final Long loanId = applyForLoanApplicationWithTranches(clientId, loanProductId, proposedAmount, createTranches); + log.info("-----------------------------------LOAN CREATED WITH LOANID------------------------------------------------- {}", loanId); - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + verifyLoanStatus(getLoanDetails(loanId), status -> status.getPendingApproval()); log.info("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode400); /* Sum of tranches is greater than approved amount */ - List> error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate, - approvalAmount4, loanID, approveTranche4, CommonConstants.RESPONSE_ERROR); - assertEquals("validation.msg.loan.principal.sum.of.multi.disburse.amounts.must.be.equal.to.or.lesser.than.approved.principal", - error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403); + CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> approveLoan(loanId, + LoanRequestBuilders.approveLoanWithTranches(approvalAmount4, approveDate, expectedDisbursementDate, approveTranche4))); + assertEquals(400, exception.getStatus()); + assertErrorGlobalisationCode(exception, + "validation.msg.loan.principal.sum.of.multi.disburse.amounts.must.be.equal.to.or.lesser.than.approved.principal"); /* Sum of tranches exceeds the proposed amount */ - error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate, approvalAmount1, loanID, - approveTranche1, CommonConstants.RESPONSE_ERROR); - assertEquals("error.msg.loan.approval.amount.can't.be.greater.than.loan.amount.demanded", - error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + exception = assertThrows(CallFailedRuntimeException.class, () -> approveLoan(loanId, + LoanRequestBuilders.approveLoanWithTranches(approvalAmount1, approveDate, expectedDisbursementDate, approveTranche1))); + assertEquals(403, exception.getStatus()); + assertErrorGlobalisationCode(exception, "error.msg.loan.approval.amount.can't.be.greater.than.loan.amount.demanded"); /* No. of tranches exceeds the max tranche count at product level */ - error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate, approvalAmount3, loanID, - approveTranche3, CommonConstants.RESPONSE_ERROR); - assertEquals("error.msg.disbursementData.exceeding.max.tranche.count", - error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - - /* If tranches are not specified for a multi-disburse loan */ - /* - * error = this.loanTransactionHelper.approveLoanForTranches(approveDate, expectedDisbursementDate, - * approvalAmount5, loanID, approveTranche5, CommonConstants.RESPONSE_ERROR); - * assertEquals("error.msg.disbursementData.required", - * error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); - */ + exception = assertThrows(CallFailedRuntimeException.class, () -> approveLoan(loanId, + LoanRequestBuilders.approveLoanWithTranches(approvalAmount3, approveDate, expectedDisbursementDate, approveTranche3))); + assertEquals(403, exception.getStatus()); + assertErrorGlobalisationCode(exception, "error.msg.disbursementData.exceeding.max.tranche.count"); } - private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String proposedAmount) { - List collaterals = new ArrayList<>(); - final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); - Assertions.assertNotNull(collateralId); - final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, - clientID.toString(), collateralId); - Assertions.assertNotNull(clientCollateralId); - addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); - - final String loanApplication = new LoanApplicationTestBuilder().withPrincipal(proposedAmount).withLoanTermFrequency("5") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate("20 September 2012") - .withCollaterals(collaterals).withSubmittedOnDate("02 April 2012") - .build(clientID.toString(), loanProductID.toString(), null); - return this.loanTransactionHelper.getLoanId(loanApplication); - } - - private void addCollaterals(List collaterals, Integer collateralId, BigDecimal quantity) { - collaterals.add(collaterals(collateralId, quantity)); + private Long applyForLoanApplicationWithCollateral(final Long clientId, final Long loanProductId, final String proposedAmount) { + final PostLoansRequest application = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, proposedAmount, 5, BigDecimal.valueOf(2), "20 September 2012")// + .submittedOnDate("02 April 2012")// + .collateral(collateralFor(clientId)); + return applyForLoan(application); } - private HashMap collaterals(Integer collateralId, BigDecimal quantity) { - HashMap collateral = new HashMap(2); - collateral.put("clientCollateralId", collateralId.toString()); - collateral.put("quantity", quantity.toString()); - return collateral; + public Long applyForLoanApplicationWithTranches(final Long clientId, final Long loanProductId, String principal, + List tranches) { + log.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); + final PostLoansRequest application = LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, principal, 5, BigDecimal.valueOf(2), "01 March 2014")// + .collateral(collateralFor(clientId))// + .disbursementData(tranches); + return applyForLoan(application); } - public Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal, - List tranches) { - log.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - List collaterals = new ArrayList<>(); - final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); + private List collateralFor(final Long clientId) { + final Long collateralId = collateralHelper.createCollateralProduct().getResourceId(); Assertions.assertNotNull(collateralId); - final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, - clientID.toString(), collateralId); + final Long clientCollateralId = collateralHelper.createClientCollateral(clientId, collateralId).getResourceId(); Assertions.assertNotNull(clientCollateralId); - addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); - final String loanApplicationJSON = new LoanApplicationTestBuilder() - // - .withPrincipal(principal) - // - .withLoanTermFrequency("5") - // - .withLoanTermFrequencyAsMonths() - // - .withNumberOfRepayments("5").withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withExpectedDisbursementDate("01 March 2014") // - .withTranches(tranches) // - .withInterestTypeAsDecliningBalance() // - .withSubmittedOnDate("01 March 2014") // - .withCollaterals(collaterals).build(clientID.toString(), loanProductID.toString(), null); - - return this.loanTransactionHelper.getLoanId(loanApplicationJSON); + return List.of(new PostLoansRequestCollateralData().clientCollateralId(clientCollateralId).quantity(BigDecimal.ONE)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest.java index e5958436830..88d4422d2fe 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest.java @@ -18,104 +18,67 @@ */ package org.apache.fineract.integrationtests; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -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.util.UUID; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdResponse; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.Utils; +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.accounting.Account; -import org.apache.fineract.integrationtests.common.accounting.AccountHelper; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -@ExtendWith(LoanTestLifecycleExtension.class) -public class LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest { - - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private ClientHelper clientHelper; - private LoanTransactionHelper loanTransactionHelper; - private AccountHelper accountHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); - this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); - } + +public class LoanApplicationRejectionForLoanProductWithPeriodicAccrualAccountingTest extends FeignLoanTestBase { @Test public void loanApplicationRejectionForPeriodicAccrualAccountingLoanProductTest() { - Account assetAccount = this.accountHelper.createAssetAccount(); - Account incomeAccount = this.accountHelper.createIncomeAccount(); - Account expenseAccount = this.accountHelper.createExpenseAccount(); - Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + Account assetAccount = accountHelper.createAssetAccount(); + Account incomeAccount = accountHelper.createIncomeAccount(); + Account expenseAccount = accountHelper.createExpenseAccount(); + Account overpaymentAccount = accountHelper.createLiabilityAccount(); // Create Loan Product with Periodic Accrual accounting - final Integer loanProductID = createLoanProductWithPeriodicAccrualAccounting(assetAccount, incomeAccount, expenseAccount, + final Long loanProductId = createLoanProductWithPeriodicAccrualAccounting(assetAccount, incomeAccount, expenseAccount, overpaymentAccount); // Loan ExternalId String loanExternalIdStr = UUID.randomUUID().toString(); // Client and Loan account creation - final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); + final Long clientId = createClient(); - final Integer loanId = createLoanAccount(clientId, loanProductID, loanExternalIdStr); + final Long loanId = createLoanAccount(clientId, loanProductId, loanExternalIdStr); // verify Loan status as submitted and pending approval - GetLoansLoanIdResponse loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanId); + GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); assertTrue(loanDetails.getStatus().getPendingApproval()); // Reject Loan application - PostLoansLoanIdResponse result = this.loanTransactionHelper.rejectLoan(loanExternalIdStr, - new PostLoansLoanIdRequest().rejectedOnDate("3 September 2022").locale("en").dateFormat("dd MMMM yyyy")); + PostLoansLoanIdResponse result = loanHelper.rejectLoanByExternalId(loanExternalIdStr, + LoanRequestBuilders.rejectLoan("3 September 2022")); // Verify Loan application status is Rejected - assertTrue(result.getChanges().getStatus().getValue().equals("Rejected")); + assertEquals("Rejected", result.getChanges().getStatus().getValue()); } - private Integer createLoanProductWithPeriodicAccrualAccounting(final Account... accounts) { - - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentAfterEvery("1") - .withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") - .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat() - .withAccountingRulePeriodicAccrual(accounts).withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0") - .build(null); - - return this.loanTransactionHelper.getLoanProductId(loanProductJSON); + private Long createLoanProductWithPeriodicAccrualAccounting(final Account... accounts) { + return createLoanProduct(new LoanProductTestBuilder().withPrincipal("1000").withRepaymentAfterEvery("1").withNumberOfRepayments("1") + .withRepaymentTypeAsMonth().withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsMonths() + .withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts) + .withDaysInMonth("30").withDaysInYear("365").withMoratorium("0", "0").buildRequest(null)); } - private Integer createLoanAccount(final Integer clientID, final Integer 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); - - final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON); - return loanId; + private Long createLoanAccount(final Long clientId, final Long loanProductId, final String externalId) { + return applyForLoan(LoanRequestBuilders.applyLoan(clientId, loanProductId, "01 September 2022", 1000.0, 1)// + .expectedDisbursementDate("03 September 2022")// + .interestType(LoanTestData.InterestType.FLAT)// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationScheduleMonthlyTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationScheduleMonthlyTest.java index fec4fb19c27..81eea608e11 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationScheduleMonthlyTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanApplicationScheduleMonthlyTest.java @@ -20,295 +20,154 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -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.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public class LoanApplicationScheduleMonthlyTest { +public class LoanApplicationScheduleMonthlyTest extends FeignLoanTestBase { - private static final Logger LOG = LoggerFactory.getLogger(LoanApplicationScheduleMonthlyTest.class); public static final Integer TOTAL_REPAYMENTS = 14; public static final String NUMBER_OF_REPAYMENTS = String.valueOf(TOTAL_REPAYMENTS); public static final String DISBURSEMENT_DATE = "30 December 2022"; public static final String CLIENT_ACTIVATION_DATE = "13 October 2022"; - public static final String DUE_DATE = "dueDate"; - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - } - - @SuppressWarnings({ "unchecked" }) @Test public void validateSeedDate31() { - final Integer clientId = createClient(CLIENT_ACTIVATION_DATE); + final Long clientId = createClient(CLIENT_ACTIVATION_DATE); String firstRepaymentDate = "31 January 2023"; - Integer loanProductId = createLoanProductEntity(); - - Integer loanId = applyForLoanApplication(clientId, loanProductId, firstRepaymentDate); - - final ArrayList repaymentPeriods = (ArrayList) this.loanTransactionHelper - .getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanId); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 1, 31)), repaymentPeriods.get(1).get(DUE_DATE), - "Checking for Due Date for 1st Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 2, 28)), repaymentPeriods.get(2).get(DUE_DATE), - "Checking for Due Date for 2nd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 3, 31)), repaymentPeriods.get(3).get(DUE_DATE), - "Checking for Due Date for 3rd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 4, 30)), repaymentPeriods.get(4).get(DUE_DATE), - "Checking for Due Date for 4th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 5, 31)), repaymentPeriods.get(5).get(DUE_DATE), - "Checking for Due Date for 5th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 6, 30)), repaymentPeriods.get(6).get(DUE_DATE), - "Checking for Due Date for 6th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 7, 31)), repaymentPeriods.get(7).get(DUE_DATE), - "Checking for Due Date for 7th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 8, 31)), repaymentPeriods.get(8).get(DUE_DATE), - "Checking for Due Date for 8th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 9, 30)), repaymentPeriods.get(9).get(DUE_DATE), - "Checking for Due Date for 9th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 10, 31)), repaymentPeriods.get(10).get(DUE_DATE), - "Checking for Due Date for 10th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 11, 30)), repaymentPeriods.get(11).get(DUE_DATE), - "Checking for Due Date for 11th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 12, 31)), repaymentPeriods.get(12).get(DUE_DATE), - "Checking for Due Date for 12th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 1, 31)), repaymentPeriods.get(13).get(DUE_DATE), - "Checking for Due Date for 13th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 2, 29)), repaymentPeriods.get(14).get(DUE_DATE), - "Checking for Due Date for 14th Month"); + Long loanProductId = createLoanProductEntity(); + + Long loanId = applyForLoanApplicationWithFirstRepaymentDate(clientId, loanProductId, firstRepaymentDate); + + verifyDueDates(loanId, List.of(// + LocalDate.of(2023, 1, 31), // + LocalDate.of(2023, 2, 28), // + LocalDate.of(2023, 3, 31), // + LocalDate.of(2023, 4, 30), // + LocalDate.of(2023, 5, 31), // + LocalDate.of(2023, 6, 30), // + LocalDate.of(2023, 7, 31), // + LocalDate.of(2023, 8, 31), // + LocalDate.of(2023, 9, 30), // + LocalDate.of(2023, 10, 31), // + LocalDate.of(2023, 11, 30), // + LocalDate.of(2023, 12, 31), // + LocalDate.of(2024, 1, 31), // + LocalDate.of(2024, 2, 29))); } - private Integer createClient(String activationDate) { - final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, activationDate); - return clientId; - } - - @SuppressWarnings({ "unchecked" }) @Test public void validateSeedDate30() { - final Integer clientId = createClient(CLIENT_ACTIVATION_DATE); + final Long clientId = createClient(CLIENT_ACTIVATION_DATE); String firstRepaymentDate = "30 January 2023"; - Integer loanProductId = createLoanProductEntity(); - - Integer loanId = applyForLoanApplication(clientId, loanProductId, firstRepaymentDate); - - final ArrayList repaymentPeriods = (ArrayList) this.loanTransactionHelper - .getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanId); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 1, 30)), repaymentPeriods.get(1).get(DUE_DATE), - "Checking for Due Date for 1st Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 2, 28)), repaymentPeriods.get(2).get(DUE_DATE), - "Checking for Due Date for 2nd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 3, 30)), repaymentPeriods.get(3).get(DUE_DATE), - "Checking for Due Date for 3rd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 4, 30)), repaymentPeriods.get(4).get(DUE_DATE), - "Checking for Due Date for 4th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 5, 30)), repaymentPeriods.get(5).get(DUE_DATE), - "Checking for Due Date for 5th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 6, 30)), repaymentPeriods.get(6).get(DUE_DATE), - "Checking for Due Date for 6th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 7, 30)), repaymentPeriods.get(7).get(DUE_DATE), - "Checking for Due Date for 7th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 8, 30)), repaymentPeriods.get(8).get(DUE_DATE), - "Checking for Due Date for 8th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 9, 30)), repaymentPeriods.get(9).get(DUE_DATE), - "Checking for Due Date for 9th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 10, 30)), repaymentPeriods.get(10).get(DUE_DATE), - "Checking for Due Date for 10th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 11, 30)), repaymentPeriods.get(11).get(DUE_DATE), - "Checking for Due Date for 11th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 12, 30)), repaymentPeriods.get(12).get(DUE_DATE), - "Checking for Due Date for 12th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 1, 30)), repaymentPeriods.get(13).get(DUE_DATE), - "Checking for Due Date for 13th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 2, 29)), repaymentPeriods.get(14).get(DUE_DATE), - "Checking for Due Date for 14th Month"); + Long loanProductId = createLoanProductEntity(); + + Long loanId = applyForLoanApplicationWithFirstRepaymentDate(clientId, loanProductId, firstRepaymentDate); + + verifyDueDates(loanId, List.of(// + LocalDate.of(2023, 1, 30), // + LocalDate.of(2023, 2, 28), // + LocalDate.of(2023, 3, 30), // + LocalDate.of(2023, 4, 30), // + LocalDate.of(2023, 5, 30), // + LocalDate.of(2023, 6, 30), // + LocalDate.of(2023, 7, 30), // + LocalDate.of(2023, 8, 30), // + LocalDate.of(2023, 9, 30), // + LocalDate.of(2023, 10, 30), // + LocalDate.of(2023, 11, 30), // + LocalDate.of(2023, 12, 30), // + LocalDate.of(2024, 1, 30), // + LocalDate.of(2024, 2, 29))); } - @SuppressWarnings({ "unchecked" }) @Test public void validateSeedDate28() { - final Integer clientId = createClient(CLIENT_ACTIVATION_DATE); + final Long clientId = createClient(CLIENT_ACTIVATION_DATE); String firstRepaymentDate = "28 January 2023"; - Integer loanProductId = createLoanProductEntity(); - - Integer loanId = applyForLoanApplication(clientId, loanProductId, firstRepaymentDate); - - final ArrayList repaymentPeriods = (ArrayList) this.loanTransactionHelper - .getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanId); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 1, 28)), repaymentPeriods.get(1).get(DUE_DATE), - "Checking for Due Date for 1st Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 2, 28)), repaymentPeriods.get(2).get(DUE_DATE), - "Checking for Due Date for 2nd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 3, 28)), repaymentPeriods.get(3).get(DUE_DATE), - "Checking for Due Date for 3rd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 4, 28)), repaymentPeriods.get(4).get(DUE_DATE), - "Checking for Due Date for 4th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 5, 28)), repaymentPeriods.get(5).get(DUE_DATE), - "Checking for Due Date for 5th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 6, 28)), repaymentPeriods.get(6).get(DUE_DATE), - "Checking for Due Date for 6th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 7, 28)), repaymentPeriods.get(7).get(DUE_DATE), - "Checking for Due Date for 7th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 8, 28)), repaymentPeriods.get(8).get(DUE_DATE), - "Checking for Due Date for 8th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 9, 28)), repaymentPeriods.get(9).get(DUE_DATE), - "Checking for Due Date for 9th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 10, 28)), repaymentPeriods.get(10).get(DUE_DATE), - "Checking for Due Date for 10th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 11, 28)), repaymentPeriods.get(11).get(DUE_DATE), - "Checking for Due Date for 11th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 12, 28)), repaymentPeriods.get(12).get(DUE_DATE), - "Checking for Due Date for 12th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 1, 28)), repaymentPeriods.get(13).get(DUE_DATE), - "Checking for Due Date for 13th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 2, 28)), repaymentPeriods.get(14).get(DUE_DATE), - "Checking for Due Date for 14th Month"); + Long loanProductId = createLoanProductEntity(); + + Long loanId = applyForLoanApplicationWithFirstRepaymentDate(clientId, loanProductId, firstRepaymentDate); + + verifyDueDates(loanId, List.of(// + LocalDate.of(2023, 1, 28), // + LocalDate.of(2023, 2, 28), // + LocalDate.of(2023, 3, 28), // + LocalDate.of(2023, 4, 28), // + LocalDate.of(2023, 5, 28), // + LocalDate.of(2023, 6, 28), // + LocalDate.of(2023, 7, 28), // + LocalDate.of(2023, 8, 28), // + LocalDate.of(2023, 9, 28), // + LocalDate.of(2023, 10, 28), // + LocalDate.of(2023, 11, 28), // + LocalDate.of(2023, 12, 28), // + LocalDate.of(2024, 1, 28), // + LocalDate.of(2024, 2, 28))); } - @SuppressWarnings({ "unchecked" }) @Test public void validateSeedDate25() { - final Integer clientId = createClient(CLIENT_ACTIVATION_DATE); + final Long clientId = createClient(CLIENT_ACTIVATION_DATE); String firstRepaymentDate = "25 January 2023"; - Integer loanProductId = createLoanProductEntity(); - - Integer loanId = applyForLoanApplication(clientId, loanProductId, firstRepaymentDate); - - final ArrayList repaymentPeriods = (ArrayList) this.loanTransactionHelper - .getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanId); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 1, 25)), repaymentPeriods.get(1).get(DUE_DATE), - "Checking for Due Date for 1st Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 2, 25)), repaymentPeriods.get(2).get(DUE_DATE), - "Checking for Due Date for 2nd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 3, 25)), repaymentPeriods.get(3).get(DUE_DATE), - "Checking for Due Date for 3rd Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 4, 25)), repaymentPeriods.get(4).get(DUE_DATE), - "Checking for Due Date for 4th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 5, 25)), repaymentPeriods.get(5).get(DUE_DATE), - "Checking for Due Date for 5th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 6, 25)), repaymentPeriods.get(6).get(DUE_DATE), - "Checking for Due Date for 6th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 7, 25)), repaymentPeriods.get(7).get(DUE_DATE), - "Checking for Due Date for 7th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 8, 25)), repaymentPeriods.get(8).get(DUE_DATE), - "Checking for Due Date for 8th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 9, 25)), repaymentPeriods.get(9).get(DUE_DATE), - "Checking for Due Date for 9th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 10, 25)), repaymentPeriods.get(10).get(DUE_DATE), - "Checking for Due Date for 10th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 11, 25)), repaymentPeriods.get(11).get(DUE_DATE), - "Checking for Due Date for 11th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2023, 12, 25)), repaymentPeriods.get(12).get(DUE_DATE), - "Checking for Due Date for 12th Month"); - - assertEquals(new ArrayList<>(Arrays.asList(2024, 1, 25)), repaymentPeriods.get(13).get(DUE_DATE), - "Checking for Due Date for 13th Month"); + Long loanProductId = createLoanProductEntity(); + + Long loanId = applyForLoanApplicationWithFirstRepaymentDate(clientId, loanProductId, firstRepaymentDate); + + verifyDueDates(loanId, List.of(// + LocalDate.of(2023, 1, 25), // + LocalDate.of(2023, 2, 25), // + LocalDate.of(2023, 3, 25), // + LocalDate.of(2023, 4, 25), // + LocalDate.of(2023, 5, 25), // + LocalDate.of(2023, 6, 25), // + LocalDate.of(2023, 7, 25), // + LocalDate.of(2023, 8, 25), // + LocalDate.of(2023, 9, 25), // + LocalDate.of(2023, 10, 25), // + LocalDate.of(2023, 11, 25), // + LocalDate.of(2023, 12, 25), // + LocalDate.of(2024, 1, 25), // + LocalDate.of(2024, 2, 25))); + } - assertEquals(new ArrayList<>(Arrays.asList(2024, 2, 25)), repaymentPeriods.get(14).get(DUE_DATE), - "Checking for Due Date for 14th Month"); + /** + * Asserts the due date of every repayment period. Period 0 is the disbursement row, so the expected dates line up + * with periods 1..n. + */ + private void verifyDueDates(final Long loanId, final List expectedDueDates) { + final List repaymentPeriods = getLoanDetails(loanId).getRepaymentSchedule().getPeriods(); + assertEquals(expectedDueDates.size() + 1, repaymentPeriods.size(), "Checking the number of repayment periods"); + for (int month = 1; month <= expectedDueDates.size(); month++) { + assertEquals(expectedDueDates.get(month - 1), repaymentPeriods.get(month).getDueDate(), + "Checking for Due Date for " + month + " Month"); + } } /** * create a new loan product **/ - private Integer createLoanProductEntity() { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("10000").withRepaymentAfterEvery("1") + private Long createLoanProductEntity() { + return createLoanProduct(new LoanProductTestBuilder().withPrincipal("10000").withRepaymentAfterEvery("1") .withNumberOfRepayments(NUMBER_OF_REPAYMENTS).withRepaymentTypeAsMonth().withInterestRateFrequencyTypeAsMonths() - .build(null); - - Integer loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON); - return loanProductId; + .buildRequest(null)); } /** * Apply for a Loan */ - private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, String firstRepaymentDate) { - final String loanApplication = new LoanApplicationTestBuilder().withPrincipal("10000").withLoanTermFrequency(NUMBER_OF_REPAYMENTS) - .withLoanTermFrequencyAsMonths().withNumberOfRepayments(NUMBER_OF_REPAYMENTS).withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate(DISBURSEMENT_DATE) - .withSubmittedOnDate(DISBURSEMENT_DATE).withFirstRepaymentDate(firstRepaymentDate) - .build(clientID.toString(), loanProductID.toString(), null); - return this.loanTransactionHelper.getLoanId(loanApplication); + private Long applyForLoanApplicationWithFirstRepaymentDate(final Long clientId, final Long loanProductId, String firstRepaymentDate) { + return applyForLoan(LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "10000", TOTAL_REPAYMENTS, BigDecimal.valueOf(2), DISBURSEMENT_DATE) + .repaymentsStartingFromDate(firstRepaymentDate)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java index e5ef1220b4f..4120cee4638 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java @@ -18,126 +18,122 @@ */ package org.apache.fineract.integrationtests; -import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY; -import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE; -import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY; -import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -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.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import org.apache.fineract.client.feign.FineractFeignClient; +import org.apache.fineract.client.models.LoanAuditFieldsData; +import org.apache.fineract.client.models.PostLoansRequest; import org.apache.fineract.infrastructure.core.service.DateUtils; -import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignLoanHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignStaffHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignUserHelper; +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.accounting.AccountHelper; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker; -import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.apache.fineract.integrationtests.common.organisation.StaffHelper; -import org.apache.fineract.integrationtests.useradministration.users.UserHelper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@ExtendWith(LoanTestLifecycleExtension.class) -public class LoanAuditingIntegrationTest { +public class LoanAuditingIntegrationTest extends FeignLoanTestBase { private static final Logger LOG = LoggerFactory.getLogger(LoanAuditingIntegrationTest.class); - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - private AccountHelper accountHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); - } + private static final String NEW_USER_PASSWORD = "A1b2c3d4e5f$"; @Test public void checkAuditDates() throws InterruptedException { - final Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + final Long staffId = new FeignStaffHelper(FineractFeignClientHelper.getFineractFeignClient()).createStaff().getResourceId(); String username = Utils.uniqueRandomStringGenerator("user", 8); - final Integer userId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, 1, staffId, username, "A1b2c3d4e5f$", - "resourceId"); + final Long userId = FeignUserHelper.createUser(1L, staffId, username, NEW_USER_PASSWORD).getResourceId(); LOG.info("-------------------------Creating Client---------------------------"); - final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); - ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientID); - LOG.info("-------------------------Creating Loan---------------------------"); - final Account assetAccount = this.accountHelper.createAssetAccount(); - final Account incomeAccount = this.accountHelper.createIncomeAccount(); - final Account expenseAccount = this.accountHelper.createExpenseAccount(); - final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + final Long clientId = createClient(); + Assertions.assertNotNull(clientHelper.getClient(clientId)); - final Integer loanProductID = this.loanTransactionHelper.createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, "2", - assetAccount, incomeAccount, expenseAccount, overpaymentAccount); + LOG.info("-------------------------Creating Loan---------------------------"); + final Long loanProductId = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, "2"); OffsetDateTime now = Utils.getAuditDateTimeToCompare(); - final Integer loanID = this.loanTransactionHelper.applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, - Collections.emptyList(), null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY, "10 July 2022", "11 July 2022"); - Assertions.assertNotNull(loanID); - HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + final Long loanId = applyForLoanApplication(clientId, loanProductId, 10000.0, "10 July 2022", "11 July 2022"); + Assertions.assertNotNull(loanId); + verifyLoanStatus(loanId, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL); - Map auditFieldsResponse = LoanTransactionHelper.getLoanAuditFields(requestSpec, responseSpec, loanID, ""); + LoanAuditFieldsData auditFieldsResponse = getAuditFields(loanId); - OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), - DateTimeFormatter.ISO_OFFSET_DATE_TIME); - OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), - DateTimeFormatter.ISO_OFFSET_DATE_TIME); + OffsetDateTime createdDate = auditFieldsResponse.getCreatedDate(); + OffsetDateTime lastModifiedDate = auditFieldsResponse.getLastModifiedDate(); LOG.info("-------------------------Check Audit dates---------------------------"); - assertEquals(1, auditFieldsResponse.get(CREATED_BY)); - assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY)); + assertEquals(1L, auditFieldsResponse.getCreatedBy()); + assertEquals(1L, auditFieldsResponse.getLastModifiedBy()); assertTrue(DateUtils.isEqual(now, createdDate, ChronoUnit.MINUTES)); assertTrue(DateUtils.isEqual(now, lastModifiedDate, ChronoUnit.MINUTES)); LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------"); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", - "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "A1b2c3d4e5f$")); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + // approve as the newly created user, so the audit fields record a different last modifier + FineractFeignClient asNewUser = FineractFeignClientHelper.createNewFineractFeignClient(username, NEW_USER_PASSWORD); + FeignLoanHelper newUserLoanHelper = new FeignLoanHelper(asNewUser); OffsetDateTime now2 = Utils.getAuditDateTimeToCompare(); - loanStatusHashMap = this.loanTransactionHelper.approveLoan("11 July 2022", loanID); - LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); - auditFieldsResponse = LoanTransactionHelper.getLoanAuditFields(requestSpec, responseSpec, loanID, ""); + newUserLoanHelper.approveLoan(loanId, LoanRequestBuilders.approveLoan(10000.0, "11 July 2022")); + verifyLoanStatus(loanId, LoanStatus.APPROVED); + auditFieldsResponse = getAuditFields(loanId); - OffsetDateTime createdDate2 = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), - DateTimeFormatter.ISO_OFFSET_DATE_TIME); - lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE), - DateTimeFormatter.ISO_OFFSET_DATE_TIME); + OffsetDateTime createdDate2 = auditFieldsResponse.getCreatedDate(); + lastModifiedDate = auditFieldsResponse.getLastModifiedDate(); LOG.info("-------------------------Check Audit dates---------------------------"); - assertEquals(1, auditFieldsResponse.get(CREATED_BY)); + assertEquals(1L, auditFieldsResponse.getCreatedBy()); assertTrue(DateUtils.isEqual(now, createdDate2, ChronoUnit.MINUTES)); assertTrue(DateUtils.isEqual(createdDate, createdDate2)); - assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY)); + assertEquals(userId, auditFieldsResponse.getLastModifiedBy()); assertTrue(DateUtils.isEqual(now2, lastModifiedDate, ChronoUnit.MINUTES)); } + + private LoanAuditFieldsData getAuditFields(Long loanId) { + return ok(() -> fineractClient().defaultApi().getLoanAuditFields(loanId)); + } + + private Long applyForLoanApplication(final Long clientId, final Long loanProductId, Double principal, final String submittedOnDate, + final String disbursementDate) { + final PostLoansRequest application = LoanRequestBuilders.applyLoan(clientId, loanProductId, submittedOnDate, principal, 6)// + .expectedDisbursementDate(disbursementDate)// + .interestRatePerPeriod(BigDecimal.valueOf(2))// + .interestType(LoanTestData.InterestType.FLAT); + return applyForLoan(application); + } + + private Long createLoanProduct(final String inMultiplesOf, final String digitsAfterDecimal, final String repaymentStrategy, + final String accountingRule) { + final Account assetAccount = accountHelper.createAssetAccount(); + final Account incomeAccount = accountHelper.createIncomeAccount(); + final Account expenseAccount = accountHelper.createExpenseAccount(); + final Account overpaymentAccount = accountHelper.createLiabilityAccount(); + + return createLoanProduct(new LoanProductTestBuilder() // + .withPrincipal("10000000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withRepaymentStrategy(repaymentStrategy) // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails(digitsAfterDecimal, inMultiplesOf) + .withAccounting(accountingRule, new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }) + .buildRequest(null)); + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java index ba8fb09252d..f254f1f5650 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java @@ -21,77 +21,52 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -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.util.HashMap; import java.util.UUID; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; -import org.apache.fineract.client.util.CallFailedRuntimeException; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.Utils; -import org.apache.fineract.integrationtests.common.loans.LoanProductHelper; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class LoanProductExternalIdTest { - - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - private LoanProductHelper loanProductHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); - this.loanProductHelper = new LoanProductHelper(); - } +public class LoanProductExternalIdTest extends FeignLoanTestBase { @Test public void testLoanProductWithExternalId() { String externalId = UUID.randomUUID().toString(); - HashMap request = new LoanProductTestBuilder().withExternalId(externalId).build(null, null); - Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(request)); + Long loanProductId = createLoanProduct(new LoanProductTestBuilder().withExternalId(externalId).buildRequest(null, null)); assertNotNull(loanProductId); - GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductByExternalId(externalId); + GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanHelper.retrieveLoanProductByExternalId(externalId); assertNotNull(getLoanProductsProductIdResponse.getId()); - assertEquals(loanProductId, getLoanProductsProductIdResponse.getId().intValue()); + assertEquals(loanProductId, getLoanProductsProductIdResponse.getId()); + assertEquals(externalId, getLoanProductsProductIdResponse.getExternalId()); final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest() .shortName(Utils.uniqueRandomStringGenerator("", 3)); - PutLoanProductsProductIdResponse putLoanProductsProductIdResponse = loanProductHelper.updateLoanProductByExternalId(externalId, + PutLoanProductsProductIdResponse putLoanProductsProductIdResponse = loanHelper.updateLoanProductByExternalId(externalId, requestModifyLoan); assertNotNull(putLoanProductsProductIdResponse.getResourceId()); - assertEquals(loanProductId, putLoanProductsProductIdResponse.getResourceId().intValue()); + assertEquals(loanProductId, putLoanProductsProductIdResponse.getResourceId()); } @Test public void testLoanProductWithInvalidExternalId() { String externalId = UUID.randomUUID().toString(); - HashMap request = new LoanProductTestBuilder().withExternalId(externalId).build(null, null); - Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(request)); + Long loanProductId = createLoanProduct(new LoanProductTestBuilder().withExternalId(externalId).buildRequest(null, null)); assertNotNull(loanProductId); - GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductByExternalId(externalId); + GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanHelper.retrieveLoanProductByExternalId(externalId); assertNotNull(getLoanProductsProductIdResponse.getId()); - assertEquals(loanProductId, getLoanProductsProductIdResponse.getId().intValue()); + assertEquals(loanProductId, getLoanProductsProductIdResponse.getId()); CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, - () -> loanProductHelper.retrieveLoanProductByExternalId(externalId.substring(2))); - assertEquals(404, exception.getResponse().code()); - assertTrue(exception.getMessage().contains("error.msg.loanproduct.id.invalid")); + () -> loanHelper.retrieveLoanProductByExternalId(externalId.substring(2))); + assertEquals(404, exception.getStatus()); + assertErrorGlobalisationCode(exception, "error.msg.loanproduct.id.invalid"); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java index 19c55e2f507..027c4735083 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductRepaymentStartDateConfigurationTest.java @@ -21,80 +21,54 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -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.time.LocalDate; -import java.util.HashMap; import java.util.UUID; -import org.apache.fineract.client.models.DelinquencyBucketResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; -import org.apache.fineract.client.models.PutGlobalConfigurationsRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; -import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; -import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; -import org.apache.fineract.integrationtests.common.BusinessDateHelper; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignDelinquencyHelper; +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.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; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class LoanProductRepaymentStartDateConfigurationTest { - - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private LoanTransactionHelper loanTransactionHelper; - private ClientHelper clientHelper; - private GlobalConfigurationHelper globalConfigurationHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); - this.globalConfigurationHelper = new GlobalConfigurationHelper(); - } +public class LoanProductRepaymentStartDateConfigurationTest extends FeignLoanTestBase { + + private static final Integer REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE = 1; + private static final Integer REPAYMENT_START_DATE_TYPE_SUBMITTED_ON_DATE = 2; + + private final FeignDelinquencyHelper delinquencyHelper = new FeignDelinquencyHelper(FineractFeignClientHelper.getFineractFeignClient()); @Test public void loanProductWithRepaymentStartDateTypeConfigurationCreateAndModifyTest() { // create product with repayment start date configuration, get , modify // Delinquency Bucket - final Long delinquencyBucketId = DelinquencyBucketsHelper.createDefaultBucket(); - final DelinquencyBucketResponse delinquencyBucket = DelinquencyBucketsHelper.getBucket(delinquencyBucketId); - - final Integer repaymentStartDateType = 2; + final Long delinquencyBucketId = delinquencyHelper.createDefaultBucket(); // create loan product with repayment start date configuration - Integer loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(loanTransactionHelper, delinquencyBucketId, - repaymentStartDateType); + Long loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(delinquencyBucketId, + REPAYMENT_START_DATE_TYPE_SUBMITTED_ON_DATE); - GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId); + GetLoanProductsProductIdResponse getLoanProductsProductResponse = retrieveLoanProduct(loanProductId); assertNotNull(getLoanProductsProductResponse); - assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals(REPAYMENT_START_DATE_TYPE_SUBMITTED_ON_DATE, + getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); assertEquals("repaymentStartDateType.submittedOnDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); // modify loan product repayment start date configuration to disbursement date - PutLoanProductsProductIdResponse loanProductModifyResponse = updateLoanProduct(loanTransactionHelper, - getLoanProductsProductResponse.getId()); + PutLoanProductsProductIdResponse loanProductModifyResponse = updateRepaymentStartDateType(getLoanProductsProductResponse.getId()); assertNotNull(loanProductModifyResponse); - getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId); + getLoanProductsProductResponse = retrieveLoanProduct(loanProductId); assertNotNull(getLoanProductsProductResponse); - assertEquals(1, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals(REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE, + getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); } @@ -104,18 +78,15 @@ public void loanProductWithNoRepaymentStartDateTypeConfigurationDefaultsToDisbur // create loan product with no configuration for repayment start date and verify that it is disbursement date by // default // Delinquency Bucket - final Long delinquencyBucketId = DelinquencyBucketsHelper.createDefaultBucket(); - final DelinquencyBucketResponse delinquencyBucket = DelinquencyBucketsHelper.getBucket(delinquencyBucketId); - - final Integer repaymentStartDateType = null; + final Long delinquencyBucketId = delinquencyHelper.createDefaultBucket(); // create loan product with repayment start date configuration - Integer loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(loanTransactionHelper, delinquencyBucketId, - repaymentStartDateType); + Long loanProductId = createLoanProductWithRepaymentStartDateTypeConfiguration(delinquencyBucketId, null); - GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId); + GetLoanProductsProductIdResponse getLoanProductsProductResponse = retrieveLoanProduct(loanProductId); assertNotNull(getLoanProductsProductResponse); - assertEquals(1, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals(REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE, + getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); } @@ -123,39 +94,30 @@ public void loanProductWithNoRepaymentStartDateTypeConfigurationDefaultsToDisbur public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateScheduleTest() { // create loan account with product with repayment start date type configuration as submitted on date, verify // repayment schedule is according to submitted on date, before and after disbursements - try { - - // Set business date - LocalDate businessDate = LocalDate.of(2023, 3, 3); - - globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE, - new PutGlobalConfigurationsRequest().enabled(true)); - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, businessDate); + runAt("2023-03-03", () -> { // Loan ExternalId String loanExternalIdStr = UUID.randomUUID().toString(); - final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); - - // set repayment start date type as submittedOn date - final Integer repaymentStartDateType = 2; + final Long clientId = createClient(); // Loan Product creation with repayment start date type configuration final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements( - loanTransactionHelper, repaymentStartDateType); + REPAYMENT_START_DATE_TYPE_SUBMITTED_ON_DATE); assertNotNull(getLoanProductsProductResponse); - assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals(REPAYMENT_START_DATE_TYPE_SUBMITTED_ON_DATE, + getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); assertEquals("repaymentStartDateType.submittedOnDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); // create loan account with submitted date as business date (03 March 2023) and expected disbursement date // as future date (07 March 2023) - final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(), + final Long loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(), loanExternalIdStr); // Retrieve Loan with loanId - GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); assertNotNull(loanDetails); @@ -163,7 +125,7 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateSch assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size()); @@ -171,41 +133,27 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateSch assertEquals(1000.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalExpected())); // first period [2023-03-03 to 2023-04-03] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 1, 1, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3), 333.33); // second period [2023-04-03 to 2023-05-03] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 2, 2, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3), 333.33); // third period [2023-05-03 to 2023-06-03] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(333.34, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 3, LocalDate.of(2023, 5, 3), LocalDate.of(2023, 6, 3), 333.34); // first disbursement on a future date (7 March 2023) - LocalDate disbursementDate = LocalDate.of(2023, 3, 7); + updateBusinessDate("07 March 2023"); - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, disbursementDate); + disburseLoan(loanId, LoanRequestBuilders.disburseLoan(500.0, "07 March 2023")); - loanTransactionHelper.disburseLoanWithTransactionAmount("07 March 2023", loanId, "500"); - - loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + loanDetails = getLoanDetails(loanId); // verify loan schedule is according to submitted on date after first disbursement assertNotNull(loanDetails); assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size()); // verify amounts @@ -213,42 +161,28 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateSch assertEquals(500.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed())); // first period [2023-03-03 to 2023-04-03] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); - assertEquals(166.67, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 1, 1, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3), 166.67); // second period [2023-04-03 to 2023-05-03] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); - assertEquals(166.67, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 2, 2, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3), 166.67); // third period [2023-05-03 to 2023-06-03] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(166.66, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 3, LocalDate.of(2023, 5, 3), LocalDate.of(2023, 6, 3), 166.66); // second disbursement next month (7 April 2023) - disbursementDate = LocalDate.of(2023, 4, 7); - - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, disbursementDate); + updateBusinessDate("07 April 2023"); - loanTransactionHelper.disburseLoanWithTransactionAmount("07 April 2023", loanId, "500"); + disburseLoan(loanId, LoanRequestBuilders.disburseLoan(500.0, "07 April 2023")); - loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + loanDetails = getLoanDetails(loanId); // verify loan schedule is according to submitted on date after second disbursement assertNotNull(loanDetails); assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(5, loanDetails.getRepaymentSchedule().getPeriods().size()); // verify amounts @@ -256,30 +190,14 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsSubmittedOnDateSch assertEquals(1000.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed())); // first period [2023-03-03 to 2023-04-03] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 1, 1, LocalDate.of(2023, 3, 3), LocalDate.of(2023, 4, 3), 333.33); // second period [2023-04-03 to 2023-05-03] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 2, LocalDate.of(2023, 4, 3), LocalDate.of(2023, 5, 3), 333.33); // third period [2023-05-03 to 2023-06-03] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 3), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); - assertEquals(333.34, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod())); - - } finally { - globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE, - new PutGlobalConfigurationsRequest().enabled(false)); - } + verifyPeriod(loanDetails, 4, 3, LocalDate.of(2023, 5, 3), LocalDate.of(2023, 6, 3), 333.34); + }); } @@ -288,39 +206,30 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc // create loan account with loan product with repayment start date type configuration as disbursement date , // verify repayment schedule is as per disbursement date before and after disbursements - try { - - // Set business date - LocalDate businessDate = LocalDate.of(2023, 3, 3); - - globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE, - new PutGlobalConfigurationsRequest().enabled(true)); - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, businessDate); + runAt("2023-03-03", () -> { // Loan ExternalId String loanExternalIdStr = UUID.randomUUID().toString(); - final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); - - // set repayment start date type as default, disbursement date - final Integer repaymentStartDateType = 1; + final Long clientId = createClient(); // Loan Product creation with repayment date type configuration final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements( - loanTransactionHelper, repaymentStartDateType); + REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE); assertNotNull(getLoanProductsProductResponse); - assertEquals(repaymentStartDateType, getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); + assertEquals(REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE, + getLoanProductsProductResponse.getRepaymentStartDateType().getId().intValue()); assertEquals("repaymentStartDateType.disbursementDate", getLoanProductsProductResponse.getRepaymentStartDateType().getCode()); // create loan account with submitted date as business date (03 March 2023) and expected disbursement date // (07 March 2023) - final Integer loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(), + final Long loanId = createLoanAccountMultipleRepaymentsDisbursement(clientId, getLoanProductsProductResponse.getId(), loanExternalIdStr); // Retrieve Loan with loanId - GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + GetLoansLoanIdResponse loanDetails = getLoanDetails(loanId); assertNotNull(loanDetails); @@ -329,7 +238,7 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size()); @@ -337,42 +246,28 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc assertEquals(1000.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalExpected())); // first period [2023-03-07 to 2023-04-07] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 1, 1, LocalDate.of(2023, 3, 7), LocalDate.of(2023, 4, 7), 333.33); // second period [2023-04-07 to 2023-05-07] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 2, 2, LocalDate.of(2023, 4, 7), LocalDate.of(2023, 5, 7), 333.33); // third period [2023-05-07 to 2023-06-07] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(333.34, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 3, LocalDate.of(2023, 5, 7), LocalDate.of(2023, 6, 7), 333.34); // first disbursement (7 March 2023) - LocalDate disbursementDate = LocalDate.of(2023, 3, 7); - - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, disbursementDate); + updateBusinessDate("07 March 2023"); - loanTransactionHelper.disburseLoanWithTransactionAmount("07 March 2023", loanId, "500"); + disburseLoan(loanId, LoanRequestBuilders.disburseLoan(500.0, "07 March 2023")); - loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + loanDetails = getLoanDetails(loanId); // verify loan schedule is according to disbursement date assertNotNull(loanDetails); assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(4, loanDetails.getRepaymentSchedule().getPeriods().size()); // verify amounts @@ -380,35 +275,21 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc assertEquals(500.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed())); // first period [2023-03-07 to 2023-04-07] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(1).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(1).getDueDate()); - assertEquals(166.67, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(1).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 1, 1, LocalDate.of(2023, 3, 7), LocalDate.of(2023, 4, 7), 166.67); // second period [2023-04-07 to 2023-05-07] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); - assertEquals(166.67, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 2, 2, LocalDate.of(2023, 4, 7), LocalDate.of(2023, 5, 7), 166.67); // third period [2023-05-07 to 2023-06-07] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(166.66, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 3, LocalDate.of(2023, 5, 7), LocalDate.of(2023, 6, 7), 166.66); // second disbursement next month (7 April 2023) - disbursementDate = LocalDate.of(2023, 4, 7); + updateBusinessDate("07 April 2023"); - BusinessDateHelper.updateBusinessDate(BusinessDateType.BUSINESS_DATE, disbursementDate); + disburseLoan(loanId, LoanRequestBuilders.disburseLoan(500.0, "07 April 2023")); - loanTransactionHelper.disburseLoanWithTransactionAmount("07 April 2023", loanId, "500"); - - loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue()); + loanDetails = getLoanDetails(loanId); // verify loan schedule is according to disbursement after second disbursement @@ -416,7 +297,7 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc assertNotNull(loanDetails.getRepaymentSchedule()); // loan term - assertEquals(92, loanDetails.getRepaymentSchedule().getLoanTermInDays()); + assertEquals(92L, loanDetails.getRepaymentSchedule().getLoanTermInDays()); assertEquals(5, loanDetails.getRepaymentSchedule().getPeriods().size()); // verify amounts @@ -424,75 +305,57 @@ public void loanAccountWithLoanProductRepaymentStartDateTypeAsDisbursementDateSc assertEquals(1000.0, Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getTotalPrincipalDisbursed())); // first period [2023-03-07 to 2023-04-07] - assertEquals(1, loanDetails.getRepaymentSchedule().getPeriods().get(2).getPeriod()); - assertEquals(LocalDate.of(2023, 3, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getFromDate()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(2).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(2).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 2, 1, LocalDate.of(2023, 3, 7), LocalDate.of(2023, 4, 7), 333.33); // second period [2023-04-07 to 2023-05-07] - assertEquals(2, loanDetails.getRepaymentSchedule().getPeriods().get(3).getPeriod()); - assertEquals(LocalDate.of(2023, 4, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getFromDate()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(3).getDueDate()); - assertEquals(333.33, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(3).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 3, 2, LocalDate.of(2023, 4, 7), LocalDate.of(2023, 5, 7), 333.33); // third period [2023-05-07 to 2023-06-07] - assertEquals(3, loanDetails.getRepaymentSchedule().getPeriods().get(4).getPeriod()); - assertEquals(LocalDate.of(2023, 5, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getFromDate()); - assertEquals(LocalDate.of(2023, 6, 7), loanDetails.getRepaymentSchedule().getPeriods().get(4).getDueDate()); - assertEquals(333.34, - Utils.getDoubleValue(loanDetails.getRepaymentSchedule().getPeriods().get(4).getTotalInstallmentAmountForPeriod())); + verifyPeriod(loanDetails, 4, 3, LocalDate.of(2023, 5, 7), LocalDate.of(2023, 6, 7), 333.34); + }); - } finally { - globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE, - new PutGlobalConfigurationsRequest().enabled(false)); - } + } + private void verifyPeriod(GetLoansLoanIdResponse loanDetails, int index, int expectedPeriod, LocalDate expectedFromDate, + LocalDate expectedDueDate, double expectedInstallmentAmount) { + var period = loanDetails.getRepaymentSchedule().getPeriods().get(index); + assertEquals(expectedPeriod, period.getPeriod()); + assertEquals(expectedFromDate, period.getFromDate()); + assertEquals(expectedDueDate, period.getDueDate()); + assertEquals(expectedInstallmentAmount, Utils.getDoubleValue(period.getTotalInstallmentAmountForPeriod())); } - private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) { + private PutLoanProductsProductIdResponse updateRepaymentStartDateType(Long id) { // repayment start date configuration - final Integer repaymentStartDateType = 1; final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest() - .repaymentStartDateType(repaymentStartDateType).locale("en"); - return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan); + .repaymentStartDateType(REPAYMENT_START_DATE_TYPE_DISBURSEMENT_DATE).locale("en"); + return updateLoanProduct(id, requestModifyLoan); } - private Integer createLoanProductWithRepaymentStartDateTypeConfiguration(final LoanTransactionHelper loanTransactionHelper, - final Long delinquencyBucketId, final Integer repaymentStartDateType) { - final HashMap loanProductMap = new LoanProductTestBuilder().withRepaymentStartDateType(repaymentStartDateType) - .build(null, delinquencyBucketId); - final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap)); - return loanProductId; - + private Long createLoanProductWithRepaymentStartDateTypeConfiguration(final Long delinquencyBucketId, + final Integer repaymentStartDateType) { + return createLoanProduct( + new LoanProductTestBuilder().withRepaymentStartDateType(repaymentStartDateType).buildRequest(null, delinquencyBucketId)); } - private Integer createLoanAccountMultipleRepaymentsDisbursement(final Integer clientID, final Long loanProductID, - final String externalId) { - - String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("3") - .withLoanTermFrequencyAsMonths().withNumberOfRepayments("3").withRepaymentEveryAfter("1") - .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsDecliningBalance() - .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() - .withExpectedDisbursementDate("07 March 2023").withSubmittedOnDate("03 March 2023").withLoanType("individual") - .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); - - final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON); - loanTransactionHelper.approveLoan("03 March 2023", "1000", loanId, null); + private Long createLoanAccountMultipleRepaymentsDisbursement(final Long clientId, final Long loanProductId, final String externalId) { + final Long loanId = applyForLoan(LoanRequestBuilders.applyLoan(clientId, loanProductId, "03 March 2023", 1000.0, 3)// + .expectedDisbursementDate("07 March 2023")// + .amortizationType(LoanTestData.AmortizationType.EQUAL_PRINCIPAL)// + .externalId(externalId)); + approveLoan(loanId, LoanRequestBuilders.approveLoan(1000.0, "03 March 2023")); return loanId; } private GetLoanProductsProductIdResponse createLoanProductWithRepaymentStartDateTypeConfigurationAndMultipleDisbursements( - LoanTransactionHelper loanTransactionHelper, final Integer repaymentStartDateType) { - final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + final Integer repaymentStartDateType) { + final Long loanProductId = createLoanProduct(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) - .withRepaymentStartDateType(repaymentStartDateType).build(null); - final Integer loanProductId = loanTransactionHelper.getLoanProductId(loanProductJSON); - return loanTransactionHelper.getLoanProduct(loanProductId); + .withRepaymentStartDateType(repaymentStartDateType).buildRequest()); + return retrieveLoanProduct(loanProductId); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductUpdateApiTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductUpdateApiTest.java index 7127f349f88..09d69616485 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductUpdateApiTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductUpdateApiTest.java @@ -18,43 +18,22 @@ */ package org.apache.fineract.integrationtests; -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.util.Arrays; -import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; 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.PutLoanProductsProductIdRequest; -import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; -import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -public class LoanProductUpdateApiTest { +public class LoanProductUpdateApiTest extends FeignLoanTestBase { - private static LoanTransactionHelper LOAN_TRANSACTION_HELPER; - private static ResponseSpecification RESPONSE_SPEC; - private static RequestSpecification REQUEST_SPEC; - - @BeforeAll - public static void setupTests() { - Utils.initializeRESTAssured(); - REQUEST_SPEC = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - REQUEST_SPEC.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - RESPONSE_SPEC = new ResponseSpecBuilder().expectStatusCode(200).build(); - LOAN_TRANSACTION_HELPER = new LoanTransactionHelper(REQUEST_SPEC, RESPONSE_SPEC); - } + private static final String DEFAULT_TRANSACTION_TYPE = "DEFAULT"; + private static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy"; @Test public void loanProductModifyForAdvancedPaymentAllocationRuleTest() { @@ -63,15 +42,15 @@ public void loanProductModifyForAdvancedPaymentAllocationRuleTest() { String futureInstallmentAllocationRule = "NEXT_INSTALLMENT"; AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation(futureInstallmentAllocationRule); - Integer loanProductId = createLoanProduct(defaultAllocation); + Long loanProductId = createAdvancedPaymentAllocationProduct(defaultAllocation); Assertions.assertNotNull(loanProductId); // verify allocation rule - GetLoanProductsProductIdResponse loanProduct = LOAN_TRANSACTION_HELPER.getLoanProduct(loanProductId); + GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); Optional defaultAllocationAfterCreate = loanProduct.getPaymentAllocation().stream() - .filter(advancedPaymentData -> "DEFAULT".equals(advancedPaymentData.getTransactionType())).findFirst(); + .filter(advancedPaymentData -> DEFAULT_TRANSACTION_TYPE.equals(advancedPaymentData.getTransactionType())).findFirst(); Assertions.assertTrue(defaultAllocationAfterCreate.isPresent()); Assertions.assertEquals(futureInstallmentAllocationRule, defaultAllocationAfterCreate.get().getFutureInstallmentAllocationRule()); @@ -79,15 +58,15 @@ public void loanProductModifyForAdvancedPaymentAllocationRuleTest() { futureInstallmentAllocationRule = "LAST_INSTALLMENT"; defaultAllocation = createDefaultPaymentAllocation(futureInstallmentAllocationRule); - loanProductId = updateLoanProduct(loanProductId, defaultAllocation); + loanProductId = updatePaymentAllocation(loanProductId, defaultAllocation); Assertions.assertNotNull(loanProductId); - loanProduct = LOAN_TRANSACTION_HELPER.getLoanProduct(loanProductId); + loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); // verify allocation rule Optional defaultAllocationAfterUpdate = loanProduct.getPaymentAllocation().stream() - .filter(advancedPaymentData -> "DEFAULT".equals(advancedPaymentData.getTransactionType())).findFirst(); + .filter(advancedPaymentData -> DEFAULT_TRANSACTION_TYPE.equals(advancedPaymentData.getTransactionType())).findFirst(); Assertions.assertTrue(defaultAllocationAfterUpdate.isPresent()); Assertions.assertEquals(futureInstallmentAllocationRule, defaultAllocationAfterUpdate.get().getFutureInstallmentAllocationRule()); @@ -100,15 +79,15 @@ public void loanProductWithInterestCalculationTypeDailyModifyForAdvancedPaymentA String futureInstallmentAllocationRule = "NEXT_INSTALLMENT"; AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation(futureInstallmentAllocationRule); - Integer loanProductId = createLoanProductWithInterestCalculationPeriodTypeDaily(defaultAllocation); + Long loanProductId = createAdvancedPaymentAllocationProductWithInterestCalculationPeriodTypeDaily(defaultAllocation); Assertions.assertNotNull(loanProductId); // verify allocation rule - GetLoanProductsProductIdResponse loanProduct = LOAN_TRANSACTION_HELPER.getLoanProduct(loanProductId); + GetLoanProductsProductIdResponse loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); Optional defaultAllocationAfterCreate = loanProduct.getPaymentAllocation().stream() - .filter(advancedPaymentData -> "DEFAULT".equals(advancedPaymentData.getTransactionType())).findFirst(); + .filter(advancedPaymentData -> DEFAULT_TRANSACTION_TYPE.equals(advancedPaymentData.getTransactionType())).findFirst(); Assertions.assertTrue(defaultAllocationAfterCreate.isPresent()); Assertions.assertEquals(futureInstallmentAllocationRule, defaultAllocationAfterCreate.get().getFutureInstallmentAllocationRule()); @@ -116,70 +95,41 @@ public void loanProductWithInterestCalculationTypeDailyModifyForAdvancedPaymentA futureInstallmentAllocationRule = "LAST_INSTALLMENT"; defaultAllocation = createDefaultPaymentAllocation(futureInstallmentAllocationRule); - loanProductId = updateLoanProduct(loanProductId, defaultAllocation); + loanProductId = updatePaymentAllocation(loanProductId, defaultAllocation); Assertions.assertNotNull(loanProductId); - loanProduct = LOAN_TRANSACTION_HELPER.getLoanProduct(loanProductId); + loanProduct = retrieveLoanProduct(loanProductId); Assertions.assertNotNull(loanProduct.getPaymentAllocation()); // verify allocation rule Optional defaultAllocationAfterUpdate = loanProduct.getPaymentAllocation().stream() - .filter(advancedPaymentData -> "DEFAULT".equals(advancedPaymentData.getTransactionType())).findFirst(); + .filter(advancedPaymentData -> DEFAULT_TRANSACTION_TYPE.equals(advancedPaymentData.getTransactionType())).findFirst(); Assertions.assertTrue(defaultAllocationAfterUpdate.isPresent()); Assertions.assertEquals(futureInstallmentAllocationRule, defaultAllocationAfterUpdate.get().getFutureInstallmentAllocationRule()); } - private Integer updateLoanProduct(Integer loanProductId, AdvancedPaymentData... advancedPaymentData) { + private Long updatePaymentAllocation(Long loanProductId, AdvancedPaymentData... advancedPaymentData) { final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest() - .transactionProcessingStrategyCode("advanced-payment-allocation-strategy") + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY) .paymentAllocation(Arrays.stream(advancedPaymentData).toList()).locale("en"); - return LOAN_TRANSACTION_HELPER.updateLoanProduct(loanProductId.longValue(), requestModifyLoan).getResourceId().intValue(); + return updateLoanProduct(loanProductId, requestModifyLoan).getResourceId(); } - private Integer createLoanProduct(AdvancedPaymentData... advancedPaymentData) { - String loanProductCreateJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") + private Long createAdvancedPaymentAllocationProduct(AdvancedPaymentData... advancedPaymentData) { + return createLoanProduct(new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .addAdvancedPaymentAllocation(advancedPaymentData).withLoanScheduleType(LoanScheduleType.PROGRESSIVE) - .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).build(); - return LOAN_TRANSACTION_HELPER.getLoanProductId(loanProductCreateJSON); - + .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).buildRequest()); } - private Integer createLoanProductWithInterestCalculationPeriodTypeDaily(AdvancedPaymentData... advancedPaymentData) { - String loanProductCreateJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") + private Long createAdvancedPaymentAllocationProductWithInterestCalculationPeriodTypeDaily(AdvancedPaymentData... advancedPaymentData) { + return createLoanProduct(new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestTypeAsDecliningBalance() .withInterestCalculationPeriodTypeAsDays().withAllowPartialPeriodInterestCalculation(false) .addAdvancedPaymentAllocation(advancedPaymentData).withLoanScheduleType(LoanScheduleType.PROGRESSIVE) - .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).build(); - return LOAN_TRANSACTION_HELPER.getLoanProductId(loanProductCreateJSON); - - } - - private AdvancedPaymentData createDefaultPaymentAllocation(String futureInstallmentAllocationRule) { - AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData(); - advancedPaymentData.setTransactionType("DEFAULT"); - advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule); - - List paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY, - PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST, - PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL, - PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE, - PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST); - - advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders); - return advancedPaymentData; - } - - private List getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) { - AtomicInteger integer = new AtomicInteger(1); - return Arrays.stream(paymentAllocationTypes).map(pat -> { - PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder(); - paymentAllocationOrder.setPaymentAllocationRule(pat.name()); - paymentAllocationOrder.setOrder(integer.getAndIncrement()); - return paymentAllocationOrder; - }).toList(); + .withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL).buildRequest()); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithRepaymentDueEventConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithRepaymentDueEventConfigurationTest.java index 4832f348cda..619f3359a4f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithRepaymentDueEventConfigurationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithRepaymentDueEventConfigurationTest.java @@ -21,113 +21,63 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -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.util.HashMap; -import java.util.UUID; -import org.apache.fineract.client.models.DelinquencyBucketResponse; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignDelinquencyHelper; +import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class LoanProductWithRepaymentDueEventConfigurationTest { +public class LoanProductWithRepaymentDueEventConfigurationTest extends FeignLoanTestBase { - private ResponseSpecification responseSpec; - private RequestSpecification requestSpec; - private ClientHelper clientHelper; - private LoanTransactionHelper loanTransactionHelper; + private static final Integer DUE_DAYS_FOR_REPAYMENT_EVENT = 1; + private static final Integer OVER_DUE_DAYS_FOR_REPAYMENT_EVENT = 2; - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - } + private final FeignDelinquencyHelper delinquencyHelper = new FeignDelinquencyHelper(FineractFeignClientHelper.getFineractFeignClient()); @Test public void loanProductCreationWithDueDaysConfigurationForRepaymentEventTest() { - // Loan ExternalId - String loanExternalIdStr = UUID.randomUUID().toString(); - - // Delinquency Bucket - final Long delinquencyBucketId = DelinquencyBucketsHelper.createDefaultBucket(); - final DelinquencyBucketResponse delinquencyBucket = DelinquencyBucketsHelper.getBucket(delinquencyBucketId); - - // event days configuration - Integer dueDaysForRepaymentEvent = 1; - Integer overDueDaysForRepaymentEvent = 2; - - // Client and Loan account creation + final Long delinquencyBucketId = delinquencyHelper.createDefaultBucket(); - final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); - Integer loanProductId = createLoanProductWithDueDaysForRepaymentEvent(loanTransactionHelper, delinquencyBucketId, - dueDaysForRepaymentEvent, overDueDaysForRepaymentEvent); - final GetLoanProductsProductIdResponse getLoanProductsProductResponse = loanTransactionHelper.getLoanProduct(loanProductId); + Long loanProductId = createLoanProductWithDueDaysForRepaymentEvent(delinquencyBucketId, DUE_DAYS_FOR_REPAYMENT_EVENT, + OVER_DUE_DAYS_FOR_REPAYMENT_EVENT); + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = retrieveLoanProduct(loanProductId); assertNotNull(getLoanProductsProductResponse); assertNotNull(getLoanProductsProductResponse.getDueDaysForRepaymentEvent()); assertNotNull(getLoanProductsProductResponse.getOverDueDaysForRepaymentEvent()); - assertEquals(getLoanProductsProductResponse.getDueDaysForRepaymentEvent(), dueDaysForRepaymentEvent); - assertEquals(getLoanProductsProductResponse.getOverDueDaysForRepaymentEvent(), overDueDaysForRepaymentEvent); + assertEquals(DUE_DAYS_FOR_REPAYMENT_EVENT, getLoanProductsProductResponse.getDueDaysForRepaymentEvent()); + assertEquals(OVER_DUE_DAYS_FOR_REPAYMENT_EVENT, getLoanProductsProductResponse.getOverDueDaysForRepaymentEvent()); } @Test public void loanProductUpdateWithDueDaysConfigurationForRepaymentEventTest() { - // Loan ExternalId - String loanExternalIdStr = UUID.randomUUID().toString(); + final Long delinquencyBucketId = delinquencyHelper.createDefaultBucket(); - // Delinquency Bucket - final Long delinquencyBucketId = DelinquencyBucketsHelper.createDefaultBucket(); - final DelinquencyBucketResponse delinquencyBucket = DelinquencyBucketsHelper.getBucket(delinquencyBucketId); - - // Client and Loan account creation - - final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); - final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProduct(loanTransactionHelper, - delinquencyBucketId); + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createDefaultLoanProduct(delinquencyBucketId); assertNotNull(getLoanProductsProductResponse); - // Modify Loan Product - PutLoanProductsProductIdResponse loanProductModifyResponse = updateLoanProduct(loanTransactionHelper, - getLoanProductsProductResponse.getId()); + PutLoanProductsProductIdResponse loanProductModifyResponse = updateDueDaysForRepaymentEvent(getLoanProductsProductResponse.getId()); assertNotNull(loanProductModifyResponse); - } - private PutLoanProductsProductIdResponse updateLoanProduct(LoanTransactionHelper loanTransactionHelper, Long id) { - // event days configuration - Integer dueDaysForRepaymentEvent = 1; - Integer overDueDaysForRepaymentEvent = 2; + private PutLoanProductsProductIdResponse updateDueDaysForRepaymentEvent(Long id) { final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest() - .dueDaysForRepaymentEvent(dueDaysForRepaymentEvent).overDueDaysForRepaymentEvent(overDueDaysForRepaymentEvent).locale("en"); - return loanTransactionHelper.updateLoanProduct(id, requestModifyLoan); + .dueDaysForRepaymentEvent(DUE_DAYS_FOR_REPAYMENT_EVENT).overDueDaysForRepaymentEvent(OVER_DUE_DAYS_FOR_REPAYMENT_EVENT) + .locale("en"); + return updateLoanProduct(id, requestModifyLoan); } - private GetLoanProductsProductIdResponse createLoanProduct(final LoanTransactionHelper loanTransactionHelper, - final Long delinquencyBucketId) { - final HashMap loanProductMap = new LoanProductTestBuilder().build(null, delinquencyBucketId); - final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap)); - return loanTransactionHelper.getLoanProduct(loanProductId); + private GetLoanProductsProductIdResponse createDefaultLoanProduct(final Long delinquencyBucketId) { + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder().buildRequest(null, delinquencyBucketId)); + return retrieveLoanProduct(loanProductId); } - private Integer createLoanProductWithDueDaysForRepaymentEvent(final LoanTransactionHelper loanTransactionHelper, - final Long delinquencyBucketId, Integer dueDaysForRepaymentEvent, Integer overDueDaysForRepaymentEvent) { - final HashMap loanProductMap = new LoanProductTestBuilder().withDueDaysForRepaymentEvent(dueDaysForRepaymentEvent) - .withOverDueDaysForRepaymentEvent(overDueDaysForRepaymentEvent).build(null, delinquencyBucketId); - final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap)); - return loanProductId; + private Long createLoanProductWithDueDaysForRepaymentEvent(final Long delinquencyBucketId, Integer dueDaysForRepaymentEvent, + Integer overDueDaysForRepaymentEvent) { + return createLoanProduct(new LoanProductTestBuilder().withDueDaysForRepaymentEvent(dueDaysForRepaymentEvent) + .withOverDueDaysForRepaymentEvent(overDueDaysForRepaymentEvent).buildRequest(null, delinquencyBucketId)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanValidationIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanValidationIntegrationTest.java index dbad3e796ae..ff3b08e58c3 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanValidationIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanValidationIntegrationTest.java @@ -18,71 +18,48 @@ */ package org.apache.fineract.integrationtests; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -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.util.Collections; -import net.minidev.json.JSONArray; -import org.apache.fineract.integrationtests.common.ClientHelper; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.math.BigDecimal; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignStaffHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignUserHelper; +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.accounting.AccountHelper; -import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; -import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; -import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; -import org.apache.fineract.integrationtests.common.organisation.StaffHelper; -import org.apache.fineract.integrationtests.useradministration.users.UserHelper; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@ExtendWith(LoanTestLifecycleExtension.class) -public class LoanValidationIntegrationTest { +public class LoanValidationIntegrationTest extends FeignLoanTestBase { private static final Logger LOG = LoggerFactory.getLogger(LoanValidationIntegrationTest.class); - - private RequestSpecification requestSpec; - private ResponseSpecification responseSpec; - private LoanTransactionHelper loanTransactionHelper; - private AccountHelper accountHelper; - - @BeforeEach - public void setup() { - Utils.initializeRESTAssured(); - this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); - this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); - } + private static final String NEW_USER_PASSWORD = "A1b2c3d4e5f$"; @Test public void checkPrincipalErrors() { - final Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec); + final Long staffId = new FeignStaffHelper(FineractFeignClientHelper.getFineractFeignClient()).createStaff().getResourceId(); String username = Utils.uniqueRandomStringGenerator("user", 8); - UserHelper.createUser(this.requestSpec, this.responseSpec, 1, staffId, username, "A1b2c3d4e5f$", "resourceId"); + FeignUserHelper.createUser(1L, staffId, username, NEW_USER_PASSWORD); LOG.info("-------------------------Creating Client---------------------------"); - final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); - ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientID); + final Long clientId = createClient(); + Assertions.assertNotNull(clientHelper.getClient(clientId)); LOG.info("-------------------------Creating Loan---------------------------"); - final Account assetAccount = this.accountHelper.createAssetAccount(); - final Account incomeAccount = this.accountHelper.createIncomeAccount(); - final Account expenseAccount = this.accountHelper.createExpenseAccount(); - final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + final Account assetAccount = accountHelper.createAssetAccount(); + final Account incomeAccount = accountHelper.createIncomeAccount(); + final Account expenseAccount = accountHelper.createExpenseAccount(); + final Account overpaymentAccount = accountHelper.createLiabilityAccount(); LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder() // + final Long loanProductId = createLoanProduct(new LoanProductTestBuilder() // .withPrincipal("10000000.00") // .withNumberOfRepayments("24") // .withRepaymentAfterEvery("1") // @@ -93,43 +70,17 @@ public void checkPrincipalErrors() { .withAmortizationTypeAsEqualPrincipalPayment() // .withInterestTypeAsDecliningBalance() // .currencyDetails("0", "0") - .withAccounting("2", new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }).build(null); - final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJSON); + .withAccounting("2", new Account[] { assetAccount, incomeAccount, expenseAccount, overpaymentAccount }).buildRequest(null)); LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); - final String loanApplicationJSON = new LoanApplicationTestBuilder() // - .withPrincipal("-1") // - .withLoanTermFrequency("6") // - .withLoanTermFrequencyAsMonths() // - .withNumberOfRepayments("6") // - .withRepaymentEveryAfter("1") // - .withRepaymentFrequencyTypeAsMonths() // - .withInterestRatePerPeriod("2") // - .withAmortizationTypeAsEqualInstallments() // - .withInterestTypeAsFlatBalance() // - .withInterestCalculationPeriodTypeSameAsRepaymentPeriod() // - .withExpectedDisbursementDate("12 July 2022") // - .withSubmittedOnDate("10 July 2022") // - .withRepaymentStrategy(LoanApplicationTestBuilder.DEFAULT_STRATEGY) // - .withCharges(Collections.emptyList()) // - .build(clientID.toString(), loanProductID.toString(), null); - - ResponseSpecification failedResponseSpec = new ResponseSpecBuilder().expectStatusCode(400).expectBody(new BaseMatcher() { - - @Override - public boolean matches(Object body) { - DocumentContext json = JsonPath.parse(body.toString()); - LOG.error(body.toString()); - JSONArray errors = json.read("$.errors[*].developerMessage"); - LOG.info("errors: {}", errors); - return errors.size() == 1; - } - - @Override - public void describeTo(Description description) { + // a negative principal is rejected, and the rejection names exactly one offending field + CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, + () -> applyForLoan(LoanRequestBuilders + .legacyIndividualApplication(clientId, loanProductId, "-1", 6, BigDecimal.valueOf(2), "12 July 2022")// + .interestType(LoanTestData.InterestType.FLAT)// + .submittedOnDate("10 July 2022"))); - } - }).build(); - final Integer loanID = this.loanTransactionHelper.getLoanId(loanApplicationJSON, requestSpec, failedResponseSpec); + assertEquals(400, exception.getStatus()); + assertEquals(1, extractErrorCount(exception)); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanOriginatorsTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanOriginatorsTest.java index 6b555fcebee..243033b56b9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanOriginatorsTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanOriginatorsTest.java @@ -23,15 +23,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -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.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -45,6 +40,8 @@ import org.apache.fineract.client.models.PostUsersRequest; import org.apache.fineract.client.models.PostUsersResponse; import org.apache.fineract.client.models.PostWorkingCapitalLoansOriginatorData; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignRoleHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignUserHelper; import org.apache.fineract.integrationtests.client.feign.helpers.WorkingCapitalLoanOriginatorHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; @@ -54,8 +51,6 @@ import org.apache.fineract.integrationtests.common.workingcapitalloan.WorkingCapitalLoanHelper; import org.apache.fineract.integrationtests.common.workingcapitalloanproduct.WorkingCapitalLoanProductHelper; import org.apache.fineract.integrationtests.common.workingcapitalloanproduct.WorkingCapitalLoanProductTestBuilder; -import org.apache.fineract.integrationtests.useradministration.roles.RolesHelper; -import org.apache.fineract.integrationtests.useradministration.users.UserHelper; import org.junit.jupiter.api.Test; public class WorkingCapitalLoanOriginatorsTest { @@ -251,25 +246,18 @@ public void testDetachOriginatorFromWorkingCapitalLoan() { @Test public void testUserWithoutPermissionsCannotAttachOrDetachOriginator() { - Utils.initializeRESTAssured(); - RequestSpecification requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); - requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); - ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); - - final Integer roleId = RolesHelper.createRole(requestSpec, responseSpec); + final Long roleId = FeignRoleHelper.createRole(); assertNotNull(roleId); - final HashMap permissions = new HashMap<>(); - permissions.put("READ_WORKINGCAPITALLOAN", true); - RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, permissions); + FeignRoleHelper.addPermissionsToRole(roleId, Map.of("READ_WORKINGCAPITALLOAN", true)); final String username = Utils.uniqueRandomStringGenerator("WCLOriginatorUser", 4); final String password = "Str0ngP@sw0rd!"; final GetOfficesResponse headOffice = OfficeHelper.getHeadOffice(); final PostUsersRequest createUserRequest = new PostUsersRequest().username(username).firstname(Utils.randomFirstNameGenerator()) .lastname(Utils.randomLastNameGenerator()).email("wcloriginator@test.org").password(password).repeatPassword(password) - .sendPasswordToEmail(false).roles(List.of(roleId.longValue())).officeId(headOffice.getId()); - final PostUsersResponse userResponse = UserHelper.createUser(requestSpec, responseSpec, createUserRequest); + .sendPasswordToEmail(false).roles(List.of(roleId)).officeId(headOffice.getId()); + final PostUsersResponse userResponse = FeignUserHelper.createUser(createUserRequest); assertNotNull(userResponse.getResourceId()); final FineractFeignClient userClient = FineractFeignClientHelper.createNewFineractFeignClient(username, password); @@ -294,9 +282,7 @@ public void testUserWithoutPermissionsCannotAttachOrDetachOriginator() { .failVoid(() -> userClient.workingCapitalLoanOriginators().attachOriginatorToWorkingCapitalLoan(loanId, originatorId)); assertThat(attachException.getStatus()).isEqualTo(403); - final HashMap attachPermission = new HashMap<>(); - attachPermission.put("ATTACH_WORKING_CAPITAL_LOAN_ORIGINATOR", true); - RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, attachPermission); + FeignRoleHelper.addPermissionsToRole(roleId, Map.of("ATTACH_WORKING_CAPITAL_LOAN_ORIGINATOR", true)); FeignCalls.ok(() -> userClient.workingCapitalLoanOriginators().attachOriginatorToWorkingCapitalLoan(loanId, originatorId)); @@ -304,9 +290,7 @@ public void testUserWithoutPermissionsCannotAttachOrDetachOriginator() { .failVoid(() -> userClient.workingCapitalLoanOriginators().detachOriginatorFromWorkingCapitalLoan(loanId, originatorId)); assertThat(detachException.getStatus()).isEqualTo(403); - final HashMap detachPermission = new HashMap<>(); - detachPermission.put("DETACH_WORKING_CAPITAL_LOAN_ORIGINATOR", true); - RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, detachPermission); + FeignRoleHelper.addPermissionsToRole(roleId, Map.of("DETACH_WORKING_CAPITAL_LOAN_ORIGINATOR", true)); FeignCalls.ok(() -> userClient.workingCapitalLoanOriginators().detachOriginatorFromWorkingCapitalLoan(loanId, originatorId)); 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 04ac93ca582..49b9e41d17f 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 @@ -36,6 +36,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.UUID; import java.util.function.Consumer; import java.util.function.Function; @@ -678,6 +679,15 @@ protected void checkJournalEntryForExpenseAccount(Account account, String date, journalHelper.checkJournalEntryForExpenseAccount(account, date, entries); } + /** + * Codes the server puts at the top of an error body purely as an envelope; the code that names the actual failure + * is then the first entry of the nested {@code errors} array. A resource-not-found reply is one of these: every + * {@code AbstractPlatformResourceNotFoundException} reports {@code error.msg.resource.not.found} at the top and the + * entity-specific code underneath. + */ + private static final Set GENERIC_ERROR_ENVELOPE_CODES = Set.of("validation.msg.validation.errors.exist", + "validation.msg.domain.rule.violation", "error.msg.resource.not.found"); + protected static void assertErrorGlobalisationCode(CallFailedRuntimeException exception, String expectedCode) { assertEquals(expectedCode, extractErrorGlobalisationCode(exception)); } @@ -687,8 +697,7 @@ protected static String extractErrorGlobalisationCode(CallFailedRuntimeException return exception.getUserMessageGlobalisationCode(); } String topLevelCode = feignException.getUserMessageGlobalisationCode(); - if (topLevelCode != null && !topLevelCode.equals("validation.msg.validation.errors.exist") - && !topLevelCode.equals("validation.msg.domain.rule.violation")) { + if (topLevelCode != null && !GENERIC_ERROR_ENVELOPE_CODES.contains(topLevelCode)) { return topLevelCode; } try { @@ -704,6 +713,23 @@ protected static String extractErrorGlobalisationCode(CallFailedRuntimeException return topLevelCode; } + /** + * The number of entries in the failed response's {@code errors} array. A validation failure reports one entry per + * rejected field, so a test that pinned the count with a REST Assured body matcher keeps that assertion here. + */ + protected static int extractErrorCount(CallFailedRuntimeException exception) { + if (!(exception.getCause() instanceof FeignException feignException)) { + return 0; + } + try { + Map body = ObjectMapperFactory.getShared().readValue(feignException.responseBodyAsString(), + new TypeReference>() {}); + return body.get("errors") instanceof List errorList ? errorList.size() : 0; + } catch (Exception e) { + throw new IllegalStateException("Could not read the errors array from: " + feignException.responseBodyAsString(), e); + } + } + protected LoanTestData.Journal journalEntry(double amount, Account account, String type) { return "DEBIT".equals(type) ? LoanTestData.Journal.debit(account.getAccountID().longValue(), amount) : LoanTestData.Journal.credit(account.getAccountID().longValue(), 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 8f1e7b60ff0..cadd3be0d38 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 @@ -187,6 +187,15 @@ public PutLoanProductsProductIdResponse updateLoanProduct(Long productId, PutLoa return ok(() -> fineractClient.loanProducts().updateLoanProduct(productId, request)); } + public GetLoanProductsProductIdResponse retrieveLoanProductByExternalId(String externalProductId) { + return ok(() -> fineractClient.loanProducts().retrieveLoanProductDetailsByExternalId(externalProductId)); + } + + public PutLoanProductsProductIdResponse updateLoanProductByExternalId(String externalProductId, + PutLoanProductsProductIdRequest request) { + return ok(() -> fineractClient.loanProducts().updateLoanProductByExternalId(externalProductId, request)); + } + public GetLoanProductsTemplateResponse getLoanProductTemplate(Boolean isProductMixTemplate) { return ok(() -> fineractClient.loanProducts().retrieveTemplateLoanProduct(isProductMixTemplate)); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignRoleHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignRoleHelper.java new file mode 100644 index 00000000000..470033676aa --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignRoleHelper.java @@ -0,0 +1,56 @@ +/** + * 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.client.feign.helpers; + +import static org.apache.fineract.client.feign.util.FeignCalls.ok; + +import java.util.Map; +import org.apache.fineract.client.feign.FineractFeignClient; +import org.apache.fineract.client.models.PostRolesRequest; +import org.apache.fineract.client.models.PostRolesResponse; +import org.apache.fineract.client.models.PutRolesRoleIdPermissionsRequest; +import org.apache.fineract.client.models.PutRolesRoleIdPermissionsResponse; +import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; +import org.apache.fineract.integrationtests.common.Utils; + +/** Typed Feign helper for role and role-permission operations. */ +public final class FeignRoleHelper { + + private FeignRoleHelper() {} + + private static FineractFeignClient client() { + return FineractFeignClientHelper.getFineractFeignClient(); + } + + /** Creates a role with a generated name and description, and returns its id. */ + public static Long createRole() { + PostRolesResponse response = ok( + () -> client().roles().createRole(new PostRolesRequest().name(Utils.uniqueRandomStringGenerator("Role_Name_", 5)) + .description(Utils.randomStringGenerator("Role_Description_", 10)))); + return response.getResourceId(); + } + + /** + * Grants or revokes the named permissions on a role. The endpoint merges the map into the role's existing + * permissions, so a call only has to name the ones it changes. + */ + public static PutRolesRoleIdPermissionsResponse addPermissionsToRole(Long roleId, Map permissions) { + return ok(() -> client().roles().updateRolePermissions(roleId, new PutRolesRoleIdPermissionsRequest().permissions(permissions))); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignUserHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignUserHelper.java index 0f763ed3de8..cdb35dca86b 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignUserHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignUserHelper.java @@ -64,11 +64,18 @@ public static FineractFeignClient getSimpleUserWithoutBypassPermissionClient() { * the generated user id. */ public static PostUsersResponse createUser(Long roleId, Long staffId, String username, String password) { + return createUser(new PostUsersRequest().username(username).firstname("Test").lastname("User").email("whatever@mifos.org") + .officeId(OfficeHelper.getHeadOffice().getId()).staffId(staffId).roles(List.of(roleId)).password(password) + .repeatPassword(password).sendPasswordToEmail(false)); + } + + /** + * Creates a user from a fully specified request, for callers that need to control the office, roles or name fields + * the convenience overload fixes. Mirrors {@code UserHelper.createUser(requestSpec, responseSpec, request)}. + */ + public static PostUsersResponse createUser(PostUsersRequest request) { FineractFeignClient adminClient = FineractFeignClientHelper.getFineractFeignClient(); - return ok(() -> adminClient.users() - .createUser(new PostUsersRequest().username(username).firstname("Test").lastname("User").email("whatever@mifos.org") - .officeId(OfficeHelper.getHeadOffice().getId()).staffId(staffId).roles(List.of(roleId)).password(password) - .repeatPassword(password).sendPasswordToEmail(false))); + return ok(() -> adminClient.users().createUser(request)); } private static void createSimpleUser(String username) {