From abcaa52ef729141df30936db01374ced609546e4 Mon Sep 17 00:00:00 2001 From: taskain7 Date: Mon, 6 Feb 2023 04:25:49 +0100 Subject: [PATCH] [FINERACT-1678] Integration test for Inline COB on write API calls when the loan account is soft locked --- .../integrationtests/common/BatchHelper.java | 20 +++ .../common/loans/LoanAccountLockHelper.java | 45 +++++ .../inlinecob/InlineLoanCOBTest.java | 158 ++++++++++++++++++ .../useradministration/roles/RolesHelper.java | 19 ++- 4 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java index e2b38aa6f..ea5e59b31 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java @@ -746,6 +746,11 @@ public final class BatchHelper { return createTransactionRequest(requestId, reference, "repayment", amount, LocalDate.now(ZoneId.systemDefault())); } + public static BatchRequest repayLoanRequestWithGivenLoanId(final Long requestId, final Integer loanId, final String amount, + final LocalDate date) { + return createTransactionRequestWithGivenLoanId(requestId, loanId, "repayment", amount, date); + } + /** * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId. * @@ -775,6 +780,21 @@ public final class BatchHelper { return br; } + public static BatchRequest createTransactionRequestWithGivenLoanId(final Long requestId, final Integer loanId, + final String transactionCommand, final String amount, final LocalDate date) { + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setRelativeUrl(String.format("loans/" + loanId + "/transactions?command=%s", transactionCommand)); + br.setMethod("POST"); + String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + br.setBody(String.format( + "{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", " + "\"transactionDate\": \"%s\", \"transactionAmount\": %s}", + dateString, amount)); + + return br; + } + /** * Creates and returns a {@link CreateTransactionLoanCommandStrategy} Request with given requestId. * diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java new file mode 100644 index 000000000..983ae9ad7 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanAccountLockHelper.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.integrationtests.common.loans; + +import com.google.gson.Gson; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import org.apache.fineract.client.util.JSON; +import org.apache.fineract.integrationtests.client.IntegrationTest; +import org.apache.fineract.integrationtests.common.Utils; + +public class LoanAccountLockHelper extends IntegrationTest { + + private static final String INTERNAL_PLACE_LOCK_ON_LOAN_ACCOUNT_URL = "/fineract-provider/api/v1/internal/loans/"; + private static final Gson GSON = new JSON().getGson(); + private final RequestSpecification requestSpec; + private final ResponseSpecification responseSpec; + + public LoanAccountLockHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { + this.requestSpec = requestSpec; + this.responseSpec = responseSpec; + } + + public String placeSoftLockOnLoanAccount(Integer loanId, String lockOwner) { + return Utils.performServerPost(requestSpec, responseSpec, + INTERNAL_PLACE_LOCK_ON_LOAN_ACCOUNT_URL + loanId + "/place-lock/" + lockOwner + "?" + Utils.TENANT_IDENTIFIER, + GSON.toJson(null)); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java index cf7cb6c40..71cd3cc39 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java @@ -32,25 +32,36 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.batch.domain.BatchRequest; +import org.apache.fineract.batch.domain.BatchResponse; import org.apache.fineract.client.models.GetDelinquencyBucketsResponse; import org.apache.fineract.client.models.GetDelinquencyRangesResponse; import org.apache.fineract.client.models.GetDelinquencyTagHistoryResponse; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.GetOfficesResponse; import org.apache.fineract.client.models.PostDelinquencyBucketResponse; import org.apache.fineract.client.models.PostDelinquencyRangeResponse; +import org.apache.fineract.client.models.PostUsersRequest; +import org.apache.fineract.client.models.PostUsersResponse; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.integrationtests.common.BatchHelper; import org.apache.fineract.integrationtests.common.BusinessDateHelper; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CollateralManagementHelper; import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.OfficeHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.charges.ChargesHelper; +import org.apache.fineract.integrationtests.common.loans.LoanAccountLockHelper; 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.LoanTransactionHelper; import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; import org.apache.fineract.integrationtests.common.products.DelinquencyRangesHelper; +import org.apache.fineract.integrationtests.useradministration.roles.RolesHelper; +import org.apache.fineract.integrationtests.useradministration.users.UserHelper; +import org.apache.http.HttpStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -58,10 +69,14 @@ import org.junit.jupiter.api.Test; @Slf4j public class InlineLoanCOBTest { + private static final String REPAYMENT_LOAN_PERMISSION = "REPAYMENT_LOAN"; + private static final String READ_LOAN_PERMISSION = "READ_LOAN"; + private ResponseSpecification responseSpec; private RequestSpecification requestSpec; private InlineLoanCOBHelper inlineLoanCOBHelper; private LoanTransactionHelper loanTransactionHelper; + private LoanAccountLockHelper loanAccountLockHelper; @BeforeEach public void setup() { @@ -214,6 +229,149 @@ public class InlineLoanCOBTest { GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); } + @Test + public void testInlineCOBOnRepayment() { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 2)); + GlobalConfigurationHelper.updateValueForGlobalConfiguration(this.requestSpec, this.responseSpec, "10", "0"); + loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + loanAccountLockHelper = new LoanAccountLockHelper(requestSpec, new ResponseSpecBuilder().expectStatusCode(202).build()); + + final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); + Assertions.assertNotNull(clientID); + + Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1")); + Assertions.assertNotNull(overdueFeeChargeId); + + final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); + Assertions.assertNotNull(loanProductID); + HashMap loanStatusHashMap; + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); + + Assertions.assertNotNull(loanID); + + loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + loanStatusHashMap = loanTransactionHelper.approveLoan("01 March 2020", loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + + String loanDetails = loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID); + loanStatusHashMap = loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID, + JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.COB_DATE, LocalDate.of(2020, 3, 2)); + inlineLoanCOBHelper.executeInlineCOB(List.of(loanID.longValue())); + GetLoansLoanIdResponse loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID); + Assertions.assertEquals(LocalDate.of(2020, 3, 2), loan.getLastClosedBusinessDate()); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 10)); + + createNewSimpleUserWithoutBypassPermission(); + + loanAccountLockHelper.placeSoftLockOnLoanAccount(loanID, "LOAN_COB_PARTITIONING"); + loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + + loanTransactionHelper.makeRepayment("10 March 2020", 10.0f, loanID); + + loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID); + Assertions.assertEquals(LocalDate.of(2020, 3, 9), loan.getLastClosedBusinessDate()); + } + + @Test + public void testInlineCOBOnBatchAPI() { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 2)); + GlobalConfigurationHelper.updateValueForGlobalConfiguration(this.requestSpec, this.responseSpec, "10", "0"); + loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + loanAccountLockHelper = new LoanAccountLockHelper(requestSpec, new ResponseSpecBuilder().expectStatusCode(202).build()); + + final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec); + Assertions.assertNotNull(clientID); + + Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanOverdueFeeJSONWithCalculationTypePercentage("1")); + Assertions.assertNotNull(overdueFeeChargeId); + + final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); + Assertions.assertNotNull(loanProductID); + HashMap loanStatusHashMap; + final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); + + Assertions.assertNotNull(loanID); + + loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + loanStatusHashMap = loanTransactionHelper.approveLoan("01 March 2020", loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + + String loanDetails = loanTransactionHelper.getLoanDetails(requestSpec, responseSpec, loanID); + loanStatusHashMap = loanTransactionHelper.disburseLoanWithNetDisbursalAmount("02 March 2020", loanID, + JsonPath.from(loanDetails).get("netDisbursalAmount").toString()); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.COB_DATE, LocalDate.of(2020, 3, 2)); + inlineLoanCOBHelper.executeInlineCOB(List.of(loanID.longValue())); + GetLoansLoanIdResponse loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID); + Assertions.assertEquals(LocalDate.of(2020, 3, 2), loan.getLastClosedBusinessDate()); + + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 3, 10)); + + createNewSimpleUserWithoutBypassPermission(); + + loanAccountLockHelper.placeSoftLockOnLoanAccount(loanID, "LOAN_COB_PARTITIONING"); + loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + + final BatchRequest br1 = BatchHelper.repayLoanRequestWithGivenLoanId(4730L, loanID, "10", LocalDate.of(2020, 3, 10)); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(0).getStatusCode(), "Verify Status Code 200 for Repayment"); + + loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID); + Assertions.assertEquals(LocalDate.of(2020, 3, 9), loan.getLastClosedBusinessDate()); + } + + private void createNewSimpleUserWithoutBypassPermission() { + GetOfficesResponse headOffice = OfficeHelper.getHeadOffice(requestSpec, responseSpec); + String username = Utils.randomNameGenerator("NotificationUser", 4); + String password = Utils.randomStringGenerator("aA1", 10); // prefix is to conform with the password rules + String simpleRoleId = createSimpleRole(); + PostUsersRequest createUserRequest = new PostUsersRequest().username(username) + .firstname(Utils.randomNameGenerator("NotificationFN", 4)).lastname(Utils.randomNameGenerator("NotificationLN", 4)) + .email("whatever@mifos.org").password(password).repeatPassword(password).sendPasswordToEmail(false) + .roles(List.of(simpleRoleId)).officeId(headOffice.getId()); + + PostUsersResponse userCreationResponse = UserHelper.createUser(requestSpec, responseSpec, createUserRequest); + Assertions.assertNotNull(userCreationResponse.getResourceId()); + + requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, password)); + responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + private String createSimpleRole() { + Integer roleId = RolesHelper.createRole(requestSpec, responseSpec); + addRepaymentPermissionToRole(roleId); + return roleId.toString(); + } + + private void addRepaymentPermissionToRole(Integer roleId) { + HashMap permissionMap = new HashMap<>(); + permissionMap.put(REPAYMENT_LOAN_PERMISSION, true); + permissionMap.put(READ_LOAN_PERMISSION, true); + RolesHelper.addPermissionsToRole(requestSpec, responseSpec, roleId, permissionMap); + } + private Integer createLoanProduct(final String chargeId) { final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("1") diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java index 024957173..34e936359 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/useradministration/roles/RolesHelper.java @@ -38,10 +38,10 @@ public final class RolesHelper { private static final String ENABLE_ROLE_COMMAND = "enable"; public static Integer createRole(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { - return Utils.performServerPost(requestSpec, responseSpec, CREATE_ROLE_URL, getTestCreaRoleAsJSON(), "resourceId"); + return Utils.performServerPost(requestSpec, responseSpec, CREATE_ROLE_URL, getTestCreateRoleAsJSON(), "resourceId"); } - public static String getTestCreaRoleAsJSON() { + public static String getTestCreateRoleAsJSON() { final HashMap map = new HashMap<>(); map.put("name", Utils.randomNameGenerator("Role_Name_", 5)); map.put("description", Utils.randomNameGenerator("Role_Description_", 10)); @@ -51,8 +51,7 @@ public final class RolesHelper { public static HashMap getRoleDetails(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer roleId) { final String GET_ROLE_URL = "/fineract-provider/api/v1/roles/" + roleId + "?" + Utils.TENANT_IDENTIFIER; - HashMap role = Utils.performServerGet(requestSpec, responseSpec, GET_ROLE_URL, ""); - return role; + return Utils.performServerGet(requestSpec, responseSpec, GET_ROLE_URL, ""); } public static Integer disableRole(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, @@ -70,6 +69,18 @@ public final class RolesHelper { return Utils.performServerDelete(requestSpec, responseSpec, createRoleOperationURL(ENABLE_ROLE_COMMAND, roleId), "resourceId"); } + public static String addPermissionsToRole(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer roleId, final HashMap permissionMap) { + return Utils.performServerPut(requestSpec, responseSpec, ROLE_URL + "/" + roleId + "/permissions?" + Utils.TENANT_IDENTIFIER, + getAddPermissionsToRoleJSON(permissionMap)); + } + + private static String getAddPermissionsToRoleJSON(HashMap permissionMap) { + final HashMap> map = new HashMap<>(); + map.put("permissions", permissionMap); + return new Gson().toJson(map); + } + private static String createRoleOperationURL(final String command, final Integer roleId) { return ROLE_URL + "/" + roleId + "?command=" + command + "&" + Utils.TENANT_IDENTIFIER; }