Skip to content

Commit

Permalink
[EWT-85] fixes existing items returned by the `merchant-accounts/{id}…
Browse files Browse the repository at this point in the history
…/transactions` endpoint and add support for refunds (#180)
  • Loading branch information
dili91 authored Jan 13, 2023
1 parent 34af0eb commit ede7ff0
Show file tree
Hide file tree
Showing 20 changed files with 703 additions and 43 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=5.0.0
version=6.0.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
@@ -1,7 +1,6 @@
package com.truelayer.java.merchantaccounts.entities.transactions;

import com.truelayer.java.entities.CurrencyCode;
import com.truelayer.java.entities.Remitter;
import java.time.ZonedDateTime;
import lombok.EqualsAndHashCode;
import lombok.Value;
Expand All @@ -18,7 +17,7 @@ public class ExternalPayment extends Transaction {

int amountInMinor;

Transaction.Status status;
Transaction.Status status = Status.SETTLED;

ZonedDateTime settledAt;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class MerchantAccountPayment extends Transaction {

int amountInMinor;

Transaction.Status status;
Transaction.Status status = Status.SETTLED;

ZonedDateTime settledAt;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,4 @@ public class PaymentSource {
List<AccountIdentifier> accountIdentifiers;

String accountHolderName;

String userId;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package com.truelayer.java.merchantaccounts.entities.transactions;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonValue;
import com.truelayer.java.entities.CurrencyCode;
import com.truelayer.java.payments.entities.beneficiary.Beneficiary;
import com.truelayer.java.merchantaccounts.entities.transactions.beneficiary.Beneficiary;
import java.time.ZonedDateTime;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Value;

/**
* DTO class that represents both <code>pending</code> and <code>executed</code> payouts.
* We're not defining explicit variants in this case based on the <code>status</code> field because
* it seems that the library used for deserialization is not capable of handling more than one deserialization hints,
* which would be required in this case to first select a DTO based on the <code>type</code> and then on the
* <code>status</code> fields.
*/
@Value
@EqualsAndHashCode(callSuper = false)
public class Payout extends Transaction {
Expand All @@ -22,20 +30,25 @@ public class Payout extends Transaction {

int amountInMinor;

/**
* Represents the status of the payout.
* Either <code>pending</code> or <code>executed</code>.
*/
Transaction.Status status;

ZonedDateTime createdAt;

ZonedDateTime settledAt;
ZonedDateTime executedAt;

Beneficiary beneficiary;

Payout.ContextCode contextCode;

String payoutId;

public Optional<ZonedDateTime> getSettledAt() {
return Optional.ofNullable(settledAt);
@JsonGetter
public Optional<ZonedDateTime> getExecutedAt() {
return Optional.ofNullable(executedAt);
}

@RequiredArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.truelayer.java.merchantaccounts.entities.transactions;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.truelayer.java.entities.CurrencyCode;
import java.time.ZonedDateTime;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import lombok.Value;

@Value
@EqualsAndHashCode(callSuper = false)
public class Refund extends Transaction {
Type type = Type.REFUND;

String id;

CurrencyCode currency;

int amountInMinor;

/**
* Represents the refund status, either <code>pending</code> or <code>executed</code>.
*/
Transaction.Status status;

ZonedDateTime createdAt;

ZonedDateTime executedAt;

com.truelayer.java.merchantaccounts.entities.transactions.beneficiary.PaymentSource beneficiary;

Payout.ContextCode contextCode;

String refundId;

String paymentId;

@JsonGetter
public Optional<ZonedDateTime> getExecutedAt() {
return Optional.ofNullable(executedAt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.truelayer.java.merchantaccounts.entities.transactions;

import com.truelayer.java.merchantaccounts.entities.transactions.accountidentifier.AccountIdentifier;
import java.util.List;
import lombok.Value;

/**
* A transaction item specific DTO for external payments
* representing account identifiers of either IBAN or SCAN type.
* This is deliberately different from the more generic
* {@link com.truelayer.java.entities.Remitter} class.
*/
@Value
public class Remitter {
private List<AccountIdentifier> accountIdentifiers;

private String accountHolderName;

private String reference;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@JsonSubTypes.Type(value = MerchantAccountPayment.class, name = "merchant_account_payment"),
@JsonSubTypes.Type(value = ExternalPayment.class, name = "external_payment"),
@JsonSubTypes.Type(value = Payout.class, name = "payout"),
@JsonSubTypes.Type(value = Refund.class, name = "refund"),
})
@Getter
public abstract class Transaction {
Expand All @@ -24,7 +25,8 @@ public abstract class Transaction {
public enum Type {
MERCHANT_ACCOUNT_PAYMENT("merchant_account_payment"),
EXTERNAL_PAYMENT("external_payment"),
PAYOUT("payout");
PAYOUT("payout"),
REFUND("refund");

@JsonValue
private final String type;
Expand All @@ -33,6 +35,7 @@ public enum Type {
@RequiredArgsConstructor
@Getter
public enum Status {
EXECUTED("executed"),
SETTLED("settled"),
PENDING("pending");

Expand All @@ -55,6 +58,11 @@ public boolean isPayout() {
return this instanceof Payout;
}

@JsonIgnore
public boolean isRefund() {
return this instanceof Refund;
}

@JsonIgnore
public MerchantAccountPayment asMerchantAccountPayment() {
if (!isMerchantAccountPayment()) {
Expand All @@ -79,6 +87,14 @@ public Payout asPayout() {
return (Payout) this;
}

@JsonIgnore
public Refund asRefund() {
if (!isRefund()) {
throw new TrueLayerException(buildErrorMessage());
}
return (Refund) this;
}

private String buildErrorMessage() {
return String.format("Payment is of type %s.", this.getClass().getSimpleName());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.truelayer.java.merchantaccounts.entities.transactions.accountidentifier;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonValue;
import com.truelayer.java.TrueLayerException;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

/**
* A transaction item specific DTO for external payments
* representing account identifiers of either IBAN or SCAN type only.
* This is deliberately different from the more generic {@link com.truelayer.java.entities.Remitter Remitter} class.
*/
@JsonTypeInfo(
include = JsonTypeInfo.As.EXISTING_PROPERTY,
use = JsonTypeInfo.Id.NAME,
property = "type",
defaultImpl = SortCodeAccountNumberAccountIdentifier.class)
@JsonSubTypes({
@JsonSubTypes.Type(value = SortCodeAccountNumberAccountIdentifier.class, name = "sort_code_account_number"),
@JsonSubTypes.Type(value = IbanAccountIdentifier.class, name = "iban"),
})
@ToString
@EqualsAndHashCode
@Getter
public abstract class AccountIdentifier {
public abstract Type getType();

@JsonIgnore
public boolean isSortCodeAccountNumberIdentifier() {
return this instanceof SortCodeAccountNumberAccountIdentifier;
}

@JsonIgnore
public boolean isIbanIdentifier() {
return this instanceof IbanAccountIdentifier;
}

@JsonIgnore
public SortCodeAccountNumberAccountIdentifier asSortCodeAccountNumber() {
if (!isSortCodeAccountNumberIdentifier()) {
throw new TrueLayerException(buildErrorMessage());
}
return (SortCodeAccountNumberAccountIdentifier) this;
}

@JsonIgnore
public IbanAccountIdentifier asIban() {
if (!isIbanIdentifier()) {
throw new TrueLayerException(buildErrorMessage());
}
return (IbanAccountIdentifier) this;
}

private String buildErrorMessage() {
return String.format("Identifier is of type %s.", this.getClass().getSimpleName());
}

@Getter
@RequiredArgsConstructor
public enum Type {
SORT_CODE_ACCOUNT_NUMBER("sort_code_account_number"),
IBAN("iban");

@JsonValue
private final String type;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.truelayer.java.merchantaccounts.entities.transactions.accountidentifier;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class IbanAccountIdentifier extends AccountIdentifier {
private final Type type = Type.IBAN;

private String iban;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.truelayer.java.merchantaccounts.entities.transactions.accountidentifier;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class SortCodeAccountNumberAccountIdentifier extends AccountIdentifier {
private final Type type = Type.SORT_CODE_ACCOUNT_NUMBER;

private String sortCode;

private String accountNumber;
}
Loading

0 comments on commit ede7ff0

Please sign in to comment.