Skip to content

Commit

Permalink
[EWT-78] Add payment refunds support (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
tl-luca-baggi authored May 3, 2023
1 parent 8aa282f commit f84b438
Show file tree
Hide file tree
Showing 21 changed files with 637 additions and 52 deletions.
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=6.1.0
version=6.2.0

# Artifacts properties
sonatype_repository_url=https://s01.oss.sonatype.org/service/local/
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/com/truelayer/java/payments/IPaymentsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.truelayer.java.http.entities.ApiResponse;
import com.truelayer.java.payments.entities.*;
import com.truelayer.java.payments.entities.paymentdetail.PaymentDetail;
import com.truelayer.java.payments.entities.paymentrefund.PaymentRefund;
import java.util.concurrent.CompletableFuture;
import retrofit2.http.*;

Expand Down Expand Up @@ -91,4 +92,34 @@ CompletableFuture<ApiResponse<AuthorizationFlowResponse>> submitConsent(
@POST("/payments/{id}/authorization-flow/actions/form")
CompletableFuture<ApiResponse<AuthorizationFlowResponse>> submitForm(
@Path("id") String paymentId, @Body SubmitFormRequest request);

/**
* Refund a merchant account payment.
* @param paymentId the payment identifier
* @param request a create refund request payload
* @return the response of the <i>Create Payment Refund</i> operation
* @see <a href="https://docs.truelayer.com/reference/create-payment-refund"><i>Create Payment Refund</i> API reference</a>
*/
@POST("/payments/{id}/refunds")
CompletableFuture<ApiResponse<CreatePaymentRefundResponse>> createPaymentRefund(
@Path("id") String paymentId, @Body CreatePaymentRefundRequest request);

/**
* Returns all refunds of a payment.
* @param paymentId the payment identifier
* @return the response of the <i>Get Payment Refunds</i> operation
* @see <a href="https://docs.truelayer.com/reference/get-payment-refunds"><i>Get Payment Refunds</i> API reference</a>
*/
@GET("/payments/{id}/refunds")
CompletableFuture<ApiResponse<ListPaymentRefundsResponse>> listPaymentRefunds(@Path("id") String paymentId);

/**
* Returns refund details.
* @param paymentId the payment identifier
* @return the response of the <i>Get Payment Refund</i> operation
* @see <a href="https://docs.truelayer.com/reference/get-payment-refund"><i>Get Payment Refund</i> API reference</a>
*/
@GET("/payments/{paymentId}/refunds/{refundId}")
CompletableFuture<ApiResponse<PaymentRefund>> getPaymentRefundById(
@Path("paymentId") String paymentId, @Path("refundId") String refundId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.truelayer.java.payments.entities;

import java.util.Map;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Builder
@Getter
@ToString
@EqualsAndHashCode
public class CreatePaymentRefundRequest {
private int amountInMinor;
private String reference;
private Map<String, String> metadata;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.truelayer.java.payments.entities;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@ToString
@EqualsAndHashCode
@Getter
public class CreatePaymentRefundResponse {
private String id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.truelayer.java.payments.entities;

import com.truelayer.java.payments.entities.paymentrefund.PaymentRefund;
import java.util.List;
import lombok.Value;

@Value
public class ListPaymentRefundsResponse {
List<PaymentRefund> items;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.truelayer.java.payments.entities.paymentrefund;

import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class AuthorizedPaymentRefund extends PaymentRefund {
Status status = Status.AUTHORIZED;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.truelayer.java.payments.entities.paymentrefund;

import java.time.ZonedDateTime;
import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class ExecutedPaymentRefund extends PaymentRefund {
Status status = Status.EXECUTED;
ZonedDateTime executedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.truelayer.java.payments.entities.paymentrefund;

import java.time.ZonedDateTime;
import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class FailedPaymentRefund extends PaymentRefund {
Status status = Status.FAILED;
ZonedDateTime failedAt;
String failureReason;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.truelayer.java.payments.entities.paymentrefund;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.truelayer.java.TrueLayerException;
import com.truelayer.java.entities.CurrencyCode;
import java.time.ZonedDateTime;
import java.util.Map;
import lombok.Getter;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "status", defaultImpl = PendingPaymentRefund.class)
@JsonSubTypes({
@JsonSubTypes.Type(value = PendingPaymentRefund.class, name = "pending"),
@JsonSubTypes.Type(value = AuthorizedPaymentRefund.class, name = "authorized"),
@JsonSubTypes.Type(value = ExecutedPaymentRefund.class, name = "executed"),
@JsonSubTypes.Type(value = FailedPaymentRefund.class, name = "failed"),
})
@Getter
public abstract class PaymentRefund {
private String id;
private int amountInMinor;
private CurrencyCode currency;
private String reference;
private Map<String, String> metadata;
private ZonedDateTime createdAt;

@JsonIgnore
public abstract Status getStatus();

@JsonIgnore
public boolean isPending() {
return this instanceof PendingPaymentRefund;
}

@JsonIgnore
public boolean isAuthorized() {
return this instanceof AuthorizedPaymentRefund;
}

@JsonIgnore
public boolean isExecuted() {
return this instanceof ExecutedPaymentRefund;
}

@JsonIgnore
public boolean isFailed() {
return this instanceof FailedPaymentRefund;
}

@JsonIgnore
public PendingPaymentRefund asPendingPaymentRefund() {
if (!isPending()) throw new TrueLayerException(buildErrorMessage());

return (PendingPaymentRefund) this;
}

@JsonIgnore
public AuthorizedPaymentRefund asAuthorizedPaymentRefund() {
if (!isAuthorized()) throw new TrueLayerException(buildErrorMessage());

return (AuthorizedPaymentRefund) this;
}

@JsonIgnore
public ExecutedPaymentRefund asExecutedPaymentRefund() {
if (!isExecuted()) throw new TrueLayerException(buildErrorMessage());

return (ExecutedPaymentRefund) this;
}

@JsonIgnore
public FailedPaymentRefund asFailedPaymentRefund() {
if (!isFailed()) throw new TrueLayerException(buildErrorMessage());

return (FailedPaymentRefund) this;
}

private String buildErrorMessage() {
return String.format("Payment refund is of type %s.", this.getClass().getSimpleName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.truelayer.java.payments.entities.paymentrefund;

import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class PendingPaymentRefund extends PaymentRefund {
Status status = Status.PENDING;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.truelayer.java.payments.entities.paymentrefund;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public enum Status {
PENDING("pending"),
AUTHORIZED("authorized"),
EXECUTED("executed"),
FAILED("failed");

@JsonValue
private final String status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ private void authorizeMandate(AuthorizationFlowResponse authorizationFlowRespons
// first we check the state of the mandate returned by the gateway
assertTrue(
authorizationFlowResponse.isAuthorizing(),
"Mandate status is" + authorizationFlowResponse.getStatus().getStatus());
"Mandate status is " + authorizationFlowResponse.getStatus().getStatus());

// follow the redirect uri and parse its Location HTTP response header
URI redirectUri = authorizationFlowResponse
Expand Down
Loading

0 comments on commit f84b438

Please sign in to comment.