Skip to content

Commit

Permalink
Add reverse payment (#423)
Browse files Browse the repository at this point in the history
  • Loading branch information
armando-rodriguez-cko authored Jul 17, 2024
1 parent 1eddd14 commit 3dbf1e6
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 33 deletions.
74 changes: 41 additions & 33 deletions src/main/java/com/checkout/OAuthScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/checkout/payments/PaymentsClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/checkout/payments/PaymentsClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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>>() {
Expand Down Expand Up @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/checkout/payments/ReverseRequest.java
Original file line number Diff line number Diff line change
@@ -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;

}
19 changes: 19 additions & 0 deletions src/main/java/com/checkout/payments/ReverseResponse.java
Original file line number Diff line number Diff line change
@@ -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;

}
62 changes: 62 additions & 0 deletions src/test/java/com/checkout/payments/PaymentsClientImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
80 changes: 80 additions & 0 deletions src/test/java/com/checkout/payments/ReversePaymentsTestIT.java
Original file line number Diff line number Diff line change
@@ -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());

}

}

0 comments on commit 3dbf1e6

Please sign in to comment.