Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
import org.apache.fineract.client.feign.services.UsersApi;
import org.apache.fineract.client.feign.services.WorkingCapitalLoanCobCatchUpApi;
import org.apache.fineract.client.feign.services.WorkingCapitalLoanProductsApi;
import org.apache.fineract.client.feign.services.WorkingCapitalLoanTransactionsApi;
import org.apache.fineract.client.feign.services.WorkingCapitalLoansApi;
import org.apache.fineract.client.feign.services.WorkingDaysApi;

Expand Down Expand Up @@ -757,6 +758,10 @@ public WorkingCapitalLoansApi workingCapitalLoans() {
return create(WorkingCapitalLoansApi.class);
}

public WorkingCapitalLoanTransactionsApi workingCapitalLoanTransactions() {
return create(WorkingCapitalLoanTransactionsApi.class);
}

public WorkingDaysApi workingDays() {
return create(WorkingDaysApi.class);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**
* 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.test.stepdef.loan;

import static org.apache.fineract.client.feign.util.FeignCalls.fail;
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
import static org.assertj.core.api.Assertions.assertThat;

import io.cucumber.datatable.DataTable;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.feign.FineractFeignClient;
import org.apache.fineract.client.feign.util.CallFailedRuntimeException;
import org.apache.fineract.client.models.PostWorkingCapitalLoansResponse;
import org.apache.fineract.client.models.WorkingCapitalLoanCommandTemplateData;
import org.apache.fineract.test.stepdef.AbstractStepDef;
import org.apache.fineract.test.support.TestContextKey;
import org.assertj.core.api.SoftAssertions;

@Slf4j
@RequiredArgsConstructor
public class WorkingCapitalLoanActionTemplateStepDef extends AbstractStepDef {

private final FineractFeignClient fineractClient;

@When("Admin retrieves the working capital loan action template with templateType {string}")
public void retrieveWcLoanActionTemplate(final String templateType) {
final Long loanId = getCreatedLoanId();

final WorkingCapitalLoanCommandTemplateData response = ok(
() -> fineractClient.workingCapitalLoanTransactions().retrieveWorkingCapitalLoanTemplate1(loanId, templateType));
testContext().set(TestContextKey.WC_LOAN_ACTION_TEMPLATE_RESPONSE, response);
log.info("Retrieved WC loan action template for loan ID: {} with templateType: {}", loanId, templateType);
}

@Then("The working capital loan approve template has the following data:")
public void verifyApproveTemplateData(final DataTable table) {
verifyTemplateData(table);
}

@Then("The working capital loan disburse template has the following data:")
public void verifyDisburseTemplateData(final DataTable table) {
verifyTemplateData(table);
}

@Then("Retrieving WC loan action template with invalid templateType {string} results in an error")
public void retrieveTemplateWithInvalidType(final String templateType) {
final Long loanId = getCreatedLoanId();

final CallFailedRuntimeException exception = fail(
() -> fineractClient.workingCapitalLoanTransactions().retrieveWorkingCapitalLoanTemplate1(loanId, templateType));

assertThat(exception.getStatus()).as("HTTP status code").isEqualTo(400);
assertThat(exception.getMessage()).as("Error message should reference the invalid command").contains(templateType);
log.info("Verified WC loan action template retrieval failed with invalid templateType: {}", templateType);
}

@Then("Retrieving WC loan action template without templateType results in an error")
public void retrieveTemplateWithoutType() {
final Long loanId = getCreatedLoanId();

final CallFailedRuntimeException exception = fail(
() -> fineractClient.workingCapitalLoanTransactions().retrieveWorkingCapitalLoanTemplate1(loanId, (String) null));

assertThat(exception.getStatus()).as("HTTP status code").isEqualTo(400);
assertThat(exception.getMessage()).as("Error message should reference unrecognized command").contains("command");
log.info("Verified WC loan action template retrieval failed without templateType");
}

@Then("Retrieving WC loan action template for non-existent loan id {long} results in a 404 error")
public void retrieveTemplateForNonExistentLoan(final Long loanId) {
final CallFailedRuntimeException exception = fail(
() -> fineractClient.workingCapitalLoanTransactions().retrieveWorkingCapitalLoanTemplate1(loanId, "approve"));

assertThat(exception.getStatus()).as("HTTP status code").isEqualTo(404);
assertThat(exception.getMessage()).as("Error message should indicate loan not found").contains("does not exist");
log.info("Verified WC loan action template retrieval failed for non-existent loan ID: {}", loanId);
}

private void verifyTemplateData(final DataTable table) {
final WorkingCapitalLoanCommandTemplateData response = testContext().get(TestContextKey.WC_LOAN_ACTION_TEMPLATE_RESPONSE);
assertThat(response).as("Template response should not be null").isNotNull();

final Map<String, String> expected = table.asMaps().get(0);

SoftAssertions.assertSoftly(softly -> expected.forEach((field, value) -> {
switch (field) {
case "approvalAmount" ->
softly.assertThat(response.getApprovalAmount()).as(field).isNotNull().isEqualByComparingTo(new BigDecimal(value));
case "approvalDate" ->
softly.assertThat(response.getApprovalDate()).as(field).isNotNull().isEqualTo(LocalDate.parse(value));
case "expectedDisbursementDate" ->
softly.assertThat(response.getExpectedDisbursementDate()).as(field).isNotNull().isEqualTo(LocalDate.parse(value));
case "expectedAmount" -> {
if ("null".equals(value)) {
softly.assertThat(response.getExpectedAmount()).as(field).isNull();
} else {
softly.assertThat(response.getExpectedAmount()).as(field).isNotNull().isEqualByComparingTo(new BigDecimal(value));
}
}
case "paymentTypeOptionsPresent" -> {
if (Boolean.parseBoolean(value)) {
softly.assertThat(response.getPaymentTypeOptions()).as(field).isNotNull().isNotEmpty();
} else {
softly.assertThat(response.getPaymentTypeOptions()).as(field).isNullOrEmpty();
}
}
default -> softly.fail("Unknown template field in DataTable: " + field);
}
}));

log.info("Verified WC loan action template data");
}

private Long getCreatedLoanId() {
final PostWorkingCapitalLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
assertThat(loanResponse).as("No loan create response in context — did a previous loan creation step run?").isNotNull();
return loanResponse.getLoanId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,6 @@ public abstract class TestContextKey {
public static final String DELINQUENCY_BUCKET_ID_FOR_UPDATE = "delinquencyBucketIdForUpdate";
public static final String DELINQUENCY_BUCKET_CREATE_REQUEST_FOR_UPDATE = "delinquencyBucketCreateRequestForUpdate";
public static final String DELINQUENCY_BUCKET_CREATE_RESPONSE_FOR_UPDATE_DUPLICATE = "delinquencyBucketUpdateRequestForUpdateDuplicate";

public static final String WC_LOAN_ACTION_TEMPLATE_RESPONSE = "wcLoanActionTemplateResponse";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
@WorkingCapitalLoanActionTemplatesFeature
Feature: Working Capital Loan Action Templates

@TestRailId:C72350
Scenario: Verify Working Capital Loan approve template returns correct defaults for submitted loan - UC1
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
When Admin retrieves the working capital loan action template with templateType "approve"
Then The working capital loan approve template has the following data:
| approvalAmount | approvalDate | expectedDisbursementDate |
| 500 | 2026-01-15 | 2026-01-15 |

@TestRailId:C72351
Scenario: Verify Working Capital Loan approve template reflects modified principal and disbursement date - UC2
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
When Admin modifies the working capital loan with the following data:
| submittedOnDate | expectedDisbursementDate | principalAmount | totalPayment | periodPaymentRate | discount |
| | 25 January 2026 | 300 | | | |
When Admin retrieves the working capital loan action template with templateType "approve"
Then The working capital loan approve template has the following data:
| approvalAmount | approvalDate | expectedDisbursementDate |
| 300 | 2026-01-25 | 2026-01-25 |

@TestRailId:C72352
Scenario: Verify Working Capital Loan approve template reflects modified principal only - UC3
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
When Admin modifies the working capital loan with the following data:
| submittedOnDate | expectedDisbursementDate | principalAmount | totalPayment | periodPaymentRate | discount |
| | | 200 | | | |
When Admin retrieves the working capital loan action template with templateType "approve"
Then The working capital loan approve template has the following data:
| approvalAmount | expectedDisbursementDate |
| 200 | 2026-01-15 |

@TestRailId:C72353
Scenario: Verify Working Capital Loan approve template reflects modified expected disbursement date only - UC4
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
When Admin modifies the working capital loan with the following data:
| submittedOnDate | expectedDisbursementDate | principalAmount | totalPayment | periodPaymentRate | discount |
| | 25 January 2026 | | | | |
When Admin retrieves the working capital loan action template with templateType "approve"
Then The working capital loan approve template has the following data:
| approvalAmount | approvalDate | expectedDisbursementDate |
| 500 | 2026-01-25 | 2026-01-25 |

@TestRailId:C72354
Scenario: Verify Working Capital Loan approve template returns correct approval amount - UC5
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 01 January 2026 | 100 | 100 | 1 | 0 |
Then Working capital loan creation was successful
When Admin retrieves the working capital loan action template with templateType "approve"
Then The working capital loan approve template has the following data:
| approvalAmount |
| 100 |

# TODO: remove @Skip once approval branch is merged
@Skip @TestRailId:C72355
Scenario: Verify Working Capital Loan disburse template returns correct defaults for approved loan - UC6
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
# TODO: add approval step once merged
When Admin retrieves the working capital loan action template with templateType "disburse"
Then The working capital loan disburse template has the following data:
| expectedAmount | expectedDisbursementDate | paymentTypeOptionsPresent |
| 500 | 2026-01-15 | true |

# TODO: remove @Skip once approval branch is merged
@Skip @TestRailId:C72356
Scenario: Verify Working Capital Loan disburse template reflects reduced approved principal - UC7
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 15 January 2026 | 500 | 500 | 1 | 0 |
Then Working capital loan creation was successful
# TODO: add approval step with reduced amount (300) once merged
When Admin retrieves the working capital loan action template with templateType "disburse"
Then The working capital loan disburse template has the following data:
| expectedAmount | expectedDisbursementDate | paymentTypeOptionsPresent |
| 300 | 2026-01-15 | true |

@TestRailId:C72357
Scenario: Verify Working Capital Loan action template with invalid templateType results in an error - UC8
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 01 January 2026 | 100 | 100 | 1 | 0 |
Then Working capital loan creation was successful
Then Retrieving WC loan action template with invalid templateType "invalid" results in an error

@TestRailId:C72358
Scenario: Verify Working Capital Loan action template without templateType results in an error - UC9
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 | totalPayment | periodPaymentRate | discount |
| WCLP | 01 January 2026 | 01 January 2026 | 100 | 100 | 1 | 0 |
Then Working capital loan creation was successful
Then Retrieving WC loan action template without templateType results in an error

@TestRailId:C72359
Scenario Outline: Verify Working Capital Loan action template for non-existent loan returns 404 - UC10
Then Retrieving WC loan action template for non-existent loan id <loanId> results in a 404 error
Examples:
| loanId |
| 999999 |
| 0 |
Loading