From 9eb181bf999f34d56a0b7d0b39c931210ec29e7d Mon Sep 17 00:00:00 2001 From: Andrea Di Lisio Date: Fri, 27 Sep 2024 11:49:03 +0200 Subject: [PATCH] feat(ACL-195): Adds cancel payment support (#315) --- gradle.properties | 2 +- .../IMerchantAccountsApi.java | 8 +++++++ .../truelayer/java/payments/IPaymentsApi.java | 12 ++++++++++ .../java/payments/IPaymentsHandler.java | 4 ++++ .../java/payments/PaymentsHandler.java | 10 ++++++++ .../acceptance/PaymentsAcceptanceTests.java | 21 ++++++++++++++++ .../integration/PaymentsIntegrationTests.java | 24 +++++++++++++++++++ 7 files changed, 80 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index bd5c7eb7..93589d73 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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/ diff --git a/src/main/java/com/truelayer/java/merchantaccounts/IMerchantAccountsApi.java b/src/main/java/com/truelayer/java/merchantaccounts/IMerchantAccountsApi.java index 02f06309..17e0109c 100644 --- a/src/main/java/com/truelayer/java/merchantaccounts/IMerchantAccountsApi.java +++ b/src/main/java/com/truelayer/java/merchantaccounts/IMerchantAccountsApi.java @@ -102,6 +102,14 @@ CompletableFuture> disableSweeping( @HeaderMap Map 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 Get payment sources API reference + */ @GET("/merchant-accounts/{merchantAccountId}/payment-sources") CompletableFuture> listPaymentSources( @Tag RequestScopes scopes, diff --git a/src/main/java/com/truelayer/java/payments/IPaymentsApi.java b/src/main/java/com/truelayer/java/payments/IPaymentsApi.java index e94268ac..6d09d19e 100644 --- a/src/main/java/com/truelayer/java/payments/IPaymentsApi.java +++ b/src/main/java/com/truelayer/java/payments/IPaymentsApi.java @@ -38,6 +38,18 @@ CompletableFuture> createPayment( @GET("/payments/{id}") CompletableFuture> 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 Cancel Payment API reference + */ + @POST("/payments/{id}/actions/cancel") + CompletableFuture> cancelPayment( + @Tag RequestScopes scopes, @HeaderMap Map 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 diff --git a/src/main/java/com/truelayer/java/payments/IPaymentsHandler.java b/src/main/java/com/truelayer/java/payments/IPaymentsHandler.java index 36a8c4e1..c06757c0 100644 --- a/src/main/java/com/truelayer/java/payments/IPaymentsHandler.java +++ b/src/main/java/com/truelayer/java/payments/IPaymentsHandler.java @@ -19,6 +19,10 @@ public interface IPaymentsHandler { CompletableFuture> getPayment(String paymentId); + CompletableFuture> cancelPayment(String paymentId); + + CompletableFuture> cancelPayment(Headers headers, String paymentId); + CompletableFuture> startAuthorizationFlow( String paymentId, StartAuthorizationFlowRequest request); diff --git a/src/main/java/com/truelayer/java/payments/PaymentsHandler.java b/src/main/java/com/truelayer/java/payments/PaymentsHandler.java index dc3e7c02..84ec3145 100644 --- a/src/main/java/com/truelayer/java/payments/PaymentsHandler.java +++ b/src/main/java/com/truelayer/java/payments/PaymentsHandler.java @@ -44,6 +44,16 @@ public CompletableFuture> getPayment(String paymentId return paymentsApi.getPayment(getRequestScopes(), paymentId); } + @Override + public CompletableFuture> cancelPayment(String paymentId) { + return paymentsApi.cancelPayment(getRequestScopes(), emptyMap(), paymentId); + } + + @Override + public CompletableFuture> cancelPayment(Headers headers, String paymentId) { + return paymentsApi.cancelPayment(getRequestScopes(), toMap(headers), paymentId); + } + @Override public CompletableFuture> startAuthorizationFlow( String paymentId, StartAuthorizationFlowRequest request) { diff --git a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java index 9b2646b9..06ea5ec1 100644 --- a/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java +++ b/src/test/java/com/truelayer/java/acceptance/PaymentsAcceptanceTests.java @@ -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 = + tlClient.payments().createPayment(paymentRequest).get(); + + assertNotError(createPaymentResponse); + assertTrue(createPaymentResponse.getData().isAuthorizationRequired()); + + // Cancel the payment + ApiResponse cancelPaymentResponse = tlClient.payments() + .cancelPayment(createPaymentResponse.getData().getId()) + .get(); + assertNotError(cancelPaymentResponse); + } + private PreselectedProviderSelection buildPreselectedProviderSelection() { return ProviderSelection.preselected() .providerId(PROVIDER_ID) diff --git a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java index eff18482..405b900c 100644 --- a/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java +++ b/src/test/java/com/truelayer/java/integration/PaymentsIntegrationTests.java @@ -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 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