From e2157501c06c7c132a449a5d70d514c2318471a5 Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Wed, 12 Feb 2025 16:50:03 +0100 Subject: [PATCH] FINERACT-2081: Allow loan charge-off via batch api --- .../command/CommandStrategyProvider.java | 2 +- ...actionByLoanExternalIdCommandStrategy.java | 2 +- .../CreateTransactionLoanCommandStrategy.java | 2 +- .../command/CommandStrategyProviderTest.java | 2 + .../integrationtests/BatchApiTest.java | 67 +++++++++++++++++++ .../integrationtests/common/BatchHelper.java | 18 +++++ 6 files changed, 90 insertions(+), 3 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java b/fineract-core/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java index 1899b3ce1..bfa7bf0d9 100644 --- a/fineract-core/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java +++ b/fineract-core/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java @@ -62,7 +62,7 @@ public class CommandStrategyProvider { /** * Regex pattern for specifying a mandatory query param that has key = 'command'. */ - private static final String MANDATORY_COMMAND_PARAM_REGEX = "\\?command=[\\w]+"; + private static final String MANDATORY_COMMAND_PARAM_REGEX = "\\?command=[\\w\\-]+"; /** * Regex pattern for specifying a UUID param. diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java index 62cd81e8f..9fa511baf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionByLoanExternalIdCommandStrategy.java @@ -65,7 +65,7 @@ public class CreateTransactionByLoanExternalIdCommandStrategy implements Command final List pathParameters = Splitter.on('/').splitToList(relativeUrlWithoutVersion(request)); final String loanExternalId = pathParameters.get(2); - final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z\\-]+"); final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(3)); if (!commandMatcher.find()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java index 8827b8ea9..8a085612d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/CreateTransactionLoanCommandStrategy.java @@ -64,7 +64,7 @@ public class CreateTransactionLoanCommandStrategy implements CommandStrategy { final List pathParameters = Splitter.on('/').splitToList(relativeUrlWithoutVersion(request)); final Long loanId = Long.parseLong(pathParameters.get(1)); - final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z]+"); + final Pattern commandPattern = Pattern.compile("^?command=[a-zA-Z\\-]+"); final Matcher commandMatcher = commandPattern.matcher(pathParameters.get(2)); if (!commandMatcher.find()) { diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java index dc0c900b6..b51d8a6bc 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java @@ -140,6 +140,8 @@ public class CommandStrategyProviderTest { mock(CreateTransactionLoanCommandStrategy.class)), Arguments.of("loans/123/transactions?command=chargeRefund", HttpMethod.POST, "createTransactionLoanCommandStrategy", mock(CreateTransactionLoanCommandStrategy.class)), + Arguments.of("loans/123/transactions?command=charge-off", HttpMethod.POST, "createTransactionLoanCommandStrategy", + mock(CreateTransactionLoanCommandStrategy.class)), Arguments.of("loans/123/transactions/123", HttpMethod.POST, "adjustLoanTransactionCommandStrategy", mock(AdjustLoanTransactionCommandStrategy.class)), Arguments.of("loans/123/transactions/123?command=chargeback", HttpMethod.POST, "adjustLoanTransactionCommandStrategy", diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java index 25e9dccd0..a951f6c85 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java @@ -2612,6 +2612,73 @@ public class BatchApiTest extends BaseLoanIntegrationTest { transactionWithdrawal2.get("runningBalance"), "Verify running balance after second withdrawal"); } + @Test + public void shouldReturnOkStatusForBatchChargeOff() { + + final String loanProductJSON = new LoanProductTestBuilder() // + .withPrincipal("10000000.00") // + .withNumberOfRepayments("24") // + .withRepaymentAfterEvery("1") // + .withRepaymentTypeAsMonth() // + .withinterestRatePerPeriod("2") // + .withInterestRateFrequencyTypeAsMonths() // + .withAmortizationTypeAsEqualPrincipalPayment() // + .withInterestTypeAsDecliningBalance() // + .currencyDetails("0", "100").build(null); + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + + 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); + + final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON); + + // Create a createClient Request + final BatchRequest br1 = BatchHelper.createClientRequest(4730L, ""); + + // Create a activateClient Request + final BatchRequest br2 = BatchHelper.activateClientRequest(4731L, 4730L); + + // Create a ApplyLoan Request + final BatchRequest br3 = BatchHelper.applyLoanRequest(4732L, 4731L, productId, clientCollateralId); + + // Create a approveLoan Request + final BatchRequest br4 = BatchHelper.approveLoanRequest(4733L, 4732L); + + // Create a disburseLoan Request + final BatchRequest br5 = BatchHelper.disburseLoanRequest(4734L, 4733L); + + // Create a loanRepay Request + final BatchRequest br6 = BatchHelper.repayLoanRequest(4735L, 4734L, "500"); + + // Create a loanRepay Request + final BatchRequest br7 = BatchHelper.repayLoanRequest(4736L, 4734L, "500"); + + final BatchRequest br8 = BatchHelper.chargeOffRequest(4737L, 4736L); + + final List batchRequests = new ArrayList<>(); + + batchRequests.add(br1); + batchRequests.add(br2); + batchRequests.add(br3); + batchRequests.add(br4); + batchRequests.add(br5); + batchRequests.add(br6); + batchRequests.add(br7); + batchRequests.add(br8); + + final String jsonifiedRequest = BatchHelper.toJsonString(batchRequests); + + final List response = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec, + jsonifiedRequest); + + Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(7).getStatusCode(), "Verify Status Code 200 for ChargeOff"); + } + /** * Delete datatable * 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 f55a1c4d7..3f1592b31 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 @@ -996,6 +996,24 @@ public final class BatchHelper { return createTransactionRequest(requestId, reference, "payoutRefund", amount, LocalDate.now(Utils.getZoneIdOfTenant())); } + public static BatchRequest chargeOffRequest(final Long requestId, final Long referenceId) { + return chargeOffRequest(requestId, referenceId, LocalDate.now(Utils.getZoneIdOfTenant())); + } + + public static BatchRequest chargeOffRequest(final Long requestId, final Long referenceId, LocalDate date) { + final BatchRequest br = new BatchRequest(); + + br.setRequestId(requestId); + br.setReference(referenceId); + br.setRelativeUrl(String.format("v1/loans/$.loanId/transactions?command=%s", "charge-off")); + br.setMethod("POST"); + String dateString = date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + br.setBody(String.format("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", " + "\"transactionDate\": \"%s\", \"note\":null}", + dateString)); + + return br; + } + /** * Creates and returns a * {@link org.apache.fineract.batch.command.internal.CreateLoanRescheduleRequestCommandStrategy} request with given