Skip to content

Commit

Permalink
feat(ACL-195): Adds cancel payment support (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
dili91 authored Sep 27, 2024
1 parent 42ffeab commit 9eb181b
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 1 deletion.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Main properties
group=com.truelayer
archivesBaseName=truelayer-java
version=14.1.0
version=14.2.0

# Artifacts properties
sonatype_repository_url=https://s01.oss.sonatype.org/service/local/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ CompletableFuture<ApiResponse<Void>> disableSweeping(
@HeaderMap Map<String, String> headers,
@Path("merchantAccountId") String merchantAccountId);

/**
* Get the payment sources from which the merchant account has received payment
* @param scopes the scopes to be used by the underlying Oauth token
* @param merchantAccountId the id of the merchant account
* @param userId the id of the user
* @return The list of payment sources from which the merchant account has received payment
* @see <a href="https://docs.truelayer.com/reference/get-merchant-account-payment-sources"><i>Get payment sources</i> API reference</a>
*/
@GET("/merchant-accounts/{merchantAccountId}/payment-sources")
CompletableFuture<ApiResponse<ListPaymentSourcesResponse>> listPaymentSources(
@Tag RequestScopes scopes,
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/truelayer/java/payments/IPaymentsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ CompletableFuture<ApiResponse<CreatePaymentResponse>> createPayment(
@GET("/payments/{id}")
CompletableFuture<ApiResponse<PaymentDetail>> getPayment(@Tag RequestScopes scopes, @Path("id") String paymentId);

/**
* Cancel a payment.
* @param scopes the scopes to be used by the underlying Oauth token
* @param headers map representing custom HTTP headers to be sent
* @param paymentId the payment identifier
* @return an empty response in case of success
* @see <a href="https://docs.truelayer.com/reference/cancel-payment"><i>Cancel Payment</i> API reference</a>
*/
@POST("/payments/{id}/actions/cancel")
CompletableFuture<ApiResponse<Void>> cancelPayment(
@Tag RequestScopes scopes, @HeaderMap Map<String, String> headers, @Path("id") String paymentId);

/**
* Starts an authorization flow for a given payment resource.
* @param scopes the scopes to be used by the underlying Oauth token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public interface IPaymentsHandler {

CompletableFuture<ApiResponse<PaymentDetail>> getPayment(String paymentId);

CompletableFuture<ApiResponse<Void>> cancelPayment(String paymentId);

CompletableFuture<ApiResponse<Void>> cancelPayment(Headers headers, String paymentId);

CompletableFuture<ApiResponse<AuthorizationFlowResponse>> startAuthorizationFlow(
String paymentId, StartAuthorizationFlowRequest request);

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/truelayer/java/payments/PaymentsHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ public CompletableFuture<ApiResponse<PaymentDetail>> getPayment(String paymentId
return paymentsApi.getPayment(getRequestScopes(), paymentId);
}

@Override
public CompletableFuture<ApiResponse<Void>> cancelPayment(String paymentId) {
return paymentsApi.cancelPayment(getRequestScopes(), emptyMap(), paymentId);
}

@Override
public CompletableFuture<ApiResponse<Void>> cancelPayment(Headers headers, String paymentId) {
return paymentsApi.cancelPayment(getRequestScopes(), toMap(headers), paymentId);
}

@Override
public CompletableFuture<ApiResponse<AuthorizationFlowResponse>> startAuthorizationFlow(
String paymentId, StartAuthorizationFlowRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,27 @@ public void shouldCreateAPaymentRefundAndGetRefundDetails() {
paymentRefundApiResponse.getData().getMetadata());
}

@SneakyThrows
@Test
@DisplayName("It should create a payment and cancel it")
public void shouldCreateAPaymentAndCancelIt() {
// create payment
CreatePaymentRequest paymentRequest =
buildPaymentRequestWithProviderSelection(buildPreselectedProviderSelection(), CurrencyCode.GBP);

ApiResponse<CreatePaymentResponse> createPaymentResponse =
tlClient.payments().createPayment(paymentRequest).get();

assertNotError(createPaymentResponse);
assertTrue(createPaymentResponse.getData().isAuthorizationRequired());

// Cancel the payment
ApiResponse<Void> cancelPaymentResponse = tlClient.payments()
.cancelPayment(createPaymentResponse.getData().getId())
.get();
assertNotError(cancelPaymentResponse);
}

private PreselectedProviderSelection buildPreselectedProviderSelection() {
return ProviderSelection.preselected()
.providerId(PROVIDER_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,30 @@ public void shouldReturnAPaymentDetail(PaymentMethod.Type paymentMethodType, Sta
assertEquals(expected, response.getData());
}

@Test
@DisplayName("It should cancel a payment")
@SneakyThrows
public void shouldCancelPayment() {
RequestStub.New()
.method("post")
.path(urlPathEqualTo("/connect/token"))
.status(200)
.bodyFile("auth/200.access_token.json")
.build();
RequestStub.New()
.method("post")
.path(urlPathEqualTo("/payments/" + A_PAYMENT_ID + "/actions/cancel"))
.withAuthorization()
.status(202)
.build();

ApiResponse<Void> response =
tlClient.payments().cancelPayment(A_PAYMENT_ID).get();

verifyGeneratedToken(Collections.singletonList(PAYMENTS));
assertNotError(response);
}

@Test
@DisplayName("It should return an error if a payment is not found")
@SneakyThrows
Expand Down

0 comments on commit 9eb181b

Please sign in to comment.