Skip to content
Merged
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 @@ -19,20 +19,27 @@
package org.apache.fineract.client.feign;

import feign.Request;
import java.io.Serial;
import java.nio.charset.Charset;
import lombok.Getter;

/**
* Base exception class for Feign client exceptions.
*/
public class FeignException extends RuntimeException {

@Serial
private static final long serialVersionUID = 1L;

private final int status;
private final Request request;
private final byte[] responseBody;
@Getter
private final String developerMessage;
@Getter
private final String userMessage;
@Getter
private final String userMessageGlobalisationCode;

protected FeignException(int status, String message, Request request) {
this(status, message, request, (byte[]) null);
Expand All @@ -49,6 +56,7 @@ protected FeignException(int status, String message, Request request, byte[] res
this.responseBody = responseBody;
this.developerMessage = null;
this.userMessage = null;
this.userMessageGlobalisationCode = null;
}

protected FeignException(int status, String message, Request request, byte[] responseBody, Throwable cause) {
Expand All @@ -58,15 +66,22 @@ protected FeignException(int status, String message, Request request, byte[] res
this.responseBody = responseBody;
this.developerMessage = null;
this.userMessage = null;
this.userMessageGlobalisationCode = null;
}

public FeignException(int status, String message, Request request, byte[] responseBody, String developerMessage, String userMessage) {
this(status, message, request, responseBody, developerMessage, userMessage, null);
}

public FeignException(final int status, final String message, final Request request, final byte[] responseBody,
final String developerMessage, final String userMessage, final String userMessageGlobalisationCode) {
super(message);
this.status = status;
this.request = request;
this.responseBody = responseBody;
this.developerMessage = developerMessage;
this.userMessage = userMessage;
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
}

public int status() {
Expand All @@ -85,14 +100,6 @@ public String responseBodyAsString() {
return responseBody != null ? new String(responseBody, Charset.defaultCharset()) : null;
}

public String getDeveloperMessage() {
return developerMessage;
}

public String getUserMessage() {
return userMessage;
}

@Override
public String getMessage() {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public Exception decode(String methodKey, Response response) {

String developerMessage = extractField(rootNode, "developerMessage");
String userMessage = extractField(rootNode, "userMessage");
final String userMessageGlobalisationCode = extractField(rootNode, "userMessageGlobalisationCode");
String validationErrors = extractValidationErrors(rootNode);

if (developerMessage != null || userMessage != null || validationErrors != null) {
Expand All @@ -49,7 +50,7 @@ public Exception decode(String methodKey, Response response) {
enhancedDeveloperMessage = validationErrors;
}
return new FeignException(response.status(), userMessage != null ? userMessage : enhancedDeveloperMessage,
response.request(), bodyData, enhancedDeveloperMessage, userMessage);
response.request(), bodyData, enhancedDeveloperMessage, userMessage, userMessageGlobalisationCode);
}
} catch (IOException e) {
return defaultDecoder.decode(methodKey, response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ public class CallFailedRuntimeException extends RuntimeException {

private final int status;
private final String developerMessage;
private final String userMessageGlobalisationCode;

public CallFailedRuntimeException(FeignException cause) {
super(createMessage(cause), cause);
this.status = cause.status();
this.developerMessage = extractDeveloperMessage(cause);
this.userMessageGlobalisationCode = cause.getUserMessageGlobalisationCode();
}

private static String createMessage(FeignException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.apache.fineract.test.helper;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
Expand All @@ -29,27 +28,19 @@
import org.apache.fineract.client.models.BatchResponse;
import org.apache.fineract.client.models.Header;
import org.apache.fineract.client.models.LoanAccountLockResponseDTO;
import retrofit2.Response;

public final class ErrorMessageHelper {

public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd MMMM yyyy");
public static final String DATA_INTEGRITY_ISSUE_ENTITY_LINKED_CODE = "error.msg.data.integrity.issue.entity.linked";

private ErrorMessageHelper() {}

public static String requestFailed(Response response) throws IOException {
return String.format("Request failed. Error:%n%s", response.errorBody() != null ? response.errorBody().string() : null);
}

public static String requestFailedWithCode(Response response) {
return String.format("Response has error code: %2d", response.code());
}

public static String batchRequestFailedWithCode(BatchResponse response) {
return String.format("Response has error code: %2d in request: %2d", response.getStatusCode(), response.getRequestId());
}

public static String chargeAppliesToIsInvalid(Enum chargeAppliesTo) {
public static String chargeAppliesToIsInvalid(final Enum<?> chargeAppliesTo) {
return String.format("%s is invalid input for charge applies to field", chargeAppliesTo);
}

Expand Down Expand Up @@ -1075,6 +1066,14 @@ public static String workingCapitalBreachDuplicateNameFailure(final Long id) {
return String.format("Data integrity issue with resource: %d", id);
}

public static String workingCapitalDelinquencyBucketLinkedToLoanProductFailure(final Long id) {
return String.format("Data integrity issue with resource: %d", id);
}

public static String workingCapitalBreachLinkedToLoanProductFailure(final Long id) {
return String.format("Data integrity issue with resource: %d", id);
}

public static String disburseNotApprovedFailure(String status) {
return String.format("Disbursement is not allowed from current status %s", status);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,6 @@ public void checkCreatedBreachHasTheFollowingValues() {
checkBreachData(request, data);
}

/*
* @Then("Get Breach has the following values") public void getBreachHasTheFollowingValues() { final Long id =
* TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID); final WorkingCapitalBreachData data = ok(()
* -> fineractFeignClient.workingCapitalBreaches().retrieveWorkingCapitalBreach(id)); // final
* WorkingCapitalBreachTemplateResponse template = ok( // () ->
* fineractFeignClient.workingCapitalBreaches().retrieveWorkingCapitalBreachTemplate());
* assertThat(data).isNotNull(); /// assertThat(template).isNotNull(); //
* assertThat(template.getBreachFrequencyTypeOptions()).isNotNull().isNotEmpty();
* //assertThat(template.getBreachAmountCalculationTypeOptions()).isNotNull().isNotEmpty(); }
*/

@When("Admin modifies WC Breach With Values")
public void adminModifiesWCBreachWithValues() {
final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID);
Expand Down Expand Up @@ -233,6 +222,44 @@ private void checkDeleteWCBreachNotFoundFailure(final Long id) {
assertThat(exception.getDeveloperMessage()).contains(ErrorMessageHelper.workingCapitalBreachNotFoundFailure(id));
}

public void deleteWCBreachAssignedToLoanEntityFailure(Long id, String errorCode, String errorMessage) {
// final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID);
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalBreaches().deleteWorkingCapitalBreach(id));

assertThat(exception.getStatus()).as(ErrorMessageHelper.incorrectExpectedValueInResponse()).isEqualTo(403);
assertThat(exception.getUserMessageGlobalisationCode()).isEqualTo(errorCode);
assertThat(exception.getDeveloperMessage()) //
.contains(errorMessage) //
.doesNotContain("Cannot delete or update a parent row") //
.doesNotContain("m_wc_loan_product");
}

@Then("Admin failed to delete WC Breach that is assigned to a Working Capital Loan Product")
public void adminFailedToDeleteWCBreachAssignedToLoanProduct() {
final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID);
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalBreaches().deleteWorkingCapitalBreach(id));

assertThat(exception.getStatus()).as(ErrorMessageHelper.incorrectExpectedValueInResponse()).isEqualTo(403);
assertThat(exception.getUserMessageGlobalisationCode()).isEqualTo(ErrorMessageHelper.DATA_INTEGRITY_ISSUE_ENTITY_LINKED_CODE);
assertThat(exception.getDeveloperMessage()) //
.contains(ErrorMessageHelper.workingCapitalBreachLinkedToLoanProductFailure(id)) //
.doesNotContain("Cannot delete or update a parent row") //
.doesNotContain("m_wc_loan_product");
}

@Then("Admin failed to delete WC Breach that is assigned to a Working Capital Loan Account")
public void adminFailedToDeleteWCBreachAssignedToLoanAccount() {
final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID);
String errorMessage = "The request caused a data integrity issue to be fired by the database.";
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalBreaches().deleteWorkingCapitalBreach(id));
assertThat(exception.getStatus()).isEqualTo(403);
assertThat(exception.getMessage()).contains(errorMessage);

}

private void checkRetrieveWCBreachNotFoundFailure(final Long id) {
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalBreaches().retrieveWorkingCapitalBreach(id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,12 @@
import org.apache.fineract.test.support.TestContext;
import org.apache.fineract.test.support.TestContextKey;
import org.assertj.core.api.SoftAssertions;
import org.springframework.beans.factory.annotation.Autowired;

@Slf4j
@RequiredArgsConstructor
public class WorkingCapitalDelinquencyConfigStepDef extends AbstractStepDef {

@Autowired
private WorkingCapitalRequestFactory workingCapitalRequestFactory;

private final WorkingCapitalRequestFactory workingCapitalRequestFactory;
private final FineractFeignClient fineractFeignClient;

@When("Admin Calls Delinquency Template")
Expand Down Expand Up @@ -348,4 +345,18 @@ public void checkDeleteWCDelinquencyBucketDoesntExistFailure(Long id) {
assertThat(exception.getDeveloperMessage()).contains(errorMessage);
}

@Then("Admin failed to delete WC Delinquency Bucket that is assigned to a Working Capital Loan Product")
public void adminFailedToDeleteWCDelinquencyBucketAssignedToLoanProduct() {
final Long id = TestContext.GLOBAL.get(TestContextKey.DELINQUENCY_BUCKET_ID);
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.delinquencyRangeAndBucketsManagement().deleteBucket(id));

assertThat(exception.getStatus()).as(ErrorMessageHelper.incorrectExpectedValueInResponse()).isEqualTo(403);
assertThat(exception.getUserMessageGlobalisationCode()).isEqualTo(ErrorMessageHelper.DATA_INTEGRITY_ISSUE_ENTITY_LINKED_CODE);
assertThat(exception.getDeveloperMessage()) //
.contains(ErrorMessageHelper.workingCapitalDelinquencyBucketLinkedToLoanProductFailure(id)) //
.doesNotContain("Cannot delete or update a parent row") //
.doesNotContain("m_wc_loan_product");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,15 @@ public void createLoanWithBreachNearBreachFromWCLPOverrideAllowedData(DataTable
createWorkingCapitalLoanAccountWithBreachNearBreachData(loanData, breachIdFromWCLP, nearBreachIdFromWCLP);
}

@Then("Admin creates working capital loan with with breach on {string} date")
public void createLoanWithBreachOverrideAllowedWithBreachData(String submittedOnDate) {
final Long breachId = createBreachAndGetId();

final PostWorkingCapitalLoansRequest loansRequest = createWorkingCapitalLoanAccountDefaultRequest(submittedOnDate)
.breachId(breachId);
createWorkingCapitalLoanAccount(loansRequest);
}

@Then("Admin creates working capital loan with with breach and near breach on {string} date")
public void createLoanWithBreachOverrideAllowedWithBreachAndNearBreachData(String submittedOnDate) {
final Long breachId = createBreachAndGetId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,27 +191,13 @@ public void adminRetrieveWCNearBreachWithIncorrectIdFailure(final Integer id) {
checkRetrieveWCNearBreachNotFoundFailure(Long.valueOf(id));
}

@Then("Admin failed to delete WC Near Breach that is still assigned to WC loan product")
@Then("Admin failed to delete WC Near Breach that is still assigned to WC loan product or account")
public void adminDeleteWCBreachAssignedToWCLPFailure() {
final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_NEAR_BREACH_ID);
String errorMessage = "The request caused a data integrity issue to be fired by the database.";
// checkDeleteWCNearBreachFailure(id, 403, errorMessage);
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalNearBreaches().deleteWorkingCapitalNearBreach(id));
assertThat(exception.getStatus()).isEqualTo(403);
// assertThat(exception.getDeveloperMessage()).contains(errorMessage);
assertThat(exception.getMessage()).contains(errorMessage);
}

@Then("Admin failed to delete WC Near Breach that is still assigned to WC loan account")
public void adminDeleteWCBreachAssignedToWCLAccountFailure() {
final Long id = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_NEAR_BREACH_ID);
String errorMessage = "The request caused a data integrity issue to be fired by the database.";
// checkDeleteWCNearBreachFailure(id, 403, errorMessage);
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalNearBreaches().deleteWorkingCapitalNearBreach(id));
assertThat(exception.getStatus()).isEqualTo(403);
// assertThat(exception.getDeveloperMessage()).contains(errorMessage);
assertThat(exception.getMessage()).contains(errorMessage);
}

Expand Down Expand Up @@ -270,13 +256,6 @@ private void checkUpdateWCNearBreachWithInvalidDataFailure(final Long id, final
}

private void checkDeleteWCNearBreachNotFoundFailure(final Long id) {
/*
* final CallFailedRuntimeException exception = fail( () ->
* fineractFeignClient.workingCapitalNearBreaches().deleteWorkingCapitalNearBreach(id));
* assertThat(exception.getStatus()).isEqualTo(404);
* assertThat(exception.getDeveloperMessage()).contains(ErrorMessageHelper.
* workingCapitalNearBreachNotFoundFailure(id));
*/
String errorMessage = ErrorMessageHelper.workingCapitalNearBreachNotFoundFailure(id);
checkDeleteWCNearBreachFailure(id, 404, errorMessage);
}
Expand All @@ -286,18 +265,8 @@ private void checkDeleteWCNearBreachFailure(final Long id, int statusCode, Strin
() -> fineractFeignClient.workingCapitalNearBreaches().deleteWorkingCapitalNearBreach(id));
assertThat(exception.getStatus()).isEqualTo(statusCode);
assertThat(exception.getDeveloperMessage()).contains(errorMessage);
// assertThat(exception.getMessage()).contains(errorMessage);
}

/*
* private void checkDeleteWCNearBreachFailure(final Long id, int statusCode, String errorMessage) { final
* CallFailedRuntimeException exception = fail( () ->
* fineractFeignClient.workingCapitalNearBreaches().deleteWorkingCapitalNearBreach(id));
* assertThat(exception.getStatus()).isEqualTo(statusCode); //
* assertThat(exception.getDeveloperMessage()).contains(errorMessage);
* assertThat(exception.getMessage()).contains(errorMessage); }
*/

private void checkRetrieveWCNearBreachNotFoundFailure(final Long id) {
final CallFailedRuntimeException exception = fail(
() -> fineractFeignClient.workingCapitalNearBreaches().retrieveWorkingCapitalNearBreach(id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import org.apache.fineract.test.helper.WorkingCapitalLoanProductAdvancedAccountingTestHelper;
import org.apache.fineract.test.helper.WorkingCapitalLoanProductAdvancedAccountingTestHelper.AdvancedAccountingExpectation;
import org.apache.fineract.test.stepdef.AbstractStepDef;
import org.apache.fineract.test.support.TestContext;
import org.apache.fineract.test.support.TestContextKey;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -410,6 +411,32 @@ public void createWorkingCapitalLoanProductWithBreachAndNearBreachConfig(final D
checkWorkingCapitalLoanProductCreate();
}

@When("Admin creates a new Working Capital Loan Product with existing WC Delinquency Bucket")
public void createWorkingCapitalLoanProductWithExistingDelinquencyBucket() {
final Long bucketId = TestContext.GLOBAL.get(TestContextKey.DELINQUENCY_BUCKET_ID);
final String name = DefaultWorkingCapitalLoanProduct.WCLP.getName() + Utils.randomStringGenerator("_", 10);
final PostWorkingCapitalLoanProductsRequest request = workingCapitalRequestFactory.defaultWorkingCapitalLoanProductRequest() //
.name(name) //
.delinquencyBucketId(bucketId);
final PostWorkingCapitalLoanProductsResponse response = createWorkingCapitalLoanProduct(request);
testContext().set(TestContextKey.WORKING_CAPITAL_LOAN_PRODUCT_CREATE_RESPONSE, response);
testContext().set(TestContextKey.WORKING_CAPITAL_LOAN_PRODUCT_CREATE_REQUEST, request);
checkWorkingCapitalLoanProductCreate();
}

@When("Admin creates a new Working Capital Loan Product with existing WC Breach")
public void createWorkingCapitalLoanProductWithExistingBreach() {
final Long breachId = TestContext.INSTANCE.get(TestContextKey.WORKING_CAPITAL_BREACH_ID);
final String name = DefaultWorkingCapitalLoanProduct.WCLP.getName() + Utils.randomStringGenerator("_", 10);
final PostWorkingCapitalLoanProductsRequest request = workingCapitalRequestFactory.defaultWorkingCapitalLoanProductRequest() //
.name(name) //
.breachId(breachId);
final PostWorkingCapitalLoanProductsResponse response = createWorkingCapitalLoanProduct(request);
testContext().set(TestContextKey.WORKING_CAPITAL_LOAN_PRODUCT_CREATE_RESPONSE, response);
testContext().set(TestContextKey.WORKING_CAPITAL_LOAN_PRODUCT_CREATE_REQUEST, request);
checkWorkingCapitalLoanProductCreate();
}

@When("Admin creates a new Working Capital Loan Product with external-id")
public void createWorkingCapitalLoanProductWithExternalId() {
final String workingCapitalProductDefaultName = DefaultWorkingCapitalLoanProduct.WCLP.getName()
Expand Down
Loading
Loading