diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index baaa6b13a1c..531ea986387 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -934,6 +934,15 @@ public CommandWrapperBuilder updatePeriodPaymentRateWorkingCapitalLoanApplicatio return this; } + public CommandWrapperBuilder markAsFraudWorkingCapitalLoan(final Long loanId) { + this.actionName = "SETFRAUD"; + this.entityName = "WORKINGCAPITALLOAN"; + this.entityId = loanId; + this.loanId = loanId; + this.href = "/working-capital-loans/" + loanId + "/mark-as-fraud"; + return this; + } + public CommandWrapperBuilder createNearBreachActionWorkingCapitalLoan(final Long loanId) { this.actionName = "CREATE"; this.entityName = "WC_NEAR_BREACH_ACTION"; diff --git a/fineract-doc/src/docs/en/chapters/features/index.adoc b/fineract-doc/src/docs/en/chapters/features/index.adoc index c942f6d6a84..64d8a9243fc 100644 --- a/fineract-doc/src/docs/en/chapters/features/index.adoc +++ b/fineract-doc/src/docs/en/chapters/features/index.adoc @@ -36,3 +36,4 @@ include::working-capital-disable/index.adoc[leveloffset=+1] include::working-capital-accrual-deferred-revenue-amortization-accounting.adoc[leveloffset=+1] include::working-capital-eir-calculation-accounting.adoc[leveloffset=+1] include::working-capital-loan-start-dates.adoc[leveloffset=+1] +include::working-capital-mark-as-fraud.adoc[leveloffset=+1] diff --git a/fineract-doc/src/docs/en/chapters/features/working-capital-mark-as-fraud.adoc b/fineract-doc/src/docs/en/chapters/features/working-capital-mark-as-fraud.adoc new file mode 100644 index 00000000000..dffb869ac9f --- /dev/null +++ b/fineract-doc/src/docs/en/chapters/features/working-capital-mark-as-fraud.adoc @@ -0,0 +1,78 @@ += Working Capital Loan — Mark as Fraud + +== Purpose + +Marking a Working Capital Loan as fraudulent flags an account that has been identified as fraud, so that a +later charge-off routes the write-off to a dedicated *fraud expense* account instead of the regular +charge-off expense account. + +The fraud flag is *independent of the charge-off action itself*: it only records that the loan is +fraudulent. It has no accounting effect until the loan is charged off. + +== Functionality + +* `fraud` is a boolean flag on the loan account (column `is_fraud` on `m_wc_loan`), defaulting to `false`. +* A loan can be marked as fraud *only while it is active*. Clearing the flag is allowed regardless of status. +* Marking a loan as fraud *does not change the loan status* — the loan keeps its `ACTIVE` status. +* The operation is idempotent: re-sending the same value is a no-op and reports no changes. + +== Validation Rules + +* `fraud` is *required* and must be a boolean (`true` or `false`). +* The loan must be *active* to be marked as fraud (`fraud = true`). Clearing the flag (`fraud = false`) is + allowed in any status. + +== Authorization + +The command requires the `SETFRAUD_WORKINGCAPITALLOAN` permission. Users with `ALL_FUNCTIONS` (super user) +are allowed implicitly. Maker-checker is supported and can be enabled for this permission; it is disabled by +default. + +== API + +[source] +---- +PUT /v1/working-capital-loans/{loanId}/mark-as-fraud +---- + +[source,json] +---- +{ + "fraud": true +} +---- + +Response (`CommandProcessingResult`): + +[source,json] +---- +{ + "officeId": 1, + "clientId": 5, + "loanId": 12, + "resourceId": 12, + "changes": { + "fraud": true + } +} +---- + +`changes` is empty when the flag already had the requested value. + +== Retrieval + +The current value is exposed as the `fraud` field of the loan retrieval response: + +[source] +---- +GET /v1/working-capital-loans/{loanId} +---- + +== Accounting Impact + +Marking a loan as fraud produces *no journal entries* on its own. The flag is consumed at charge-off time: +a charged-off fraudulent loan debits the *Charge-Off Fraud Expense* account instead of the regular +*Charge-Off Expense* account. All other charge-off processing is identical. + +NOTE: This command is served through the legacy command-source pipeline, like every other Working Capital +Loan command, so it is recorded in the command audit trail and can participate in maker-checker. diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanTestHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanTestHelper.java index 66b6a03fb7d..dd70dbdb3e5 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanTestHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkingCapitalLoanTestHelper.java @@ -82,7 +82,8 @@ public Long insertLoan(final LoanStatus status, final LocalDate lastClosedBusine .addValue("principal_amount_proposed", DEFAULT_PRINCIPAL)// .addValue("approved_principal", DEFAULT_PRINCIPAL)// .addValue("total_payment_volume", DEFAULT_PRINCIPAL)// - .addValue("breach_start_type", "DISBURSEMENT"); + .addValue("breach_start_type", "DISBURSEMENT")// + .addValue("is_fraud", Boolean.FALSE); final Number key = wcLoanInsert.executeAndReturnKey(params); return Objects.requireNonNull(key, "Generated key must not be null").longValue(); } diff --git a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanDetails.feature b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanDetails.feature index 9b9e74c7116..c5d1a9a5a93 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanDetails.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/WorkingCapitalLoanDetails.feature @@ -158,7 +158,7 @@ Feature: Working Capital Loan Details | paymentAllocation.0.paymentAllocationOrder | present | | originators.size | 0 | | enableInstallmentLevelDelinquency | true | - | fraud | null | + | fraud | false | | chargedOff | null | And Working capital loan details has the auto-generated fields present diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/WorkingCapitalLoanConstants.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/WorkingCapitalLoanConstants.java index 6e0ddc959ea..94c0a60e796 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/WorkingCapitalLoanConstants.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/WorkingCapitalLoanConstants.java @@ -62,6 +62,7 @@ private WorkingCapitalLoanConstants() { public static final String discountExternalIdParameterName = "discountExternalId"; public static final String noteParamName = "note"; public static final String rejectedOnDateParamName = "rejectedOnDate"; + public static final String fraudParamName = "fraud"; // Disbursal / Undo disbursal parameters public static final String actualDisbursementDateParamName = "actualDisbursementDate"; diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResource.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResource.java index 7e01beba520..200043d217d 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResource.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResource.java @@ -52,6 +52,7 @@ import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.workingcapitalloan.WorkingCapitalLoanConstants; +import org.apache.fineract.portfolio.workingcapitalloan.data.MarkWorkingCapitalLoanAsFraudRequest; import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanData; import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanDelinquencyTagHistoryData; import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanPeriodPaymentRateChangeData; @@ -159,6 +160,20 @@ public CommandProcessingResult modifyLoanApplicationById( return modifyLoanApplication(loanId, null, apiRequestBodyAsJson); } + @PUT + @Path("{loanId}/mark-as-fraud") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(operationId = "markWorkingCapitalLoanAsFraud", summary = "Mark or unmark a Working Capital Loan as fraudulent", description = "Flags the loan as fraudulent. When the loan is later charged off, a fraudulent loan is routed to the charge-off fraud expense account instead of the regular charge-off expense account. Does not change the loan status.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = MarkWorkingCapitalLoanAsFraudRequest.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CommandProcessingResult.class))) + public CommandProcessingResult markAsFraud(@PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + final CommandWrapper commandRequest = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson) + .markAsFraudWorkingCapitalLoan(loanId).build(); + return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } + @DELETE @Path("{loanId}") @Produces({ MediaType.APPLICATION_JSON }) diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResourceSwagger.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResourceSwagger.java index 7f238367d38..3a48857d4f0 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResourceSwagger.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/api/WorkingCapitalLoanApiResourceSwagger.java @@ -343,7 +343,7 @@ private GetWorkingCapitalLoanSummary() {} public Boolean enableInstallmentLevelDelinquency; @Schema(description = "List of originators associated with this loan") public List originators; - @Schema(description = "Fraud flag. Placeholder: null until the WCP fraud feature is implemented") + @Schema(description = "Fraud flag. True when the loan has been marked as fraudulent", example = "false") public Boolean fraud; @Schema(description = "Charge-off flag. Placeholder: null until the WCP charge-off feature is implemented") public Boolean chargedOff; diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/data/MarkWorkingCapitalLoanAsFraudRequest.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/data/MarkWorkingCapitalLoanAsFraudRequest.java new file mode 100644 index 00000000000..8c7762a4f92 --- /dev/null +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/data/MarkWorkingCapitalLoanAsFraudRequest.java @@ -0,0 +1,31 @@ +/** + * 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.portfolio.workingcapitalloan.data; + +import io.swagger.v3.oas.annotations.media.Schema; + +/** + * Request body schema for the mark-as-fraud endpoint. Used for OpenAPI documentation; the command is served through the + * legacy command-source pipeline, which parses the raw JSON body. + */ +public class MarkWorkingCapitalLoanAsFraudRequest { + + @Schema(description = "Whether the loan should be flagged as fraudulent", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + public Boolean fraud; +} diff --git a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoan.java b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoan.java index 15910897054..d11f31044f3 100644 --- a/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoan.java +++ b/fineract-working-capital-loan/src/main/java/org/apache/fineract/portfolio/workingcapitalloan/domain/WorkingCapitalLoan.java @@ -170,6 +170,14 @@ public class WorkingCapitalLoan extends AbstractAuditableWithUTCDateTimeCustom new WorkingCapitalLoanNotFoundException(loanId)); + + // A loan can only be marked as fraud while it is active. Clearing the flag and idempotent re-marks are + // allowed regardless of status. + final boolean markingAsFraud = fraud && !loan.isFraud(); + if (markingAsFraud && loan.getLoanStatus() != LoanStatus.ACTIVE) { + throw new PlatformApiDataValidationException("validation.msg.wc.loan.mark.as.fraud.not.allowed", + "Marking a loan as fraud is allowed only for active loans", "loanStatus"); + } + + final Map changes = new LinkedHashMap<>(); + if (loan.isFraud() != fraud) { + loan.setFraud(fraud); + this.loanRepository.saveAndFlush(loan); + changes.put(WorkingCapitalLoanConstants.fraudParamName, fraud); + } + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(loan.getId()) // + .withEntityExternalId(loan.getExternalId()) // + .withOfficeId(loan.getOfficeId()) // + .withClientId(loan.getClientId()) // + .withLoanId(loan.getId()) // + .with(changes) // + .build(); + } + + private boolean validateAndExtractFraud(final JsonCommand command) { + final String json = command.json(); + final Set supportedParameters = Set.of(WorkingCapitalLoanConstants.fraudParamName); + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + final Boolean fraud = this.fromApiJsonHelper.extractBooleanNamed(WorkingCapitalLoanConstants.fraudParamName, element); + + final List dataValidationErrors = new ArrayList<>(); + new DataValidatorBuilder(dataValidationErrors).resource("workingcapitalloan.markasfraud") + .parameter(WorkingCapitalLoanConstants.fraudParamName).value(fraud).notNull(); + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException(dataValidationErrors); + } + + return fraud; + } +} 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 015b71c3ad8..bfcaaad7ab9 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 @@ -80,4 +80,5 @@ + diff --git a/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0059_wc_loan_add_fraud_attribute.xml b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0059_wc_loan_add_fraud_attribute.xml new file mode 100644 index 00000000000..67062781363 --- /dev/null +++ b/fineract-working-capital-loan/src/main/resources/db/changelog/tenant/module/workingcapitalloan/parts/0059_wc_loan_add_fraud_attribute.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + SELECT COUNT(*) FROM m_permission WHERE code = 'SETFRAUD_WORKINGCAPITALLOAN' + + + + + + + + + + + diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanMarkAsFraudTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanMarkAsFraudTest.java new file mode 100644 index 00000000000..3da0be3f2e2 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/WorkingCapitalLoanMarkAsFraudTest.java @@ -0,0 +1,139 @@ +/** + * 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; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.UUID; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; +import org.apache.fineract.client.models.GetWorkingCapitalLoansLoanIdResponse; +import org.apache.fineract.client.models.MarkWorkingCapitalLoanAsFraudRequest; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.workingcapitalloan.WorkingCapitalLoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.common.workingcapitalloan.WorkingCapitalLoanDisbursementTestBuilder; +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.junit.jupiter.api.Test; + +/** + * Integration test for the Working Capital Loan mark-as-fraud command, exercised through the generated Feign client. + * The command is served through the legacy command-source pipeline (audit trail and maker-checker), which enforces the + * SETFRAUD_WORKINGCAPITALLOAN permission. + */ +public class WorkingCapitalLoanMarkAsFraudTest { + + private final WorkingCapitalLoanHelper applicationHelper = new WorkingCapitalLoanHelper(); + private final WorkingCapitalLoanProductHelper productHelper = new WorkingCapitalLoanProductHelper(); + + @Test + public void testMarkAndUnmarkWorkingCapitalLoanAsFraud() { + final Long productId = createProduct(); + final Long clientId = createClient(); + final Long loanId = activeLoan(clientId, productId); + + // A freshly disbursed loan is not fraudulent. + assertFalse(Boolean.TRUE.equals(retrieveLoan(loanId).getFraud())); + + // Mark the loan as fraudulent. + applicationHelper.markAsFraud(loanId, new MarkWorkingCapitalLoanAsFraudRequest().fraud(true)); + assertTrue(retrieveLoan(loanId).getFraud()); + + // Marking again with the same value is idempotent. + applicationHelper.markAsFraud(loanId, new MarkWorkingCapitalLoanAsFraudRequest().fraud(true)); + assertTrue(retrieveLoan(loanId).getFraud()); + + // Unmark the loan. + applicationHelper.markAsFraud(loanId, new MarkWorkingCapitalLoanAsFraudRequest().fraud(false)); + assertFalse(Boolean.TRUE.equals(retrieveLoan(loanId).getFraud())); + } + + @Test + public void testMarkAsFraudFailsWhenFraudFlagMissing() { + final Long productId = createProduct(); + final Long clientId = createClient(); + final Long loanId = submitLoan(clientId, productId); + + // fraud is a required field; omitting it must be rejected by the request validation. + final CallFailedRuntimeException ex = applicationHelper.markAsFraudExpectingFailure(loanId, + new MarkWorkingCapitalLoanAsFraudRequest()); + assertEquals(400, ex.getStatus()); + } + + @Test + public void testMarkAsFraudFailsWhenLoanNotActive() { + final Long productId = createProduct(); + final Long clientId = createClient(); + // The loan is only submitted (not approved/disbursed), so it is not active. + final Long loanId = submitLoan(clientId, productId); + + // Marking a non-active loan as fraud must be rejected with a 400 carrying the specific validation message. + final CallFailedRuntimeException ex = applicationHelper.markAsFraudExpectingFailure(loanId, + new MarkWorkingCapitalLoanAsFraudRequest().fraud(true)); + assertEquals(400, ex.getStatus()); + assertNotNull(ex.getDeveloperMessage()); + assertTrue(ex.getDeveloperMessage().contains("Marking a loan as fraud is allowed only for active loans")); + } + + private Long activeLoan(final Long clientId, final Long productId) { + final Long loanId = submitLoan(clientId, productId); + final LocalDate currentDate = LocalDate.now(ZoneId.systemDefault()); + applicationHelper.approveById(loanId, + WorkingCapitalLoanApplicationTestBuilder.buildApproveRequest(currentDate, BigDecimal.valueOf(5000), null)); + applicationHelper.disburseById(loanId, + WorkingCapitalLoanDisbursementTestBuilder.buildDisburseRequest(currentDate, BigDecimal.valueOf(5000))); + return loanId; + } + + private Long submitLoan(final Long clientId, final Long productId) { + return applicationHelper.submit(new WorkingCapitalLoanApplicationTestBuilder() // + .withClientId(clientId) // + .withProductId(productId) // + .withPrincipal(BigDecimal.valueOf(5000)) // + .withPeriodPaymentRate(WorkingCapitalLoanProductTestBuilder.DEFAULT_PERIOD_PAYMENT_RATE_PERCENT) // + .withTotalPaymentVolume(BigDecimal.valueOf(100000)) // + .buildSubmitRequest()); + } + + private GetWorkingCapitalLoansLoanIdResponse retrieveLoan(final Long loanId) { + final GetWorkingCapitalLoansLoanIdResponse response = applicationHelper.retrieveById(loanId); + assertNotNull(response); + return response; + } + + private Long createProduct() { + final String uniqueName = "WCL Product " + UUID.randomUUID().toString().substring(0, 8); + final String uniqueShortName = Utils.uniqueRandomStringGenerator("", 4); + return productHelper + .createWorkingCapitalLoanProduct( + new WorkingCapitalLoanProductTestBuilder().withName(uniqueName).withShortName(uniqueShortName).build()) + .getResourceId(); + } + + private Long createClient() { + return ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/workingcapitalloan/WorkingCapitalLoanHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/workingcapitalloan/WorkingCapitalLoanHelper.java index 2a2e1d7988c..019a254d55c 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/workingcapitalloan/WorkingCapitalLoanHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/workingcapitalloan/WorkingCapitalLoanHelper.java @@ -31,6 +31,7 @@ import org.apache.fineract.client.models.GetWorkingCapitalLoansLoanIdResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoansPagedResponse; import org.apache.fineract.client.models.GetWorkingCapitalLoansTemplateResponse; +import org.apache.fineract.client.models.MarkWorkingCapitalLoanAsFraudRequest; import org.apache.fineract.client.models.PostWorkingCapitalLoanTransactionsRequest; import org.apache.fineract.client.models.PostWorkingCapitalLoansLoanIdRequest; import org.apache.fineract.client.models.PostWorkingCapitalLoansRequest; @@ -79,6 +80,14 @@ public GetWorkingCapitalLoansLoanIdResponse retrieveById(final Long loanId) { return FeignCalls.ok(() -> api().retrieveWorkingCapitalLoanById(loanId)); } + public void markAsFraud(final Long loanId, final MarkWorkingCapitalLoanAsFraudRequest request) { + FeignCalls.ok(() -> api().markWorkingCapitalLoanAsFraud(loanId, request)); + } + + public CallFailedRuntimeException markAsFraudExpectingFailure(final Long loanId, final MarkWorkingCapitalLoanAsFraudRequest request) { + return FeignCalls.fail(() -> api().markWorkingCapitalLoanAsFraud(loanId, request)); + } + public GetWorkingCapitalLoansLoanIdResponse retrieveByExternalId(final String externalId) { return FeignCalls.ok(() -> api().retrieveWorkingCapitalLoanByExternalId(externalId)); }