From 8fbea6b47691e171377d1d47ebad0e8588a920a8 Mon Sep 17 00:00:00 2001 From: Oleksii Novikov Date: Tue, 15 Sep 2026 19:46:14 +0300 Subject: [PATCH 1/2] FINERACT-2455: WC - Add missing permissions for transaction undo and charge creation --- .../domain/CommandWrapperConstants.java | 2 +- .../features/working-capital-charges.adoc | 1 + .../working-capital-recovery-payment.adoc | 16 +---- .../test/stepdef/common/UserStepDef.java | 19 ++++- .../loan/WorkingCapitalChargeStepDef.java | 56 ++++++++------- .../WorkingCapitalLoanAccountStepDef.java | 47 ++++++++++--- .../features/WorkingCapitalLoanCharge.feature | 17 ++++- .../WorkingCapitalLoanUndoTransaction.feature | 39 +++++++++++ .../module-changelog-master.xml | 1 + ...81_wc_loan_missing_command_permissions.xml | 70 +++++++++++++++++++ 10 files changed, 214 insertions(+), 54 deletions(-) create mode 100644 fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0081_wc_loan_missing_command_permissions.xml diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandWrapperConstants.java b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandWrapperConstants.java index 8fd06faed21..aafe2a9738e 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandWrapperConstants.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/domain/CommandWrapperConstants.java @@ -183,7 +183,7 @@ private CommandWrapperConstants() {} public static final String ENTITY_LOANPRODUCT = "LOANPRODUCT"; public static final String ENTITY_WORKINGCAPITALLOANPRODUCT = "WORKINGCAPITALLOANPRODUCT"; public static final String ENTITY_WORKINGCAPITALLOAN = "WORKINGCAPITALLOAN"; - public static final String ENTITY_WORKINGCAPITALLOANTRANSACTION = "ENTITY_WORKINGCAPITALLOANTRANSACTION"; + public static final String ENTITY_WORKINGCAPITALLOANTRANSACTION = "WORKINGCAPITALLOANTRANSACTION"; public static final String ENTITY_CLIENTIDENTIFIER = "CLIENTIDENTIFIER"; public static final String ENTITY_CLIENT = "CLIENT"; public static final String ENTITY_DATATABLE = "DATATABLE"; diff --git a/fineract-doc/src/docs/en/chapters/features/working-capital-charges.adoc b/fineract-doc/src/docs/en/chapters/features/working-capital-charges.adoc index 3da7c3f99e9..8c91f69f73b 100644 --- a/fineract-doc/src/docs/en/chapters/features/working-capital-charges.adoc +++ b/fineract-doc/src/docs/en/chapters/features/working-capital-charges.adoc @@ -83,6 +83,7 @@ POST /working-capital-loans/{loanId}/charges * Accepts charge products with `chargeTimeType` `2` (`specified due date`) only. `dueDate` is mandatory, cannot be in the past, and the loan must be active, closed (obligations met) or overpaid. * A `disbursement` charge product is rejected with HTTP 403 and the error code `error.msg.wc.loan.charge.time.type.not.supported`. Nothing is persisted on the account. +* Requires the `CREATE_WORKINGCAPITALLOANCHARGE` permission (grouping `transaction_loan`, entity `WORKINGCAPITALLOANCHARGE`, action `CREATE`). === Loan Account Charge Template diff --git a/fineract-doc/src/docs/en/chapters/features/working-capital-recovery-payment.adoc b/fineract-doc/src/docs/en/chapters/features/working-capital-recovery-payment.adoc index e9b45d7c58b..f980c926312 100644 --- a/fineract-doc/src/docs/en/chapters/features/working-capital-recovery-payment.adoc +++ b/fineract-doc/src/docs/en/chapters/features/working-capital-recovery-payment.adoc @@ -276,17 +276,5 @@ Neither operation emits a balance-changed or status-changed event: the outstandi |=== The reversal adds no permission of its own: it goes through the generic transaction-undo command, exactly as -the reversal of a repayment, goodwill credit, payout refund or charge adjustment does. That command carries -action `UNDO` on entity `ENTITY_WORKINGCAPITALLOANTRANSACTION`. - -[NOTE] -==== -The permission code checked for a reversal is *not written anywhere in the source*: it is derived at runtime as -`actionName + "_" + entityName`, which for this command yields `UNDO_ENTITY_WORKINGCAPITALLOANTRANSACTION`. -Searching the codebase for that string finds nothing — the entity name and the action are declared separately -and concatenated when the command wrapper is built. - -No `m_permission` row is seeded for it, so today it can only be exercised by a super user (`ALL_FUNCTIONS`); -no other role can be granted it. This is pre-existing behaviour shared by every Working Capital transaction -reversal, not something the recovery payment introduces. -==== +the reversal of a repayment, goodwill credit, payout refund or charge adjustment does, and is guarded by +`UNDO_WORKINGCAPITALLOANTRANSACTION` (grouping `transaction_loan`, entity `WORKINGCAPITALLOANTRANSACTION`, action `UNDO`). diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/UserStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/UserStepDef.java index 0a2ccacd9a9..4d9357d745a 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/UserStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/UserStepDef.java @@ -19,12 +19,16 @@ package org.apache.fineract.test.stepdef.common; import static org.apache.fineract.client.feign.util.FeignCalls.ok; +import static org.assertj.core.api.Assertions.assertThat; +import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.RequiredArgsConstructor; import org.apache.fineract.client.feign.FineractFeignClient; +import org.apache.fineract.client.models.GetPermissionsResponse; import org.apache.fineract.client.models.PostRolesRequest; import org.apache.fineract.client.models.PostRolesResponse; import org.apache.fineract.client.models.PostUsersRequest; @@ -33,14 +37,13 @@ import org.apache.fineract.test.helper.Utils; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; -import org.springframework.beans.factory.annotation.Autowired; +@RequiredArgsConstructor public class UserStepDef extends AbstractStepDef { private static final String EMAIL = "test@test.com"; - @Autowired - private FineractFeignClient fineractClient; + private final FineractFeignClient fineractClient; private static final String PWD_USER_WITH_ROLE = "1234567890Aa!"; @@ -73,4 +76,14 @@ public void createUserWithUsernameAndRoles(String username, String roleName, Lis testContext().set(TestContextKey.CREATED_SIMPLE_USER_USERNAME, generatedUsername); testContext().set(TestContextKey.CREATED_SIMPLE_USER_PASSWORD, PWD_USER_WITH_ROLE); } + + @Then("Permission {string} is returned with grouping {string}, entity {string} and action {string}") + public void verifyPermissionIsReturned(final String code, final String grouping, final String entityName, final String actionName) { + final List permissions = ok(() -> fineractClient.permissions().retrieveAllPermissions()); + final GetPermissionsResponse permission = permissions.stream().filter(p -> code.equals(p.getCode())).findFirst() + .orElseThrow(() -> new AssertionError("Permission " + code + " is not returned by GET /permissions")); + assertThat(permission.getGrouping()).isEqualTo(grouping); + assertThat(permission.getEntityName()).isEqualTo(entityName); + assertThat(permission.getActionName()).isEqualTo(actionName); + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java index 305b9436f18..2014a1f5d24 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalChargeStepDef.java @@ -52,6 +52,7 @@ import org.apache.fineract.client.models.PostWorkingCapitalLoansLoanIdChargesChargeIdResponse; import org.apache.fineract.client.models.PostWorkingCapitalLoansResponse; import org.apache.fineract.client.models.WorkingCapitalLoanChargeData; +import org.apache.fineract.test.api.FineractClientConfiguration; import org.apache.fineract.test.data.ChargeCalculationType; import org.apache.fineract.test.data.ChargePaymentMode; import org.apache.fineract.test.data.ChargeProductAppliesTo; @@ -82,6 +83,7 @@ public class WorkingCapitalChargeStepDef extends AbstractStepDef { private final FineractFeignClient fineractClient; private final WorkingCapitalChargeRequestFactory chargeRequestFactory; private final ChargeProductResolver chargeProductResolver; + private final FineractClientConfiguration fineractClientConfiguration; @When("Admin creates working capital loan charge") public void createWorkingCapitalLoanCharge() { @@ -190,18 +192,7 @@ public void addWorkingCapitalCharge(String chargeType, String dueDate, Double am Long loanId = getLoanId(); Assertions.assertNotNull(loanId); - ChargeProductType chargeProductType = ChargeProductType.valueOf(chargeType); - Long chargeTypeId = chargeProductResolver.resolve(chargeProductType); - - LocalDate dueDateParsed = LocalDate.parse(dueDate, FORMATTER); - String dueDateFormatted = dueDateParsed.format(FORMATTER_API); - - PostLoansLoanIdChargesRequest request = new PostLoansLoanIdChargesRequest() // - .chargeId(chargeTypeId)// - .amount(amount)// - .dueDate(dueDateFormatted)// - .dateFormat(DATE_FORMAT_API)// - .locale("en");// + final PostLoansLoanIdChargesRequest request = buildSpecifiedDueDateChargeRequest(chargeType, dueDate, amount); PostLoansLoanIdChargesResponse response = ok(() -> fineractClient.workingCapitalLoanCharges().createLoanCharge(loanId, request)); Assertions.assertNotNull(response); Assertions.assertNotNull(response.getResourceId()); @@ -211,6 +202,34 @@ public void addWorkingCapitalCharge(String chargeType, String dueDate, Double am testContext().set(TestContextKey.ADD_DUE_DATE_CHARGE_WORKING_CAPITAL_RESPONSE, response); } + @When("Created user adds {string} specified due date charge to working capital loan with {string} due date and {double} transaction amount") + public void addWorkingCapitalChargeWithCreatedUser(final String chargeType, final String dueDate, final Double amount) { + final Long loanId = getLoanId(); + final PostLoansLoanIdChargesRequest request = buildSpecifiedDueDateChargeRequest(chargeType, dueDate, amount); + final FineractFeignClient userClient = userClient(); + final PostLoansLoanIdChargesResponse response = ok(() -> userClient.workingCapitalLoanCharges().createLoanCharge(loanId, request)); + Assertions.assertNotNull(response.getResourceId()); + testContext().set(TestContextKey.ADD_DUE_DATE_CHARGE_WORKING_CAPITAL_RESPONSE, response); + } + + private PostLoansLoanIdChargesRequest buildSpecifiedDueDateChargeRequest(final String chargeType, final String dueDate, + final Double amount) { + final Long chargeTypeId = chargeProductResolver.resolve(ChargeProductType.valueOf(chargeType)); + final String dueDateFormatted = LocalDate.parse(dueDate, FORMATTER).format(FORMATTER_API); + return new PostLoansLoanIdChargesRequest() // + .chargeId(chargeTypeId) // + .amount(amount) // + .dueDate(dueDateFormatted) // + .dateFormat(DATE_FORMAT_API) // + .locale("en"); + } + + private FineractFeignClient userClient() { + final String username = testContext().get(TestContextKey.CREATED_SIMPLE_USER_USERNAME); + final String password = testContext().get(TestContextKey.CREATED_SIMPLE_USER_PASSWORD); + return fineractClientConfiguration.fineractFeignClientForUser(username, password); + } + @Then("Working Capital Loan has charges with the following data:") public void verifyWorkingCapitalLoanChargesWithData(DataTable table) { Long loanId = getLoanId(); @@ -668,18 +687,7 @@ private void assertErrorMessage(final CallFailedRuntimeException exception, fina public void addWorkingCapitalChargeResultsAnError(final String chargeType, final String dueDate, final Double amount, final DataTable table) { final Long loanId = getLoanId(); - final ChargeProductType chargeProductType = ChargeProductType.valueOf(chargeType); - final Long chargeTypeId = chargeProductResolver.resolve(chargeProductType); - - final LocalDate dueDateParsed = LocalDate.parse(dueDate, FORMATTER); - final String dueDateFormatted = dueDateParsed.format(FORMATTER_API); - - final PostLoansLoanIdChargesRequest request = new PostLoansLoanIdChargesRequest() // - .chargeId(chargeTypeId) // - .amount(amount) // - .dueDate(dueDateFormatted) // - .dateFormat(DATE_FORMAT_API) // - .locale("en"); + final PostLoansLoanIdChargesRequest request = buildSpecifiedDueDateChargeRequest(chargeType, dueDate, amount); final CallFailedRuntimeException exception = fail( () -> fineractClient.workingCapitalLoanCharges().createLoanCharge(loanId, request)); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalLoanAccountStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalLoanAccountStepDef.java index 25cf20bffd9..9ddbeec5e52 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalLoanAccountStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/WorkingCapitalLoanAccountStepDef.java @@ -4409,17 +4409,8 @@ private List retrieveJournalEntriesForTransaction(G @When("Customer undo {string}th {string} transaction made on {string} on Working Capital loan") public void undoWorkingCapitalLoanTransaction(String nthItemStr, String transactionType, String transactionDate) throws IOException { final Long loanId = getCreatedLoanId(); - final GetWorkingCapitalLoanTransactionsResponse response = retrieveLoanTransactions(loanId); - final List actualTransactions = response.getContent(); - - final TransactionType resolvedType = resolveTransactionType(transactionType); - final String expectedCode = "loanTransactionType." + resolvedType.getValue(); - int nthItem = Integer.parseInt(nthItemStr) - 1; - - GetWorkingCapitalLoanTransactionIdResponse target = actualTransactions.stream() - .filter(t -> t.getType() != null && expectedCode.equals(t.getType().getCode()) - && transactionDate.equals(FORMATTER.format(t.getTransactionDate())) && !Boolean.TRUE.equals(t.getReversed())) - .toList().get(nthItem); + final GetWorkingCapitalLoanTransactionIdResponse target = findNthActiveTransaction(loanId, nthItemStr, transactionType, + transactionDate); String reversalExternalId = Utils.randomStringGenerator("wcl-reversal-ext-id", 8); ExecuteWorkingCapitalLoanTransactionCommandRequest request = new ExecuteWorkingCapitalLoanTransactionCommandRequest() @@ -4457,6 +4448,40 @@ public void undoWorkingCapitalLoanTransactionExpectError(String nthItemStr, Stri assertValidationError(exception, expectedErrorMessage); } + @When("Created user undoes {string}th {string} transaction made on {string} on Working Capital loan") + public void undoWorkingCapitalLoanTransactionWithCreatedUser(final String nthItemStr, final String transactionType, + final String transactionDate) { + final Long loanId = getCreatedLoanId(); + final GetWorkingCapitalLoanTransactionIdResponse target = findNthActiveTransaction(loanId, nthItemStr, transactionType, + transactionDate); + final ExecuteWorkingCapitalLoanTransactionCommandRequest request = new ExecuteWorkingCapitalLoanTransactionCommandRequest() + .reversalExternalId(Utils.randomStringGenerator("wcl-reversal-ext-id", 8)); + final FineractFeignClient userClient = userClient(); + final ExecuteWorkingCapitalLoanTransactionCommandResponse undo = ok(() -> userClient.workingCapitalLoanTransactions() + .executeWorkingCapitalLoanTransactionCommandByLoanIdTransactionId(loanId, target.getId(), "undo", request)); + Assertions.assertNotNull(undo); + } + + @Then("Created user without UNDO_WORKINGCAPITALLOANTRANSACTION permission fails to undo {string}th {string} transaction made on {string} on Working Capital loan") + public void undoWorkingCapitalLoanTransactionWithoutPermissionResultsAnError(final String nthItemStr, final String transactionType, + final String transactionDate) { + final Long loanId = getCreatedLoanId(); + final GetWorkingCapitalLoanTransactionIdResponse target = findNthActiveTransaction(loanId, nthItemStr, transactionType, + transactionDate); + final ExecuteWorkingCapitalLoanTransactionCommandRequest request = new ExecuteWorkingCapitalLoanTransactionCommandRequest(); + final FineractFeignClient userClient = userClient(); + final CallFailedRuntimeException exception = fail(() -> userClient.workingCapitalLoanTransactions() + .executeWorkingCapitalLoanTransactionCommandByLoanIdTransactionId(loanId, target.getId(), "undo", request)); + assertHttpStatus(exception, 403); + assertThat(exception.getDeveloperMessage()).contains("User has no authority to: UNDO_WORKINGCAPITALLOANTRANSACTION"); + } + + private GetWorkingCapitalLoanTransactionIdResponse findNthActiveTransaction(final Long loanId, final String nthItemStr, + final String transactionType, final String transactionDate) { + return findMatchingTransactions(loanId, resolveTransactionType(transactionType), transactionDate, false) + .get(Integer.parseInt(nthItemStr) - 1); + } + public void updatePeriodPaymentRateFailed(String periodPaymentRate, String errorMessage) { updatePeriodPaymentRateFailed(periodPaymentRate, errorMessage, 400); } diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature index 13412e7c4ad..f6c35410446 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature @@ -318,4 +318,19 @@ Feature: WorkingCapitalLoanChargesFeature Then Trying to add working capital loan charge by loan id and charge id with amount 45.0 and due date "10-01-2026" results an error with the following data: | httpCode | errorMessage | | 403 | Charge time type DISBURSEMENT is not supported on a Working Capital Loan. | - When Admin deletes working capital loan charge \ No newline at end of file + When Admin deletes working capital loan charge + + Scenario: Verify Working Capital Charge on loan account level - user with CREATE_WORKINGCAPITALLOANCHARGE permission can add a charge + Then Permission "CREATE_WORKINGCAPITALLOANCHARGE" is returned with grouping "transaction_loan", entity "WORKINGCAPITALLOANCHARGE" and action "CREATE" + Given Admin sets the business date to "01 January 2026" + And Admin creates a client with random data and creates-approves-disburses a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPayment | periodPaymentRate | discount | + | WCLP | 01 January 2026 | 01 January 2026 | 9000 | 100000 | 18 | 0 | + And Admin creates new user with "WC_ADD_CHARGE_USER" username, "WC_ADD_CHARGE_ROLE" role name and given permissions: + | CREATE_WORKINGCAPITALLOANCHARGE | + When Created user adds "WORKING_CAPITAL_SPECIFIED_DUE_DATE_FEE" specified due date charge to working capital loan with "01 January 2026" due date and 35.0 transaction amount + Then Working Capital Loan has charges with the following data: + | Charge Name | Due Date | Amount | Currency | isPenalty | Charge Time Type | Charge Calculation Type | Charge Payment mode | + | Working Capital Loan Fee | 01 January 2026 | 35.0 | EUR | false | Specified due date | Flat | Regular | + And Admin runs inline COB job for Working Capital Loan by loanId + Then Admin closes the Working Capital loan with all obligations met with a full repayment on "01 January 2026" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature index 2333f1864e5..214af667391 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature @@ -627,3 +627,42 @@ Feature: Working Capital Loan Undo Transaction # --- Close loan --- When Admin closes the Working Capital loan with a full repayment on "07 January 2026" Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + Scenario: Verify working capital loan undo transaction - user with UNDO_WORKINGCAPITALLOANTRANSACTION permission can undo a repayment + Then Permission "UNDO_WORKINGCAPITALLOANTRANSACTION" is returned with grouping "transaction_loan", entity "WORKINGCAPITALLOANTRANSACTION" and action "UNDO" + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | WCLP_ACC_DEF_REV_AM | 01 January 2026 | 01 January 2026 | 9000 | 100000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "9000" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "9000" EUR transaction amount + And Admin creates new user with "WC_UNDO_TXN_USER" username, "WC_UNDO_TXN_ROLE" role name and given permissions: + | REPAYMENT_WORKINGCAPITALLOAN | + | UNDO_WORKINGCAPITALLOANTRANSACTION | + When Admin sets the business date to "10 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Created user makes repayment on "10 January 2026" with 270.0 transaction amount on Working Capital loan + And Created user undoes "1"th "REPAYMENT" transaction made on "10 January 2026" on Working Capital loan + Then Working Capital loan balance payload contains the following fields: + | field | value | + | principalOutstanding | 9000.00 | + When Admin closes the Working Capital loan with a full repayment on "10 January 2026" + Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + + Scenario: Verify working capital loan undo transaction - user without UNDO_WORKINGCAPITALLOANTRANSACTION permission is rejected + When Admin sets the business date to "01 January 2026" + And Admin creates a client with random data + And Admin creates a working capital loan with the following data: + | LoanProduct | submittedOnDate | expectedDisbursementDate | principalAmount | totalPaymentVolume | periodPaymentRate | discount | + | WCLP_ACC_DEF_REV_AM | 01 January 2026 | 01 January 2026 | 9000 | 100000 | 18 | 0 | + And Admin successfully approves the working capital loan on "01 January 2026" with "9000" amount and expected disbursement date on "01 January 2026" + And Admin successfully disburse the Working Capital loan on "01 January 2026" with "9000" EUR transaction amount + And Admin creates new user with "WC_NO_UNDO_TXN_USER" username, "WC_NO_UNDO_TXN_ROLE" role name and given permissions: + | REPAYMENT_WORKINGCAPITALLOAN | + When Admin sets the business date to "10 January 2026" + And Admin runs inline COB job for Working Capital Loan by loanId + And Created user makes repayment on "10 January 2026" with 270.0 transaction amount on Working Capital loan + Then Created user without UNDO_WORKINGCAPITALLOANTRANSACTION permission fails to undo "1"th "REPAYMENT" transaction made on "10 January 2026" on Working Capital loan + When Admin closes the Working Capital loan with a full repayment on "10 January 2026" + Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" diff --git a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml index 0255c65a59d..d06d6105b79 100644 --- a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml +++ b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/module-changelog-master.xml @@ -102,4 +102,5 @@ + diff --git a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0081_wc_loan_missing_command_permissions.xml b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0081_wc_loan_missing_command_permissions.xml new file mode 100644 index 00000000000..b67ab1ee0c5 --- /dev/null +++ b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0081_wc_loan_missing_command_permissions.xml @@ -0,0 +1,70 @@ + + + + + + + + SELECT COUNT(*) FROM m_permission WHERE code = 'UNDO_WORKINGCAPITALLOANTRANSACTION'; + + + + + + + + + + + + + + + SELECT COUNT(*) FROM m_permission WHERE code = 'CREATE_WORKINGCAPITALLOANCHARGE'; + + + + + + + + + + + + + + + SELECT COUNT(*) FROM m_permission WHERE code = 'CREATE_WORKINGCAPITALLOANCHARGE_CHECKER'; + + + + + + + + + + + From eeaebf4b6cd746704f349ebee79c185e9880f776 Mon Sep 17 00:00:00 2001 From: Rustam Zeinalov Date: Fri, 18 Sep 2026 14:53:14 +0200 Subject: [PATCH 2/2] FINERACT-2455: updated e2e tests for validating WC - Add missing permissions for transaction undo and charge creation --- .../test/resources/features/WorkingCapitalLoanCharge.feature | 1 + .../features/WorkingCapitalLoanUndoTransaction.feature | 2 ++ 2 files changed, 3 insertions(+) diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature index f6c35410446..467737ded5f 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanCharge.feature @@ -320,6 +320,7 @@ Feature: WorkingCapitalLoanChargesFeature | 403 | Charge time type DISBURSEMENT is not supported on a Working Capital Loan. | When Admin deletes working capital loan charge + @TestRailId:C106718 Scenario: Verify Working Capital Charge on loan account level - user with CREATE_WORKINGCAPITALLOANCHARGE permission can add a charge Then Permission "CREATE_WORKINGCAPITALLOANCHARGE" is returned with grouping "transaction_loan", entity "WORKINGCAPITALLOANCHARGE" and action "CREATE" Given Admin sets the business date to "01 January 2026" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature index 214af667391..6c69e1b617f 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanUndoTransaction.feature @@ -628,6 +628,7 @@ Feature: Working Capital Loan Undo Transaction When Admin closes the Working Capital loan with a full repayment on "07 January 2026" Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + @TestRailId:C106716 Scenario: Verify working capital loan undo transaction - user with UNDO_WORKINGCAPITALLOANTRANSACTION permission can undo a repayment Then Permission "UNDO_WORKINGCAPITALLOANTRANSACTION" is returned with grouping "transaction_loan", entity "WORKINGCAPITALLOANTRANSACTION" and action "UNDO" When Admin sets the business date to "01 January 2026" @@ -650,6 +651,7 @@ Feature: Working Capital Loan Undo Transaction When Admin closes the Working Capital loan with a full repayment on "10 January 2026" Then Working Capital loan status will be "CLOSED_OBLIGATIONS_MET" + @TestRailId:C106717 Scenario: Verify working capital loan undo transaction - user without UNDO_WORKINGCAPITALLOANTRANSACTION permission is rejected When Admin sets the business date to "01 January 2026" And Admin creates a client with random data