diff --git a/src/main/java/com/checkout/OAuthScope.java b/src/main/java/com/checkout/OAuthScope.java index 46a5635a..75e22fdd 100644 --- a/src/main/java/com/checkout/OAuthScope.java +++ b/src/main/java/com/checkout/OAuthScope.java @@ -2,51 +2,59 @@ public enum OAuthScope { - VAULT("vault"), - VAULT_INSTRUMENTS("vault:instruments"), - VAULT_TOKENIZATION("vault:tokenization"), + ACCOUNTS("accounts"), + BALANCES("balances"), + BALANCES_VIEW("balances:view"), + CARD_MANAGEMENT("card-management"), + DISPUTES("disputes"), + DISPUTES_ACCEPT("disputes:accept"), + DISPUTES_PROVIDE_EVIDENCE("disputes:provide-evidence"), + DISPUTES_VIEW("disputes:view"), + FILES("files"), + FILES_DOWNLOAD("files:download"), + FILES_RETRIEVE("files:retrieve"), + FILES_UPLOAD("files:upload"), + FINANCIAL_ACTIONS("financial-actions"), + FINANCIAL_ACTIONS_VIEW("financial-actions:view"), + FLOW("flow"), + FLOW_EVENTS("flow:events"), + FLOW_WORKFLOWS("flow:workflows"), + FX("fx"), GATEWAY("gateway"), GATEWAY_PAYMENT("gateway:payment"), - GATEWAY_PAYMENT_DETAILS("gateway:payment-details"), GATEWAY_PAYMENT_AUTHORIZATION("gateway:payment-authorizations"), - GATEWAY_PAYMENT_VOIDS("gateway:payment-voids"), GATEWAY_PAYMENT_CAPTURES("gateway:payment-captures"), + GATEWAY_PAYMENT_CANCELLATIONS("gateway:payment-cancellations"), + GATEWAY_PAYMENT_DETAILS("gateway:payment-details"), GATEWAY_PAYMENT_REFUNDS("gateway:payment-refunds"), - FX("fx"), + GATEWAY_PAYMENT_VOIDS("gateway:payment-voids"), + ISSUING_CARD_MANAGEMENT_READ("issuing:card-management-read"), + ISSUING_CARD_MANAGEMENT_WRITE("issuing:card-management-write"), + ISSUING_CARD_MGMT("issuing:card-mgmt"), + ISSUING_CLIENT("issuing:client"), + ISSUING_CONTROLS_READ("issuing:controls-read"), + ISSUING_CONTROLS_WRITE("issuing:controls-write"), + ISSUING_TRANSACTIONS_READ("issuing:transactions-read"), + ISSUING_TRANSACTIONS_WRITE("issuing:transactions-write"), + MARKETPLACE("marketplace"), + MIDDLEWARE("middleware"), + MIDDLEWARE_MERCHANTS_PUBLIC("middleware:merchants-public"), + MIDDLEWARE_MERCHANTS_SECRET("middleware:merchants-secret"), + PAYMENT_CONTEXTS("gateway:payment-contexts"), + PAYMENT_SESSIONS("payment-sessions"), PAYOUTS_BANK_DETAILS("payouts:bank-details"), + REPORTS("reports"), + REPORTS_VIEW("reports:view"), SESSIONS_APP("sessions:app"), SESSIONS_BROWSER("sessions:browser"), - DISPUTES("disputes"), - DISPUTES_VIEW("disputes:view"), - DISPUTES_PROVIDE_EVIDENCE("disputes:provide-evidence"), - DISPUTES_ACCEPT("disputes:accept"), - MARKETPLACE("marketplace"), - ACCOUNTS("accounts"), - FLOW("flow"), - FLOW_WORKFLOWS("flow:workflows"), - FLOW_EVENTS("flow:events"), - FILES("files"), - FILES_RETRIEVE("files:retrieve"), - FILES_UPLOAD("files:upload"), - FILES_DOWNLOAD("files:download"), + TRANSACTIONS("transactions"), TRANSFERS("transfers"), TRANSFERS_CREATE("transfers:create"), TRANSFERS_VIEW("transfers:view"), - BALANCES("balances"), - BALANCES_VIEW("balances:view"), - MIDDLEWARE("middleware"), - MIDDLEWARE_MERCHANTS_SECRET("middleware:merchants-secret"), - MIDDLEWARE_MERCHANTS_PUBLIC("middleware:merchants-public"), - REPORTS("reports"), - REPORTS_VIEW("reports:view"), + VAULT("vault"), VAULT_CARD_METADATA("vault:card-metadata"), - FINANCIAL_ACTIONS("financial-actions"), - FINANCIAL_ACTIONS_VIEW("financial-actions:view"), - ISSUING_CLIENT("issuing:client"), - ISSUING_CARD_MGMT("issuing:card-mgmt"), - ISSUING_CONTROLS_READ("issuing:controls-read"), - ISSUING_CONTROLS_WRITE("issuing:controls-write"), - PAYMENT_CONTEXTS("Payment Contexts"); + VAULT_INSTRUMENTS("vault:instruments"), + VAULT_TOKENIZATION("vault:tokenization"); private final String scope; diff --git a/src/main/java/com/checkout/payments/PaymentsClient.java b/src/main/java/com/checkout/payments/PaymentsClient.java index 2807d01a..64297f82 100644 --- a/src/main/java/com/checkout/payments/PaymentsClient.java +++ b/src/main/java/com/checkout/payments/PaymentsClient.java @@ -48,6 +48,14 @@ public interface PaymentsClient { CompletableFuture<RefundResponse> refundPayment(String paymentId, RefundRequest refundRequest, String idempotencyKey); + CompletableFuture<ReverseResponse> reversePayment(String paymentId); + + CompletableFuture<ReverseResponse> reversePayment(String paymentId, String idempotencyKey); + + CompletableFuture<ReverseResponse> reversePayment(String paymentId, ReverseRequest reverseRequest); + + CompletableFuture<ReverseResponse> reversePayment(String paymentId, ReverseRequest reverseRequest, String idempotencyKey); + CompletableFuture<VoidResponse> voidPayment(String paymentId); CompletableFuture<VoidResponse> voidPayment(String paymentId, String idempotencyKey); diff --git a/src/main/java/com/checkout/payments/PaymentsClientImpl.java b/src/main/java/com/checkout/payments/PaymentsClientImpl.java index 52cd833e..4dac7661 100644 --- a/src/main/java/com/checkout/payments/PaymentsClientImpl.java +++ b/src/main/java/com/checkout/payments/PaymentsClientImpl.java @@ -23,6 +23,7 @@ public final class PaymentsClientImpl extends AbstractClient implements Payments private static final String CAPTURES_PATH = "captures"; private static final String AUTHORIZATIONS_PATH = "authorizations"; private static final String REFUNDS_PATH = "refunds"; + private static final String REVERSALS_PATH = "reversals"; private static final String VOIDS_PATH = "voids"; private static final Type PAYMENT_ACTIONS_TYPE = new TypeToken<ItemsResponse<PaymentAction>>() { @@ -134,6 +135,30 @@ public CompletableFuture<RefundResponse> refundPayment(final String paymentId, f return apiClient.postAsync(buildPath(PAYMENTS_PATH, paymentId, REFUNDS_PATH), sdkAuthorization(), RefundResponse.class, refundRequest, idempotencyKey); } + @Override + public CompletableFuture<ReverseResponse> reversePayment(final String paymentId) { + validateParams("paymentId", paymentId); + return apiClient.postAsync(buildPath(PAYMENTS_PATH, paymentId, REVERSALS_PATH), sdkAuthorization(), ReverseResponse.class, null, null); + } + + @Override + public CompletableFuture<ReverseResponse> reversePayment(final String paymentId, final String idempotencyKey) { + validateParams("paymentId", paymentId, "idempotencyKey", idempotencyKey); + return apiClient.postAsync(buildPath(PAYMENTS_PATH, paymentId, REVERSALS_PATH), sdkAuthorization(), ReverseResponse.class, null, idempotencyKey); + } + + @Override + public CompletableFuture<ReverseResponse> reversePayment(final String paymentId, final ReverseRequest reverseRequest) { + validateParams("paymentId", paymentId, "reverseRequest", reverseRequest); + return apiClient.postAsync(buildPath(PAYMENTS_PATH, paymentId, REVERSALS_PATH), sdkAuthorization(), ReverseResponse.class, reverseRequest, null); + } + + @Override + public CompletableFuture<ReverseResponse> reversePayment(final String paymentId, final ReverseRequest reverseRequest, final String idempotencyKey) { + validateParams("paymentId", paymentId, "reverseRequest", reverseRequest, "idempotencyKey", idempotencyKey); + return apiClient.postAsync(buildPath(PAYMENTS_PATH, paymentId, REVERSALS_PATH), sdkAuthorization(), ReverseResponse.class, reverseRequest, idempotencyKey); + } + @Override public CompletableFuture<VoidResponse> voidPayment(final String paymentId) { validateParams("paymentId", paymentId); diff --git a/src/main/java/com/checkout/payments/ReverseRequest.java b/src/main/java/com/checkout/payments/ReverseRequest.java new file mode 100644 index 00000000..3238ea5d --- /dev/null +++ b/src/main/java/com/checkout/payments/ReverseRequest.java @@ -0,0 +1,20 @@ +package com.checkout.payments; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReverseRequest { + + private String reference; + + private Map<String, String> metadata; + +} diff --git a/src/main/java/com/checkout/payments/ReverseResponse.java b/src/main/java/com/checkout/payments/ReverseResponse.java new file mode 100644 index 00000000..70cf557d --- /dev/null +++ b/src/main/java/com/checkout/payments/ReverseResponse.java @@ -0,0 +1,19 @@ +package com.checkout.payments; + +import com.checkout.common.Resource; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ReverseResponse extends Resource { + + @SerializedName("action_id") + private String actionId; + + private String reference; + +} diff --git a/src/test/java/com/checkout/payments/PaymentsClientImplTest.java b/src/test/java/com/checkout/payments/PaymentsClientImplTest.java index 9a22053c..61b28e31 100644 --- a/src/test/java/com/checkout/payments/PaymentsClientImplTest.java +++ b/src/test/java/com/checkout/payments/PaymentsClientImplTest.java @@ -408,6 +408,68 @@ void shouldRefundPayment_request_idempotencyKey() throws ExecutionException, Int } + @Test + void shouldReversePayment() throws ExecutionException, InterruptedException { + + final ReverseResponse response = new ReverseResponse(); + + when(apiClient.postAsync(eq("payments/123456/reversals"), any(SdkAuthorization.class), eq(ReverseResponse.class), isNull(), isNull())) + .thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture<ReverseResponse> future = paymentsClient.reversePayment("123456"); + + assertNotNull(future.get()); + assertEquals(response, future.get()); + + } + + @Test + void shouldReversePayment_idempotencyKey() throws ExecutionException, InterruptedException { + + final ReverseResponse response = new ReverseResponse(); + + when(apiClient.postAsync(eq("payments/123456/reversals"), any(SdkAuthorization.class), eq(ReverseResponse.class), isNull(), eq("123"))) + .thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture<ReverseResponse> future = paymentsClient.reversePayment("123456", "123"); + + assertNotNull(future.get()); + assertEquals(response, future.get()); + + } + + @Test + void shouldReversePayment_request() throws ExecutionException, InterruptedException { + + final ReverseRequest request = new ReverseRequest(); + final ReverseResponse response = new ReverseResponse(); + + when(apiClient.postAsync(eq("payments/123456/reversals"), any(SdkAuthorization.class), eq(ReverseResponse.class), eq(request), isNull())) + .thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture<ReverseResponse> future = paymentsClient.reversePayment("123456", request); + + assertNotNull(future.get()); + assertEquals(response, future.get()); + + } + + @Test + void shouldReversePayment_request_idempotencyKey() throws ExecutionException, InterruptedException { + + final ReverseRequest request = new ReverseRequest(); + final ReverseResponse response = new ReverseResponse(); + + when(apiClient.postAsync(eq("payments/123456/reversals"), any(SdkAuthorization.class), eq(ReverseResponse.class), eq(request), eq("123"))) + .thenReturn(CompletableFuture.completedFuture(response)); + + final CompletableFuture<ReverseResponse> future = paymentsClient.reversePayment("123456", request, "123"); + + assertNotNull(future.get()); + assertEquals(response, future.get()); + + } + @Test void shouldVoidPayment() throws ExecutionException, InterruptedException { diff --git a/src/test/java/com/checkout/payments/ReversePaymentsTestIT.java b/src/test/java/com/checkout/payments/ReversePaymentsTestIT.java new file mode 100644 index 00000000..460544cb --- /dev/null +++ b/src/test/java/com/checkout/payments/ReversePaymentsTestIT.java @@ -0,0 +1,80 @@ +package com.checkout.payments; + +import com.checkout.payments.request.PaymentRequest; +import com.checkout.payments.request.source.RequestCardSource; +import com.checkout.payments.response.PaymentResponse; +import com.checkout.payments.sender.PaymentCorporateSender; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static com.checkout.CardSourceHelper.getCardSourcePayment; +import static com.checkout.CardSourceHelper.getCorporateSender; +import static com.checkout.CardSourceHelper.getRequestCardSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ReversePaymentsTestIT extends AbstractPaymentsTestIT { + + @Test + void shouldReversePayment() { + + final RequestCardSource source = getRequestCardSource(); + final PaymentCorporateSender sender = getCorporateSender(); + final PaymentRequest request = getCardSourcePayment(source, sender, false); + + // payment + final PaymentResponse paymentResponse = makeCardPayment(request); + assertNotNull(paymentResponse.getLink("capture")); + + final String reference = UUID.randomUUID().toString(); + + // reverse + final ReverseRequest reverseRequest = ReverseRequest.builder() + .reference(reference) + .build(); + + final ReverseResponse reverseResponse = blocking(() -> paymentsClient.reversePayment(paymentResponse.getId(), reverseRequest)); + + assertNotNull(reverseResponse); + assertNotNull(reverseResponse.getReference()); + assertEquals(reference, reverseResponse.getReference()); + + } + + @Test + void shouldReversePayment_idempotencyKey() { + + final RequestCardSource source = getRequestCardSource(); + final PaymentCorporateSender sender = getCorporateSender(); + final PaymentRequest request = getCardSourcePayment(source, sender, false); + + // payment + final PaymentResponse paymentResponse = makeCardPayment(request); + assertNotNull(paymentResponse.getLink("capture")); + + final String reference = UUID.randomUUID().toString(); + final String idempotencyKey = UUID.randomUUID().toString(); + + // reverse + final ReverseRequest reverseRequest = ReverseRequest.builder() + .reference(reference) + .build(); + + final ReverseResponse reverseResponse = blocking(() -> paymentsClient.reversePayment(paymentResponse.getId(), reverseRequest, idempotencyKey)); + + assertNotNull(reverseResponse); + assertNotNull(reverseResponse.getReference()); + assertEquals(reference, reverseResponse.getReference()); + + final ReverseResponse reverseResponse_2 = blocking(() -> paymentsClient.reversePayment(paymentResponse.getId(), reverseRequest, idempotencyKey)); + + assertNotNull(reverseResponse_2); + assertNotNull(reverseResponse_2.getReference()); + assertEquals(reference, reverseResponse_2.getReference()); + + assertEquals(reverseResponse.getActionId(), reverseResponse_2.getActionId()); + + } + +}