diff --git a/src/main/java/com/univapay/sdk/SDKMethods.java b/src/main/java/com/univapay/sdk/SDKMethods.java
index cbcf015a..ec3db8a3 100644
--- a/src/main/java/com/univapay/sdk/SDKMethods.java
+++ b/src/main/java/com/univapay/sdk/SDKMethods.java
@@ -50,11 +50,7 @@
import com.univapay.sdk.models.response.subscription.FullSubscription;
import com.univapay.sdk.models.response.transactiontoken.TokenAliasKey;
import com.univapay.sdk.settings.AbstractSDKSettings;
-import com.univapay.sdk.types.BusinessType;
-import com.univapay.sdk.types.PaymentTypeName;
-import com.univapay.sdk.types.RefundReason;
-import com.univapay.sdk.types.SubscriptionPeriod;
-import com.univapay.sdk.types.TransactionTokenType;
+import com.univapay.sdk.types.*;
import java.math.BigInteger;
import java.net.URL;
import java.util.List;
@@ -210,7 +206,7 @@ AbstractAuthenticationBuilders.AbstractLoginRequestBuilder getLoginToken(
* Get the checkout information for the merchant.
*
* @param origin a domain included in the list of domains associated with the
- * application token
+ * application token
* @return a request builder
*/
AbstractStoreBuilders.AbstractGetCheckoutInfoRequestBuilder getCheckoutInfo(Domain origin);
@@ -222,6 +218,15 @@ AbstractAuthenticationBuilders.AbstractLoginRequestBuilder getLoginToken(
*/
AbstractStoreBuilders.AbstractGetCheckoutInfoRequestBuilder getCheckoutInfo();
+ /**
+ * Get the supported brands for a gateway, required when the Supported Brand at the CheckoutInfo,
+ * has the dynamic_info: true
+ *
+ * @return a request builder
+ */
+ AbstractStoreBuilders.AbstractGetDynamicBrandInfoRequestBuilder getDynamicBrandInfo(
+ Gateway gateway);
+
/**
* List the application tokens available for the store with ID storeId.
*
@@ -349,7 +354,7 @@ AbstractApplicationTokenBuilders.AbstractDeleteStoreApplicationJWTRequestBuilder
*
* @param storeId (optional) the ID of the store for which charges are being requested
* @return an instance of ListChargesRequestBuilder implementing Paginator
- *
+ *
* @see Paginator
*/
AbstractChargesBuilders.AbstractListChargesRequestBuilder listCharges(StoreId storeId);
@@ -358,7 +363,7 @@ AbstractApplicationTokenBuilders.AbstractDeleteStoreApplicationJWTRequestBuilder
* Obtain a list of charges made by the merchant.
*
* @return an instance of ListChargesRequestBuilder implementing Paginator
- *
+ *
* @see Paginator
*/
AbstractChargesBuilders.AbstractListChargesRequestBuilder listCharges();
@@ -539,7 +544,7 @@ AbstractChargesBuilders.AbstractUpdateChargeRequestBuilder updateCharge(
* Obtain a list of all the subscriptions.
*
* @return a request builder that implements ListSubscriptionsRequest and
- * Paginator
+ * Paginator
* @see Paginator
*/
AbstractSubscriptionBuilders.AbstractListSubscriptionsMerchantRequestBuilder listSubscriptions();
@@ -549,7 +554,7 @@ AbstractChargesBuilders.AbstractUpdateChargeRequestBuilder updateCharge(
*
* @param storeId the ID of the store for which subscriptions will be listed
* @return a request builder that implements ListSubscriptionsRequest and
- * Paginator
+ * Paginator
* @see Paginator
*/
AbstractSubscriptionBuilders.AbstractListSubscriptionsRequestBuilder listSubscriptions(
diff --git a/src/main/java/com/univapay/sdk/UnivapaySDK.java b/src/main/java/com/univapay/sdk/UnivapaySDK.java
index 18df2c9f..f40d423f 100644
--- a/src/main/java/com/univapay/sdk/UnivapaySDK.java
+++ b/src/main/java/com/univapay/sdk/UnivapaySDK.java
@@ -56,11 +56,7 @@
import com.univapay.sdk.models.response.transactiontoken.TokenAliasKey;
import com.univapay.sdk.settings.AbstractSDKSettings;
import com.univapay.sdk.settings.UnivapaySettings;
-import com.univapay.sdk.types.BusinessType;
-import com.univapay.sdk.types.PaymentTypeName;
-import com.univapay.sdk.types.RefundReason;
-import com.univapay.sdk.types.SubscriptionPeriod;
-import com.univapay.sdk.types.TransactionTokenType;
+import com.univapay.sdk.types.*;
import java.io.Closeable;
import java.io.IOException;
import java.math.BigInteger;
@@ -279,6 +275,11 @@ public StoreBuilders.GetCheckoutInfoRequestBuilder getCheckoutInfo() {
return new StoreBuilders.GetCheckoutInfoRequestBuilder(retrofit);
}
+ @Override
+ public StoreBuilders.GetDynamicBrandInfoRequestBuilder getDynamicBrandInfo(Gateway gateway) {
+ return new StoreBuilders.GetDynamicBrandInfoRequestBuilder(retrofit, gateway);
+ }
+
@Override
public StoreBuilders.CreateCustomerIdRequestBuilder createCustomerId(
StoreId storeId, String customerId) {
diff --git a/src/main/java/com/univapay/sdk/adapters/JsonAdapters.java b/src/main/java/com/univapay/sdk/adapters/JsonAdapters.java
index 58caa57f..9992bdc1 100644
--- a/src/main/java/com/univapay/sdk/adapters/JsonAdapters.java
+++ b/src/main/java/com/univapay/sdk/adapters/JsonAdapters.java
@@ -312,4 +312,17 @@ public T read(JsonReader in) throws IOException {
}
}
}
+
+ public static class OsTypeTypeAdapter extends BrandsTypeAdapters.SimpleEnumTypeAdapter {
+
+ @Override
+ protected String getValueOfObject(OsType input) {
+ return input.getTypeRepresentation();
+ }
+
+ @Override
+ protected OsType getByValue(String value) {
+ return OsType.getInstanceByLiteralValueNullable(value);
+ }
+ }
}
diff --git a/src/main/java/com/univapay/sdk/builders/charge/ChargesBuilders.java b/src/main/java/com/univapay/sdk/builders/charge/ChargesBuilders.java
index 48152672..f6119700 100644
--- a/src/main/java/com/univapay/sdk/builders/charge/ChargesBuilders.java
+++ b/src/main/java/com/univapay/sdk/builders/charge/ChargesBuilders.java
@@ -2,7 +2,6 @@
import com.univapay.sdk.UnivapaySDK;
import com.univapay.sdk.builders.ResourceMonitor;
-import com.univapay.sdk.builders.ResourcePredicate;
import com.univapay.sdk.builders.charge.AbstractChargesBuilders.*;
import com.univapay.sdk.models.common.*;
import com.univapay.sdk.models.common.ChargeId;
@@ -131,12 +130,7 @@ public static ResourceMonitor createChargeCompletionMonitor(
Retrofit retrofit, StoreId storeId, ChargeId chargeId) {
return new ResourceMonitor<>(
new GetChargeRequestBuilder(retrofit, storeId, chargeId).withPolling(true),
- new ResourcePredicate() {
- @Override
- public boolean test(Charge resource) {
- return resource.getStatus() != ChargeStatus.PENDING;
- }
- });
+ resource -> resource.getStatus() != ChargeStatus.PENDING);
}
public static class CreateChargeWithTokenAliasRequestBuilder
diff --git a/src/main/java/com/univapay/sdk/builders/store/AbstractStoreBuilders.java b/src/main/java/com/univapay/sdk/builders/store/AbstractStoreBuilders.java
index 1c4fba70..28b3ce97 100644
--- a/src/main/java/com/univapay/sdk/builders/store/AbstractStoreBuilders.java
+++ b/src/main/java/com/univapay/sdk/builders/store/AbstractStoreBuilders.java
@@ -25,6 +25,7 @@
import com.univapay.sdk.models.response.subscription.SubscriptionConfiguration;
import com.univapay.sdk.types.CardBrand;
import com.univapay.sdk.types.Country;
+import com.univapay.sdk.types.Gateway;
import java.math.BigDecimal;
import java.net.URL;
import java.time.ZoneId;
@@ -470,6 +471,37 @@ public AbstractGetCheckoutInfoRequestBuilder(Retrofit retrofit) {
}
}
+ public abstract static class AbstractGetDynamicBrandInfoRequestBuilder<
+ B extends AbstractGetDynamicBrandInfoRequestBuilder, R, M extends DynamicBrandInfo>
+ extends RetrofitRequestBuilder {
+
+ public AbstractGetDynamicBrandInfoRequestBuilder(Retrofit retrofit) {
+ super(retrofit);
+ }
+
+ // Parameters for this request
+
+ protected Gateway gateway;
+ protected MoneyLike requestedMoney;
+ protected CallMethod callMethod;
+ protected OsType osType;
+
+ public B withRequestedMoney(MoneyLike requestedMoney) {
+ this.requestedMoney = requestedMoney;
+ return (B) this;
+ }
+
+ public B withCallMethod(CallMethod callMethod) {
+ this.callMethod = callMethod;
+ return (B) this;
+ }
+
+ public B withOsType(OsType osType) {
+ this.osType = osType;
+ return (B) this;
+ }
+ }
+
public abstract static class AbstractCreateCustomerIdRequestBuilder<
B extends AbstractCreateCustomerIdRequestBuilder, R, M extends UnivapayCustomerId>
extends RetrofitRequestBuilder {
diff --git a/src/main/java/com/univapay/sdk/builders/store/StoreBuilders.java b/src/main/java/com/univapay/sdk/builders/store/StoreBuilders.java
index e43bf12a..4d20b6f9 100644
--- a/src/main/java/com/univapay/sdk/builders/store/StoreBuilders.java
+++ b/src/main/java/com/univapay/sdk/builders/store/StoreBuilders.java
@@ -1,18 +1,19 @@
package com.univapay.sdk.builders.store;
import com.univapay.sdk.builders.store.AbstractStoreBuilders.*;
-import com.univapay.sdk.models.common.Domain;
-import com.univapay.sdk.models.common.StoreId;
-import com.univapay.sdk.models.common.UnivapayCustomerId;
+import com.univapay.sdk.models.common.*;
import com.univapay.sdk.models.common.Void;
import com.univapay.sdk.models.request.configuration.StoreConfigurationRequest;
import com.univapay.sdk.models.request.store.CustomerIdRequest;
+import com.univapay.sdk.models.request.store.GetDynamicBrandInfoForm;
import com.univapay.sdk.models.request.store.StoreCreateData;
import com.univapay.sdk.models.response.PaginatedList;
import com.univapay.sdk.models.response.store.CheckoutInfo;
+import com.univapay.sdk.models.response.store.DynamicBrandInfo;
import com.univapay.sdk.models.response.store.Store;
import com.univapay.sdk.models.response.store.StoreWithConfiguration;
import com.univapay.sdk.resources.StoresResource;
+import com.univapay.sdk.types.Gateway;
import com.univapay.sdk.utils.builders.ConfigurationBuilder;
import retrofit2.Call;
import retrofit2.Retrofit;
@@ -147,6 +148,30 @@ protected Call getRequest(StoresResource resource) {
}
}
+ public static class GetDynamicBrandInfoRequestBuilder
+ extends AbstractGetDynamicBrandInfoRequestBuilder<
+ GetDynamicBrandInfoRequestBuilder, StoresResource, DynamicBrandInfo> {
+
+ public GetDynamicBrandInfoRequestBuilder(Retrofit retrofit, Gateway gateway) {
+ super(retrofit);
+ this.gateway = gateway;
+ }
+
+ @Override
+ protected Call getRequest(StoresResource resource) {
+ GetDynamicBrandInfoForm form = new GetDynamicBrandInfoForm();
+
+ if (requestedMoney != null) {
+ form.setRequestedMoney(new GetDynamicBrandInfoForm.RequestMoneyInformation(requestedMoney));
+ }
+
+ form.setCallMethod(callMethod);
+ form.setOsType(osType);
+
+ return resource.getDynamicBrandInfo(gateway, form);
+ }
+ }
+
public static class CreateCustomerIdRequestBuilder
extends AbstractCreateCustomerIdRequestBuilder<
CreateCustomerIdRequestBuilder, StoresResource, UnivapayCustomerId> {
diff --git a/src/main/java/com/univapay/sdk/models/common/CallMethod.java b/src/main/java/com/univapay/sdk/models/common/CallMethod.java
index a7bc16c6..59cbcd8d 100644
--- a/src/main/java/com/univapay/sdk/models/common/CallMethod.java
+++ b/src/main/java/com/univapay/sdk/models/common/CallMethod.java
@@ -5,10 +5,10 @@
/** Representation of the method that is used to consume the issuerToken */
public enum CallMethod {
- /** The issuer token is a HTTP endpoint, invoked with GET */
+ /** The issuer token is an HTTP endpoint, invoked with GET */
@SerializedName("http_get")
HTTP_GET,
- /** The issuer token is a HTTP endpoint, invoked with POST */
+ /** The issuer token is an HTTP endpoint, invoked with POST */
@SerializedName("http_post")
HTTP_POST,
/** The issuer token should be forwarded to the service's provided SDK */
diff --git a/src/main/java/com/univapay/sdk/models/common/OnlinePayment.java b/src/main/java/com/univapay/sdk/models/common/OnlinePayment.java
index 6ee9d093..baffa4d8 100644
--- a/src/main/java/com/univapay/sdk/models/common/OnlinePayment.java
+++ b/src/main/java/com/univapay/sdk/models/common/OnlinePayment.java
@@ -8,8 +8,12 @@
public class OnlinePayment implements PaymentData {
/** This defines which service will be used when creating the TransactionToken & Charge */
+
+ // Can be a Static brand & or a ConnectWallet dynamic sub brand
@SerializedName("brand")
- private final OnlineBrand brand;
+ private final String brand;
+
+ private transient OnlineBrand onlineBrand;
@SerializedName("call_method")
private CallMethod callMethod;
@@ -17,13 +21,27 @@ public class OnlinePayment implements PaymentData {
@SerializedName("user_identifier")
private String userIdentifier;
+ @SerializedName("os_type")
+ private OsType osType;
+
@Override
public PaymentTypeName getPaymentType() {
return PaymentTypeName.ONLINE;
}
public OnlinePayment(OnlineBrand brand) {
+ if (brand != null) {
+ this.brand = brand.getTypeRepresentation();
+ } else {
+ this.brand = null;
+ }
+
+ this.onlineBrand = brand;
+ }
+
+ public OnlinePayment(String brand) {
this.brand = brand;
+ this.onlineBrand = OnlineBrand.getInstanceByLiteralValueNullable(brand);
}
public OnlinePayment withCallMethod(CallMethod callMethod) {
@@ -36,8 +54,17 @@ public OnlinePayment withUserIdentifier(String userIdentifier) {
return this;
}
- public OnlineBrand getBrand() {
- return brand;
+ public OnlinePayment withOsType(OsType osType) {
+ this.osType = osType;
+ return this;
+ }
+
+ public OnlineBrand getOnlineBrand() {
+ if (onlineBrand == null) {
+ onlineBrand = OnlineBrand.getInstanceByLiteralValueNullable(brand);
+ }
+
+ return onlineBrand;
}
public CallMethod getCallMethod() {
@@ -47,4 +74,12 @@ public CallMethod getCallMethod() {
public String getUserIdentifier() {
return userIdentifier;
}
+
+ public String getBrand() {
+ return brand;
+ }
+
+ public OsType getOsType() {
+ return osType;
+ }
}
diff --git a/src/main/java/com/univapay/sdk/models/common/OsType.java b/src/main/java/com/univapay/sdk/models/common/OsType.java
new file mode 100644
index 00000000..3375dc1a
--- /dev/null
+++ b/src/main/java/com/univapay/sdk/models/common/OsType.java
@@ -0,0 +1,40 @@
+package com.univapay.sdk.models.common;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public enum OsType {
+ iOS("i_os"),
+ Android("android");
+
+ private final String typeRepresentation;
+
+ OsType(String typeRepresentation) {
+ this.typeRepresentation = typeRepresentation;
+ }
+
+ public String getTypeRepresentation() {
+ return typeRepresentation;
+ }
+
+ static final Map entryMapByTypeRepresentation =
+ Arrays.stream(OsType.values())
+ .collect(Collectors.toMap(OsType::getTypeRepresentation, Function.identity()));
+
+ public static OsType getInstanceByLiteralValue(final String literalValue)
+ throws IllegalArgumentException {
+ OsType value = entryMapByTypeRepresentation.get(literalValue);
+
+ if (value == null) {
+ throw new IllegalArgumentException();
+ } else {
+ return value;
+ }
+ }
+
+ public static OsType getInstanceByLiteralValueNullable(final String literalValue) {
+ return entryMapByTypeRepresentation.get(literalValue);
+ }
+}
diff --git a/src/main/java/com/univapay/sdk/models/common/PaymentDataTypeAdapter.java b/src/main/java/com/univapay/sdk/models/common/PaymentDataTypeAdapter.java
index 90b6b240..59aa21e9 100644
--- a/src/main/java/com/univapay/sdk/models/common/PaymentDataTypeAdapter.java
+++ b/src/main/java/com/univapay/sdk/models/common/PaymentDataTypeAdapter.java
@@ -4,7 +4,6 @@
import com.univapay.sdk.models.response.transactiontoken.*;
import com.univapay.sdk.types.Gateway;
import com.univapay.sdk.types.Konbini;
-import com.univapay.sdk.types.brand.OnlineBrand;
import com.univapay.sdk.types.brand.QrCpmBrand;
import com.univapay.sdk.types.brand.QrMpmBrand;
import java.lang.reflect.Type;
@@ -92,7 +91,7 @@ public PaymentData deserialize(JsonElement json, Type type, JsonDeserializationC
QrCpmBrand qrCpmBrand = context.deserialize(object.get("brand"), QrCpmBrand.class);
QrMpmBrand qrMpmBrand = context.deserialize(object.get("brand"), QrMpmBrand.class);
- OnlineBrand onlineBrand = context.deserialize(object.get("brand"), OnlineBrand.class);
+ String onlineBrand = context.deserialize(object.get("brand"), String.class);
CallMethod callMethod = context.deserialize(object.get("call_method"), CallMethod.class);
String issuerToken = asString(object, "issuer_token");
String userIdentifier = asString(object, "user_identifier");
diff --git a/src/main/java/com/univapay/sdk/models/request/store/GetDynamicBrandInfoForm.java b/src/main/java/com/univapay/sdk/models/request/store/GetDynamicBrandInfoForm.java
new file mode 100644
index 00000000..c8cdaeb5
--- /dev/null
+++ b/src/main/java/com/univapay/sdk/models/request/store/GetDynamicBrandInfoForm.java
@@ -0,0 +1,66 @@
+package com.univapay.sdk.models.request.store;
+
+import com.google.gson.annotations.SerializedName;
+import com.univapay.sdk.models.common.CallMethod;
+import com.univapay.sdk.models.common.MoneyLike;
+import com.univapay.sdk.models.common.OsType;
+import java.math.BigInteger;
+import javax.annotation.Nonnull;
+
+public class GetDynamicBrandInfoForm {
+
+ @SerializedName("amount")
+ private RequestMoneyInformation requestedMoney;
+
+ @SerializedName("call_method")
+ private CallMethod callMethod;
+
+ @SerializedName("os_type")
+ private OsType osType;
+
+ public RequestMoneyInformation getRequestedMoney() {
+ return requestedMoney;
+ }
+
+ public void setRequestedMoney(RequestMoneyInformation requestedMoney) {
+ this.requestedMoney = requestedMoney;
+ }
+
+ public CallMethod getCallMethod() {
+ return callMethod;
+ }
+
+ public void setCallMethod(CallMethod callMethod) {
+ this.callMethod = callMethod;
+ }
+
+ public OsType getOsType() {
+ return osType;
+ }
+
+ public void setOsType(OsType osType) {
+ this.osType = osType;
+ }
+
+ public static class RequestMoneyInformation {
+
+ @SerializedName("value")
+ private final BigInteger amount;
+
+ @SerializedName("currency")
+ private final String currency;
+
+ public BigInteger getAmount() {
+ return amount;
+ }
+
+ public String getCurrency() {
+ return currency;
+ }
+
+ public RequestMoneyInformation(@Nonnull MoneyLike input) {
+ this.amount = input.getAmount();
+ this.currency = input.getCurrency();
+ }
+ }
+}
diff --git a/src/main/java/com/univapay/sdk/models/response/store/CheckoutFeatureSupport.java b/src/main/java/com/univapay/sdk/models/response/store/CheckoutFeatureSupport.java
index 58699f1a..7e13976d 100644
--- a/src/main/java/com/univapay/sdk/models/response/store/CheckoutFeatureSupport.java
+++ b/src/main/java/com/univapay/sdk/models/response/store/CheckoutFeatureSupport.java
@@ -148,4 +148,8 @@ public Set getSupportedCurrencies() {
public QrMpmBrand getQrMpmBrand() {
return qrMpmBrand;
}
+
+ public Boolean getDynamicInfo() {
+ return dynamicInfo;
+ }
}
diff --git a/src/main/java/com/univapay/sdk/models/response/store/DynamicBrandInfo.java b/src/main/java/com/univapay/sdk/models/response/store/DynamicBrandInfo.java
new file mode 100644
index 00000000..adbac1b9
--- /dev/null
+++ b/src/main/java/com/univapay/sdk/models/response/store/DynamicBrandInfo.java
@@ -0,0 +1,61 @@
+package com.univapay.sdk.models.response.store;
+
+import com.google.gson.annotations.SerializedName;
+import com.univapay.sdk.models.response.UnivapayResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DynamicBrandInfo extends UnivapayResponse {
+
+ @SerializedName("brands")
+ private List brands;
+
+ public List getBrands() {
+ if (brands == null) {
+ this.brands = new ArrayList<>();
+ }
+
+ return brands;
+ }
+
+ public static class DynamicBrand {
+
+ @SerializedName("brand_name")
+ private String brandName;
+
+ @SerializedName("brand_logo")
+ private String brandLogo;
+
+ @SerializedName("sub_brand_name")
+ private String subBrandName;
+
+ @SerializedName("sub_brand_logo")
+ private String subBrandLogo;
+
+ public DynamicBrand(
+ String brandName, String brandLogo, String subBrandName, String subBrandLogo) {
+ this.brandName = brandName;
+ this.brandLogo = brandLogo;
+ this.subBrandName = subBrandName;
+ this.subBrandLogo = subBrandLogo;
+ }
+
+ public DynamicBrand() {}
+
+ public String getBrandName() {
+ return brandName;
+ }
+
+ public String getBrandLogo() {
+ return brandLogo;
+ }
+
+ public String getSubBrandName() {
+ return subBrandName;
+ }
+
+ public String getSubBrandLogo() {
+ return subBrandLogo;
+ }
+ }
+}
diff --git a/src/main/java/com/univapay/sdk/models/response/transactiontoken/OnlinePaymentData.java b/src/main/java/com/univapay/sdk/models/response/transactiontoken/OnlinePaymentData.java
index bff3fd68..1a946aaa 100644
--- a/src/main/java/com/univapay/sdk/models/response/transactiontoken/OnlinePaymentData.java
+++ b/src/main/java/com/univapay/sdk/models/response/transactiontoken/OnlinePaymentData.java
@@ -6,21 +6,22 @@
/** This represents the online payment data for the TransactionToken response */
public class OnlinePaymentData {
- private final OnlineBrand brand;
+ private final String brand;
+ private final OnlineBrand onlineBrand;
private final String issuerToken;
private final CallMethod callMethod;
private final String userIdentifier;
public OnlinePaymentData(
- OnlineBrand brand, String issuerToken, CallMethod callMethod, String userIdentifier) {
-
+ String brand, String issuerToken, CallMethod callMethod, String userIdentifier) {
this.brand = brand;
+ this.onlineBrand = OnlineBrand.getInstanceByLiteralValueNullable(brand);
this.issuerToken = issuerToken;
this.callMethod = callMethod;
this.userIdentifier = userIdentifier;
}
- public OnlineBrand getBrand() {
+ public String getBrand() {
return brand;
}
@@ -35,4 +36,12 @@ public CallMethod getCallMethod() {
public String getUserIdentifier() {
return userIdentifier;
}
+
+ public OnlineBrand getOnlineBrand() {
+ return onlineBrand;
+ }
+
+ public boolean couldBeDynamicBrand() {
+ return brand != null && !brand.isEmpty() && onlineBrand == null;
+ }
}
diff --git a/src/main/java/com/univapay/sdk/models/response/transactiontoken/PaymentData.java b/src/main/java/com/univapay/sdk/models/response/transactiontoken/PaymentData.java
index e8803b51..f7beea70 100644
--- a/src/main/java/com/univapay/sdk/models/response/transactiontoken/PaymentData.java
+++ b/src/main/java/com/univapay/sdk/models/response/transactiontoken/PaymentData.java
@@ -3,7 +3,6 @@
import com.univapay.sdk.models.common.*;
import com.univapay.sdk.types.Gateway;
import com.univapay.sdk.types.Konbini;
-import com.univapay.sdk.types.brand.OnlineBrand;
import com.univapay.sdk.types.brand.QrCpmBrand;
import com.univapay.sdk.types.brand.QrMpmBrand;
import java.time.Period;
@@ -25,7 +24,7 @@ public PaymentData(
String qrImageUrl,
QrCpmBrand qrCpmBrand,
QrMpmBrand qrMpmBrand,
- OnlineBrand onlineBrand,
+ String onlineBrand,
CallMethod callMethod,
String issuerToken,
String userIdentifier) {
@@ -71,7 +70,7 @@ public PaymentData(
private QrMpmBrand qrMpmBrand;
- private OnlineBrand onlineBrand;
+ private String onlineBrand;
private CallMethod callMethod;
diff --git a/src/main/java/com/univapay/sdk/resources/StoresResource.java b/src/main/java/com/univapay/sdk/resources/StoresResource.java
index 881310bf..151ac58e 100644
--- a/src/main/java/com/univapay/sdk/resources/StoresResource.java
+++ b/src/main/java/com/univapay/sdk/resources/StoresResource.java
@@ -8,12 +8,15 @@
import com.univapay.sdk.models.common.UnivapayCustomerId;
import com.univapay.sdk.models.common.Void;
import com.univapay.sdk.models.request.store.CustomerIdRequest;
+import com.univapay.sdk.models.request.store.GetDynamicBrandInfoForm;
import com.univapay.sdk.models.request.store.StoreCreateData;
import com.univapay.sdk.models.response.PaginatedList;
import com.univapay.sdk.models.response.store.CheckoutInfo;
+import com.univapay.sdk.models.response.store.DynamicBrandInfo;
import com.univapay.sdk.models.response.store.Store;
import com.univapay.sdk.models.response.store.StoreWithConfiguration;
import com.univapay.sdk.types.CursorDirection;
+import com.univapay.sdk.types.Gateway;
import org.jetbrains.annotations.Nullable;
import retrofit2.Call;
import retrofit2.http.*;
@@ -47,6 +50,10 @@ Call update(
@GET("/checkout_info")
Call getCheckoutInfo(@Query("origin") Domain origin);
+ @POST("/checkout_info/gateway/{gateway}")
+ Call getDynamicBrandInfo(
+ @Path("gateway") Gateway gateway, @Body GetDynamicBrandInfoForm form);
+
@POST("/stores/{storeId}/create_customer_id")
Call createCustomerId(
@Path("storeId") StoreId storeId, @Body CustomerIdRequest userId);
diff --git a/src/main/java/com/univapay/sdk/utils/RetrofitBuilder.java b/src/main/java/com/univapay/sdk/utils/RetrofitBuilder.java
index 1dbdbec0..12a13a60 100644
--- a/src/main/java/com/univapay/sdk/utils/RetrofitBuilder.java
+++ b/src/main/java/com/univapay/sdk/utils/RetrofitBuilder.java
@@ -9,10 +9,7 @@
import com.univapay.sdk.converters.DomainConverterFactory;
import com.univapay.sdk.converters.IdempotencyKeyConverterFactory;
import com.univapay.sdk.converters.VoidConverterFactory;
-import com.univapay.sdk.models.common.Domain;
-import com.univapay.sdk.models.common.PaidyToken;
-import com.univapay.sdk.models.common.PaymentDataTypeAdapter;
-import com.univapay.sdk.models.common.UnivapayEmailAddress;
+import com.univapay.sdk.models.common.*;
import com.univapay.sdk.models.common.auth.AuthStrategy;
import com.univapay.sdk.models.common.auth.LoginJWTStrategy;
import com.univapay.sdk.models.request.subscription.RemoveInstallmentsPlan;
@@ -95,6 +92,7 @@ RemoveInstallmentsPlan.class, new JsonRemoveInstallmentsPlanAdapter(gsonForNulls
.registerTypeAdapter(OnlineBrand.class, new BrandsTypeAdapters.OnlineBrandTypeAdapter())
.registerTypeAdapter(PaidyBrand.class, new BrandsTypeAdapters.PaidyBrandTypeAdapter())
.registerTypeAdapter(QrMpmBrand.class, new BrandsTypeAdapters.QrMpmBrandTypeAdapter())
+ .registerTypeAdapter(OsType.class, new OsTypeTypeAdapter())
.registerTypeAdapterFactory(new JsonPreconfiguredTransferScheduleSerializer());
return postCreateGsonBuilder(builder);
}
diff --git a/src/test/java/com/univapay/sdk/builders/ResourceMonitorTest.java b/src/test/java/com/univapay/sdk/builders/ResourceMonitorTest.java
index 6f4d6932..277d0464 100644
--- a/src/test/java/com/univapay/sdk/builders/ResourceMonitorTest.java
+++ b/src/test/java/com/univapay/sdk/builders/ResourceMonitorTest.java
@@ -36,7 +36,7 @@ public class ResourceMonitorTest {
@Before
public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.openMocks(this);
when(request.dispatch()).thenReturn(0);
diff --git a/src/test/java/com/univapay/sdk/e2e/AlipayPlusOnlineIT.java b/src/test/java/com/univapay/sdk/e2e/AlipayPlusOnlineIT.java
new file mode 100644
index 00000000..f714297d
--- /dev/null
+++ b/src/test/java/com/univapay/sdk/e2e/AlipayPlusOnlineIT.java
@@ -0,0 +1,288 @@
+package com.univapay.sdk.e2e;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.fail;
+
+import com.univapay.sdk.UnivapaySDK;
+import com.univapay.sdk.models.common.*;
+import com.univapay.sdk.models.errors.UnivapayException;
+import com.univapay.sdk.models.response.IssuerToken;
+import com.univapay.sdk.models.response.charge.Charge;
+import com.univapay.sdk.models.response.store.CheckoutInfo;
+import com.univapay.sdk.models.response.store.DynamicBrandInfo;
+import com.univapay.sdk.models.response.store.DynamicBrandInfo.DynamicBrand;
+import com.univapay.sdk.models.response.transactiontoken.OnlinePaymentData;
+import com.univapay.sdk.models.response.transactiontoken.TransactionTokenWithData;
+import com.univapay.sdk.types.AuthType;
+import com.univapay.sdk.types.ChargeStatus;
+import com.univapay.sdk.types.Gateway;
+import com.univapay.sdk.types.TransactionTokenType;
+import com.univapay.sdk.types.brand.OnlineBrand;
+import com.univapay.sdk.utils.GenericTest;
+import com.univapay.sdk.utils.MockRRGeneratorWithAppTokenSecret;
+import com.univapay.sdk.utils.mockcontent.ChargesFakeRR;
+import com.univapay.sdk.utils.mockcontent.IssuerTokensFakeRR;
+import com.univapay.sdk.utils.mockcontent.StoreFakeRR;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+public class AlipayPlusOnlineIT extends GenericTest {
+
+ // This is a test that showcases the SDK/API usage when creating & processing the Alipay+ Payment
+
+ @Test
+ public void shouldProcessOnlinePaymentsWithDynamicBrands() throws UnivapayException, IOException {
+ mockRequestsForSuccessfulPathWithDynamicBrands();
+
+ // Assuming that menu is presented to the user to choose the payment method
+ // 1 - System must query the supported brands for a Store level ApplicationToken
+ // 2 - If one of the brands is ConnectWallet & dynamicInfo is true, query the DynamicInfo route
+ // 3 - Render said menu with Alipay+ & SubBrands as options for Alipay+ Online payments
+ // 4 - User will choose Alipay+ & Brand
+ // 5 - System will use SDK to create a TransactionToken & Charge with said sub-brand
+ // 6 - As any online payment, API will generate the required data and return to front end
+ // ----
+ // At asynchronous fashion & using webhook, await for charge processing to be completed
+ // ChargeStatus will become terminal (successful, error ,failed etc)
+
+ //
+ //
+ // 1 - System must query the supported brands for a Store level ApplicationToken
+
+ // Given the stored token, create or fetch previous created sdk instance
+
+ UnivapaySDK sdk = createTestInstance(AuthType.APP_TOKEN);
+
+ // Then query the checkout info route
+ CheckoutInfo checkoutInfo = sdk.getCheckoutInfo().dispatch();
+
+ // 2 - If one of the brands is ConnectWallet & dynamicInfo is true, query the DynamicInfo route
+ boolean supportDynamicAlipayPlus = checkIfAlipayPlusIsSupported(checkoutInfo);
+
+ assertThat(
+ "Is this example, we expect that the store can support Alipay+ payments with Dynamic rendering of the sub brands",
+ supportDynamicAlipayPlus,
+ is(equalTo(true)));
+
+ DynamicBrandInfo dynamicBrandInfo =
+ sdk.getDynamicBrandInfo(Gateway.ALIPAY_PLUS_ONLINE)
+ .withRequestedMoney(MoneyLike.of("JPY", 1000))
+ .withCallMethod(CallMethod.APP)
+ .withOsType(OsType.iOS)
+ .dispatch();
+
+ // Alipay+ dynamic brands will be grouped as "CONNECT_WALLET" key (brand name)
+ List alipayPlusSubBrands =
+ dynamicBrandInfo.getBrands().stream()
+ .filter(value -> "CONNECT_WALLET".equals(value.getBrandName()))
+ .collect(Collectors.toList());
+
+ assertThat(
+ "Must have at least one to process with Alipay+, is this example, is expected 7",
+ alipayPlusSubBrands,
+ hasSize(7));
+
+ // Organize the data in any shape that is preferred
+ AlipayPlusInformation information = generateInformation(alipayPlusSubBrands);
+
+ // 3 - Render said menu with Alipay+ & SubBrands as options for Alipay+ Online payments
+ render(information);
+ // 4 - User will choose Alipay+ & Brand
+
+ // At this point the TransactionToken and Charge will be created
+
+ // 5 - System will use SDK to create a TransactionToken & Charge with said sub-brand as
+ // online_brand
+ OnlinePayment dynamicTokenCreation =
+ new OnlinePayment("KAKAOPAY").withCallMethod(CallMethod.APP).withOsType(OsType.iOS);
+
+ TransactionTokenWithData transactionTokenForDynamicBrand =
+ sdk.createTransactionToken(/*email ,*/ dynamicTokenCreation, TransactionTokenType.ONE_TIME)
+ .dispatch();
+
+ OnlinePaymentData onlinePaymentData =
+ transactionTokenForDynamicBrand.getData().asOnlinePaymentData();
+
+ // Java enum are really static, so I can't model a "ConnectWallet(sub-brand)"
+ assertThat(onlinePaymentData.couldBeDynamicBrand(), is(true));
+ // If the brand is dynamic, the OnlineBrand will be null...
+ assertThat(onlinePaymentData.getOnlineBrand(), is(nullValue()));
+
+ // Then create a Charge
+ TransactionTokenId id = transactionTokenForDynamicBrand.getId();
+
+ Charge createdCharge =
+ sdk.createCharge(id, BigInteger.valueOf(100), "JPY")
+ .withIdempotencyKey(new IdempotencyKey("Recommended"))
+ .dispatch();
+
+ assertThat(createdCharge.getStatus(), is(ChargeStatus.PENDING));
+
+ Charge charge = null;
+
+ try {
+ charge =
+ sdk.chargeCompletionMonitor(createdCharge.getStoreId(), createdCharge.getId()).await();
+ } catch (InterruptedException | TimeoutException e) {
+ fail(
+ "Charge status usually goes from PENDING to AWAITING really quickly.. but is important to handle TimeoutException");
+ }
+
+ // After charge becomes AWAITING, the token information is available
+ IssuerToken issuerToken = sdk.getIssuerToken(charge.getStoreId(), charge.getId()).dispatch();
+
+ assertThat(issuerToken.getIssuerToken(), is("alipayconnect://schemeUrl"));
+ assertThat(issuerToken.getCallMethod(), is(CallMethod.APP));
+
+ // Return to the front end the issuerToken.getIssuerToken() && issuerToken.getCallMethod()
+ // values
+ // Then this is ready to wait until the charge is Successful or Failed
+
+ // TODO: Add a Successful Charge Response
+ // TODO: Add a Successful Transaction Token Response
+
+ }
+
+ private void mockRequestsForSuccessfulPathWithDynamicBrands() {
+
+ // TODO: Check if all these routes require a secret or not
+
+ MockRRGeneratorWithAppTokenSecret mock = new MockRRGeneratorWithAppTokenSecret();
+
+ mock.GenerateMockRequestResponse(
+ "GET", "/checkout_info", appToken, secret, 200, StoreFakeRR.getCheckoutInfoFakeResponse);
+
+ mock.GenerateMockRequestResponse(
+ "POST",
+ "/checkout_info/gateway/alipay_plus_online",
+ appToken,
+ secret,
+ 200,
+ StoreFakeRR.getDynamicInfoAlipayPlusResponse,
+ StoreFakeRR.getDynamicInfoAlipayPlusRequest);
+
+ mock.GenerateMockRequestResponse(
+ "POST",
+ "/tokens",
+ appToken,
+ secret,
+ 200,
+ StoreFakeRR.createTransactionTokenAlipayPlusDynamicBrandResponse,
+ StoreFakeRR.createTransactionTokenAlipayPlusDynamicBrandRequest);
+
+ mock.GenerateMockRequestResponse(
+ "POST",
+ "/charges",
+ appToken,
+ secret,
+ 200,
+ ChargesFakeRR.createStoreChargeOnlineResponse,
+ ChargesFakeRR.createStoreChargeOnlineRequest);
+
+ mock.GenerateMockQueuedRequestResponse(
+ "GET",
+ "/stores/11ec8336-dcea-f374-80a8-174b9ae64898/charges/11ec8336-de56-9a4c-935e-6f39db819b28?polling=true",
+ appToken,
+ secret,
+ 200,
+ /*request body = */ null,
+ ChargesFakeRR.createStoreChargeOnlineResponse,
+ ChargesFakeRR.createStoreChargeOnlineResponse,
+ ChargesFakeRR.createStoreChargeOnlineDeferredResponse);
+
+ mock.GenerateMockRequestResponse(
+ "GET",
+ "/stores/11ec8336-dcea-f374-80a8-174b9ae64898/charges/11ec8336-de56-9a4c-935e-6f39db819b28/issuerToken",
+ appToken,
+ secret,
+ 200,
+ IssuerTokensFakeRR.getIssuerTokenForAlipayPlusAppResponse);
+ }
+
+ private boolean checkIfAlipayPlusIsSupported(CheckoutInfo checkoutInfo) {
+ return checkoutInfo.getSupportedBrands().stream()
+ .anyMatch(
+ value ->
+ OnlineBrand.CONNECT_WALLET.equals(value.getOnlineBrand())
+ && Boolean.TRUE.equals(value.getDynamicInfo()));
+ }
+
+ // This is just a marker to note that this will be returned to the front ent
+ private void render(AlipayPlusInformation information) {
+ assertThat(information.getLogoUri(), is("http://localhost/CONNECT_WALLET.svg"));
+ }
+
+ private AlipayPlusInformation generateInformation(List alipayPlusSubBrands) {
+ if (alipayPlusSubBrands.isEmpty()) {
+ throw new IllegalArgumentException("alipayPlusSubBrands must be non empty");
+ }
+
+ DynamicBrand brand = alipayPlusSubBrands.get(0);
+ Set setOfSubBrands =
+ alipayPlusSubBrands.stream()
+ .map(value -> new AlipayPlusSubBrand(value.getSubBrandName(), value.getSubBrandLogo()))
+ .collect(Collectors.toSet());
+
+ return new AlipayPlusInformation(brand.getBrandLogo(), setOfSubBrands);
+ }
+
+ // This is just an example how to organize the DynamicBrandInfo
+ static class AlipayPlusInformation {
+
+ private final String logoUri;
+ private Set subBrands;
+
+ AlipayPlusInformation(String logoUri, Set subBrands) {
+ this.logoUri = logoUri;
+ this.subBrands = subBrands;
+ }
+
+ public Set getSubBrands() {
+ return subBrands;
+ }
+
+ public String getLogoUri() {
+ return logoUri;
+ }
+ }
+
+ static class AlipayPlusSubBrand {
+
+ private final String logoUri;
+ // Need to be used to create the TransactionToken later
+ private final String brandName;
+
+ AlipayPlusSubBrand(String logoUri, String brandName) {
+ this.logoUri = logoUri;
+ this.brandName = brandName;
+ }
+
+ public String getBrandName() {
+ return brandName;
+ }
+
+ public String getLogoUri() {
+ return logoUri;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AlipayPlusSubBrand that = (AlipayPlusSubBrand) o;
+ return Objects.equals(logoUri, that.logoUri) && Objects.equals(brandName, that.brandName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(logoUri, brandName);
+ }
+ }
+}
diff --git a/src/test/java/com/univapay/sdk/store/DynamicBrandInfoTest.java b/src/test/java/com/univapay/sdk/store/DynamicBrandInfoTest.java
new file mode 100644
index 00000000..f7d291a9
--- /dev/null
+++ b/src/test/java/com/univapay/sdk/store/DynamicBrandInfoTest.java
@@ -0,0 +1,183 @@
+package com.univapay.sdk.store;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.core.Is.is;
+
+import com.univapay.sdk.UnivapaySDK;
+import com.univapay.sdk.models.common.*;
+import com.univapay.sdk.models.errors.UnivapayException;
+import com.univapay.sdk.models.response.store.*;
+import com.univapay.sdk.models.response.store.DynamicBrandInfo.DynamicBrand;
+import com.univapay.sdk.models.response.store.checkoutInfo.*;
+import com.univapay.sdk.types.*;
+import com.univapay.sdk.utils.GenericTest;
+import com.univapay.sdk.utils.MockRRGeneratorWithAppTokenSecret;
+import com.univapay.sdk.utils.mockcontent.StoreFakeRR;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+public class DynamicBrandInfoTest extends GenericTest {
+ UnivapaySDK univapay = createTestInstance(AuthType.APP_TOKEN);
+
+ @Test
+ public void shouldReturnDynamicBrandsForAlipayPlusOnline() throws UnivapayException, IOException {
+ MockRRGeneratorWithAppTokenSecret mockRRGenerator = new MockRRGeneratorWithAppTokenSecret();
+ mockRRGenerator.GenerateMockRequestResponse(
+ "POST",
+ "/checkout_info/gateway/alipay_plus_online",
+ appToken,
+ secret,
+ 200,
+ StoreFakeRR.getDynamicInfoAlipayPlusResponse,
+ StoreFakeRR.getDynamicInfoAlipayPlusRequest);
+
+ DynamicBrandInfo response =
+ univapay
+ .getDynamicBrandInfo(Gateway.ALIPAY_PLUS_ONLINE)
+ .withCallMethod(CallMethod.APP)
+ .withOsType(OsType.iOS)
+ .withRequestedMoney(MoneyLike.of("JPY", 1000))
+ .dispatch();
+
+ // Seems that dynamic brands list for Alipay+ Online is upper case CONNECT_WALLET
+
+ // So to check if is possible to process with Alipay+, gather a list of any item that have the
+ // brand name as "CONNECT_WALLET"
+ List alipayPlusDynamicBrands =
+ response.getBrands().stream()
+ .filter(dynamicBrand -> "CONNECT_WALLET".equals(dynamicBrand.getBrandName()))
+ .collect(Collectors.toList());
+
+ // If there are elements in this list, yes is possible
+ assertThat(alipayPlusDynamicBrands, hasSize(7));
+
+ // Start to render the Pay with Alipay+ Online button
+ DynamicBrand brand = alipayPlusDynamicBrands.get(0);
+ // Is easier to the Logo provided - brand.getBrandLogo()
+
+ assertThat(brand.getBrandName(), is("CONNECT_WALLET"));
+ assertThat(brand.getBrandLogo(), is("http://localhost/CONNECT_WALLET.svg"));
+
+ // Then for each sub brand
+ Set subBrands =
+ alipayPlusDynamicBrands.stream()
+ .map(
+ dynamicBrand ->
+ new SubBrand(dynamicBrand.getSubBrandName(), dynamicBrand.getSubBrandLogo()))
+ .collect(Collectors.toSet());
+
+ // Render each sub brand as a valid choice for the user to click on
+
+ assertThat(
+ subBrands,
+ containsInAnyOrder(
+ new SubBrand("ALIPAY_HK", "http://localhost/icon/ALIPAY_HK.svg"),
+ new SubBrand("BPI", "http://localhost/icon/BPI.svg"),
+ new SubBrand("GCASH", "http://localhost/icon/GCASH.svg"),
+ new SubBrand("KAKAOPAY", "http://localhost/icon/KAKAOPAY.svg"),
+ new SubBrand("RABBIT_LINE_PAY", "http://localhost/icon/RABBIT_LINE_PAY.svg"),
+ new SubBrand("TNG", "http://localhost/icon/TNG.svg"),
+ new SubBrand("TRUEMONEY", "http://localhost/icon/TRUEMONEY.svg")));
+
+ // any option would be used to create a valid transaction token
+
+ }
+
+ @Test
+ public void couldReturnNoBrandsIfIsNotSupported() throws UnivapayException, IOException {
+
+ MockRRGeneratorWithAppTokenSecret mockRRGenerator = new MockRRGeneratorWithAppTokenSecret();
+ mockRRGenerator.GenerateMockRequestResponse(
+ "POST",
+ "/checkout_info/gateway/alipay_plus_online",
+ appToken,
+ secret,
+ 200,
+ StoreFakeRR.getDynamicInfoEmpty,
+ StoreFakeRR.getDynamicInfoOtherInput);
+
+ // There is a chance that Alipay+ could return no brands for this query
+ DynamicBrandInfo response =
+ univapay
+ .getDynamicBrandInfo(Gateway.ALIPAY_PLUS_ONLINE)
+ .withCallMethod(CallMethod.APP)
+ .withOsType(OsType.iOS)
+ .withRequestedMoney(MoneyLike.of("JPY", 12000))
+ .dispatch();
+
+ // Check if is possible to process with Alipay+, gather a list of any item that have the brand
+ // name as "CONNECT_WALLET"
+ List alipayPlusDynamicBrands =
+ response.getBrands().stream()
+ .filter(dynamicBrand -> "CONNECT_WALLET".equals(dynamicBrand.getBrandName()))
+ .collect(Collectors.toList());
+
+ assertThat(alipayPlusDynamicBrands, hasSize(0));
+
+ // Is this case is not possible to render the Pay with Alipay+ button
+
+ }
+
+ @Test
+ public void returnNoBrandsIfNotSupported() throws UnivapayException, IOException {
+
+ MockRRGeneratorWithAppTokenSecret mockRRGenerator = new MockRRGeneratorWithAppTokenSecret();
+ mockRRGenerator.GenerateMockRequestResponse(
+ "POST",
+ "/checkout_info/gateway/we_chat_online",
+ appToken,
+ secret,
+ 200,
+ StoreFakeRR.getDynamicInfoEmpty,
+ StoreFakeRR.getDynamicInfoWithoutOsTypeInput);
+
+ DynamicBrandInfo response =
+ univapay
+ .getDynamicBrandInfo(Gateway.WE_CHAT_ONLINE)
+ .withCallMethod(CallMethod.APP)
+ .withRequestedMoney(MoneyLike.of("JPY", 12000))
+ .dispatch();
+
+ assertThat(response.getBrands(), hasSize(0));
+ }
+
+ // Just a helper class to group up the response to make easier assertions
+ class SubBrand {
+ private String subBrandName;
+ private String subBrandLogo;
+
+ SubBrand(String subBrandName, String subBrandLogo) {
+ this.subBrandName = subBrandName;
+ this.subBrandLogo = subBrandLogo;
+ }
+
+ public String getSubBrandLogo() {
+ return subBrandLogo;
+ }
+
+ public String getSubBrandName() {
+ return subBrandName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ SubBrand subBrand = (SubBrand) o;
+
+ if (!Objects.equals(subBrandName, subBrand.subBrandName)) return false;
+ return Objects.equals(subBrandLogo, subBrand.subBrandLogo);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = subBrandName != null ? subBrandName.hashCode() : 0;
+ result = 31 * result + (subBrandLogo != null ? subBrandLogo.hashCode() : 0);
+ return result;
+ }
+ }
+}
diff --git a/src/test/java/com/univapay/sdk/transactiontoken/CreateTransactionTokenTest.java b/src/test/java/com/univapay/sdk/transactiontoken/CreateTransactionTokenTest.java
index d9aabf00..ee1ed072 100644
--- a/src/test/java/com/univapay/sdk/transactiontoken/CreateTransactionTokenTest.java
+++ b/src/test/java/com/univapay/sdk/transactiontoken/CreateTransactionTokenTest.java
@@ -1067,7 +1067,8 @@ public void shouldBeAbleToCreateTransactionTokenWithOnlinePaymentData()
OnlinePaymentData onlinePaymentData = token.getData().asOnlinePaymentData();
assertThat(onlinePaymentData, is(notNullValue()));
- assertThat(onlinePaymentData.getBrand(), is(OnlineBrand.TEST));
+ assertThat(onlinePaymentData.getBrand(), is(OnlineBrand.TEST.getTypeRepresentation()));
+ assertThat(onlinePaymentData.getOnlineBrand(), is(OnlineBrand.TEST));
// These will be provided if the charge is successfully processed to the Deferred status
assertThat(onlinePaymentData.getCallMethod(), is(nullValue()));
assertThat(onlinePaymentData.getCallMethod(), is(nullValue()));
@@ -1110,7 +1111,8 @@ public void shouldCreateTransactionTokenWithFullOnlinePaymentData()
OnlinePaymentData onlinePaymentData = token.getData().asOnlinePaymentData();
assertThat(onlinePaymentData, is(notNullValue()));
- assertThat(onlinePaymentData.getBrand(), is(OnlineBrand.TEST));
+ assertThat(onlinePaymentData.getBrand(), is(OnlineBrand.TEST.getTypeRepresentation()));
+ assertThat(onlinePaymentData.getOnlineBrand(), is(OnlineBrand.TEST));
assertThat(onlinePaymentData.getCallMethod(), is(CallMethod.SDK));
assertThat(onlinePaymentData.getUserIdentifier(), is("1234"));
}
diff --git a/src/test/java/com/univapay/sdk/transactiontoken/GetTransactionTokenTest.java b/src/test/java/com/univapay/sdk/transactiontoken/GetTransactionTokenTest.java
index c260e7ef..9419206c 100644
--- a/src/test/java/com/univapay/sdk/transactiontoken/GetTransactionTokenTest.java
+++ b/src/test/java/com/univapay/sdk/transactiontoken/GetTransactionTokenTest.java
@@ -201,7 +201,8 @@ public void shouldReturnIssuerTokenAndCallMethodIfAvailable()
.dispatch();
OnlinePaymentData data = response.getData().asOnlinePaymentData();
- assertThat(data.getBrand(), is(OnlineBrand.TEST));
+ assertThat(data.getBrand(), is(OnlineBrand.TEST.getTypeRepresentation()));
+ assertThat(data.getOnlineBrand(), is(OnlineBrand.TEST));
assertThat(data.getCallMethod(), is(CallMethod.SDK));
assertThat(data.getIssuerToken(), is("TOKEN"));
assertThat(data.getUserIdentifier(), is("1234"));
diff --git a/src/test/java/com/univapay/sdk/utils/MockRRGeneratorWithAppTokenSecret.java b/src/test/java/com/univapay/sdk/utils/MockRRGeneratorWithAppTokenSecret.java
index b08fd257..4eaf3a83 100644
--- a/src/test/java/com/univapay/sdk/utils/MockRRGeneratorWithAppTokenSecret.java
+++ b/src/test/java/com/univapay/sdk/utils/MockRRGeneratorWithAppTokenSecret.java
@@ -1,6 +1,7 @@
package com.univapay.sdk.utils;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED;
import com.github.tomakehurst.wiremock.client.MappingBuilder;
import com.github.tomakehurst.wiremock.http.HttpHeader;
@@ -8,7 +9,9 @@
import com.univapay.sdk.constants.UnivapayConstants;
import com.univapay.sdk.models.common.IdempotencyKey;
import com.univapay.sdk.types.IdempotencyStatus;
+import java.util.Arrays;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
public class MockRRGeneratorWithAppTokenSecret implements MockServer {
@@ -155,4 +158,58 @@ public void GenerateMockRequestResponse(
headerMap);
stubFor(stub);
}
+
+ // Useful for charge monitor tests...
+ public void GenerateMockQueuedRequestResponse(
+ String method,
+ String path,
+ String app_token,
+ String secret,
+ int status,
+ String requestBody,
+ String... responseBody) {
+
+ AtomicInteger step = new AtomicInteger(0);
+ Arrays.stream(responseBody)
+ .limit(1)
+ .findFirst()
+ .ifPresent(
+ firstRequest -> {
+ MappingBuilder stub =
+ createStub(
+ RequestMethod.fromString(method),
+ path,
+ app_token,
+ secret,
+ status,
+ firstRequest,
+ requestBody,
+ null)
+ .inScenario(path)
+ .whenScenarioStateIs(STARTED)
+ .willSetStateTo("STEP " + step.incrementAndGet());
+ stubFor(stub);
+ });
+
+ Arrays.stream(responseBody)
+ .skip(1)
+ .forEachOrdered(
+ otherRequests -> {
+ MappingBuilder stub =
+ createStub(
+ RequestMethod.fromString(method),
+ path,
+ app_token,
+ secret,
+ status,
+ otherRequests,
+ requestBody,
+ null)
+ .inScenario(path)
+ .whenScenarioStateIs("STEP " + step.get())
+ .willSetStateTo("STEP " + step.incrementAndGet());
+
+ stubFor(stub);
+ });
+ }
}
diff --git a/src/test/java/com/univapay/sdk/utils/mockcontent/ChargesFakeRR.java b/src/test/java/com/univapay/sdk/utils/mockcontent/ChargesFakeRR.java
index 77c8fd9f..09a64adf 100644
--- a/src/test/java/com/univapay/sdk/utils/mockcontent/ChargesFakeRR.java
+++ b/src/test/java/com/univapay/sdk/utils/mockcontent/ChargesFakeRR.java
@@ -227,6 +227,14 @@ public static String createFullChargeWithComplexMetadataFakeRequest(String captu
+ " \"created_on\": null\n"
+ "}";
+ public static String createStoreChargeOnlineRequest =
+ JsonLoader.loadJson("requests/charges/post-create-charge-online-request.json");
+
+ public static String createStoreChargeOnlineResponse =
+ JsonLoader.loadJson("responses/charges/post-create-charge-online-response.json");
+ public static String createStoreChargeOnlineDeferredResponse =
+ JsonLoader.loadJson("responses/charges/post-create-charge-online-deferred-response.json");
+
public static String createStoreChargeNoMetadataFakeResponse =
"{\n"
+ " \"id\": \"425e88b7-b588-4247-80ee-0ea0caff1190\",\n"
diff --git a/src/test/java/com/univapay/sdk/utils/mockcontent/IssuerTokensFakeRR.java b/src/test/java/com/univapay/sdk/utils/mockcontent/IssuerTokensFakeRR.java
index 868e53f0..497535b9 100644
--- a/src/test/java/com/univapay/sdk/utils/mockcontent/IssuerTokensFakeRR.java
+++ b/src/test/java/com/univapay/sdk/utils/mockcontent/IssuerTokensFakeRR.java
@@ -3,4 +3,7 @@
public class IssuerTokensFakeRR {
public static final String getIssuerTokenFakeResponse =
JsonLoader.loadJson("responses/issuerToken/get-issuer-token.json");
+
+ public static final String getIssuerTokenForAlipayPlusAppResponse =
+ JsonLoader.loadJson("responses/issuerToken/get-issuer-token-alipay-plus-app.json");
}
diff --git a/src/test/java/com/univapay/sdk/utils/mockcontent/StoreFakeRR.java b/src/test/java/com/univapay/sdk/utils/mockcontent/StoreFakeRR.java
index d9d114f8..6fde6e19 100644
--- a/src/test/java/com/univapay/sdk/utils/mockcontent/StoreFakeRR.java
+++ b/src/test/java/com/univapay/sdk/utils/mockcontent/StoreFakeRR.java
@@ -608,6 +608,11 @@ public class StoreFakeRR {
public static String createFullTransactionTokenWithOnlinePaymentFakeRequest =
JsonLoader.loadJson("requests/transactiontoken/post-online-full.json");
+ public static String createTransactionTokenAlipayPlusDynamicBrandRequest =
+ JsonLoader.loadJson("requests/transactiontoken/post-online-alipay-plus-dynamic-brand.json");
+ public static String createTransactionTokenAlipayPlusDynamicBrandResponse =
+ JsonLoader.loadJson("responses/transactiontoken/post-online-alipay-plus-dynamic-brand.json");
+
public static String createRecurringTransactionTokenFakeRequest =
"{\"payment_type\":\"card\",\"email\":\"some@email.com\",\"type\":\"recurring\", \"metadata\" : { }, \"usage_limit\":\"weekly\" ,\"data\":{\"cardholder\":\"full name\",\"card_number\":\"4556137309615276\",\"exp_month\":12,\"exp_year\":2018,\"cvv\":599,\"line1\":\"somewhere\",\"city\":\"Tokyo\",\"country\":\"JP\",\"zip\":\"111-1111\"}}";
@@ -962,4 +967,17 @@ public class StoreFakeRR {
public static String createCardTransactionTokenFullRequest =
JsonLoader.loadJson("requests/transactiontoken/post-card-full.json");
+
+ public static String getDynamicInfoAlipayPlusResponse =
+ JsonLoader.loadJson("responses/checkoutInfo/post-dynamic-brands-alipay-plus-online.json");
+ public static String getDynamicInfoAlipayPlusRequest =
+ JsonLoader.loadJson("requests/checkoutInfo/post-dynamic-brands-alipay-plus-online.json");
+
+ public static String getDynamicInfoEmpty =
+ JsonLoader.loadJson("responses/checkoutInfo/post-dynamic-brands-empty.json");
+ public static String getDynamicInfoOtherInput =
+ JsonLoader.loadJson("requests/checkoutInfo/post-dynamic-brands-other-input.json");
+
+ public static String getDynamicInfoWithoutOsTypeInput =
+ JsonLoader.loadJson("requests/checkoutInfo/post-dynamic-brands-without-os-type-input.json");
}
diff --git a/src/test/resources/requests/charges/post-create-charge-online-request.json b/src/test/resources/requests/charges/post-create-charge-online-request.json
new file mode 100644
index 00000000..89b59723
--- /dev/null
+++ b/src/test/resources/requests/charges/post-create-charge-online-request.json
@@ -0,0 +1,5 @@
+{
+ "transaction_token_id": "004b391f-1c98-43f8-87de-28b21aaaca00",
+ "amount": 100,
+ "currency": "JPY"
+}
\ No newline at end of file
diff --git a/src/test/resources/requests/checkoutInfo/post-dynamic-brands-alipay-plus-online.json b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-alipay-plus-online.json
new file mode 100644
index 00000000..c53aadf4
--- /dev/null
+++ b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-alipay-plus-online.json
@@ -0,0 +1,8 @@
+{
+ "amount": {
+ "value": 1000,
+ "currency": "JPY"
+ },
+ "call_method": "app",
+ "os_type": "i_os"
+}
\ No newline at end of file
diff --git a/src/test/resources/requests/checkoutInfo/post-dynamic-brands-other-input.json b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-other-input.json
new file mode 100644
index 00000000..9bee98d3
--- /dev/null
+++ b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-other-input.json
@@ -0,0 +1,8 @@
+{
+ "amount": {
+ "value": 12000,
+ "currency": "JPY"
+ },
+ "call_method": "app",
+ "os_type": "i_os"
+}
\ No newline at end of file
diff --git a/src/test/resources/requests/checkoutInfo/post-dynamic-brands-without-os-type-input.json b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-without-os-type-input.json
new file mode 100644
index 00000000..9d8e332a
--- /dev/null
+++ b/src/test/resources/requests/checkoutInfo/post-dynamic-brands-without-os-type-input.json
@@ -0,0 +1,7 @@
+{
+ "amount": {
+ "value": 12000,
+ "currency": "JPY"
+ },
+ "call_method": "app"
+}
\ No newline at end of file
diff --git a/src/test/resources/requests/transactiontoken/post-online-alipay-plus-dynamic-brand.json b/src/test/resources/requests/transactiontoken/post-online-alipay-plus-dynamic-brand.json
new file mode 100644
index 00000000..6238dca7
--- /dev/null
+++ b/src/test/resources/requests/transactiontoken/post-online-alipay-plus-dynamic-brand.json
@@ -0,0 +1,10 @@
+{
+ "payment_type": "online",
+ "type": "one_time",
+ "metadata": {},
+ "data": {
+ "brand": "KAKAOPAY",
+ "call_method": "app",
+ "os_type": "i_os"
+ }
+}
diff --git a/src/test/resources/responses/charges/post-create-charge-online-deferred-response.json b/src/test/resources/responses/charges/post-create-charge-online-deferred-response.json
new file mode 100644
index 00000000..a425bd33
--- /dev/null
+++ b/src/test/resources/responses/charges/post-create-charge-online-deferred-response.json
@@ -0,0 +1,23 @@
+{
+ "id" : "11ec8336-de56-9a4c-935e-6f39db819b28",
+ "store_id" : "11ec8336-dcea-f374-80a8-174b9ae64898",
+ "transaction_token_id" : "11ec8336-dd10-c8b1-89f7-55d3da73e140",
+ "transaction_token_type" : "one_time",
+ "subscription_id" : null,
+ "merchant_transaction_id" : null,
+ "requested_amount" : 1000,
+ "requested_currency" : "JPY",
+ "requested_amount_formatted" : 1000,
+ "charged_amount" : null,
+ "charged_currency" : null,
+ "charged_amount_formatted" : null,
+ "only_direct_currency" : false,
+ "capture_at" : null,
+ "descriptor" : null,
+ "descriptor_phone_number" : null,
+ "status" : "awaiting",
+ "error" : null,
+ "metadata" : {},
+ "mode" : "live_test",
+ "created_on" : "2022-02-01T17:13:42.467203+09:00"
+}
diff --git a/src/test/resources/responses/charges/post-create-charge-online-response.json b/src/test/resources/responses/charges/post-create-charge-online-response.json
new file mode 100644
index 00000000..036a9f4d
--- /dev/null
+++ b/src/test/resources/responses/charges/post-create-charge-online-response.json
@@ -0,0 +1,23 @@
+{
+ "id" : "11ec8336-de56-9a4c-935e-6f39db819b28",
+ "store_id" : "11ec8336-dcea-f374-80a8-174b9ae64898",
+ "transaction_token_id" : "11ec8336-dd10-c8b1-89f7-55d3da73e140",
+ "transaction_token_type" : "one_time",
+ "subscription_id" : null,
+ "merchant_transaction_id" : null,
+ "requested_amount" : 1000,
+ "requested_currency" : "JPY",
+ "requested_amount_formatted" : 1000,
+ "charged_amount" : null,
+ "charged_currency" : null,
+ "charged_amount_formatted" : null,
+ "only_direct_currency" : false,
+ "capture_at" : null,
+ "descriptor" : null,
+ "descriptor_phone_number" : null,
+ "status" : "pending",
+ "error" : null,
+ "metadata" : {},
+ "mode" : "live_test",
+ "created_on" : "2022-02-01T17:13:42.467203+09:00"
+}
diff --git a/src/test/resources/responses/checkoutInfo/get-checkout-info.json b/src/test/resources/responses/checkoutInfo/get-checkout-info.json
index 99ba90e0..b9483864 100644
--- a/src/test/resources/responses/checkoutInfo/get-checkout-info.json
+++ b/src/test/resources/responses/checkoutInfo/get-checkout-info.json
@@ -150,6 +150,7 @@
},
{
"card_brand": "maestro",
+ "dynamic_info": false,
"support_auth_capture": true,
"requires_full_name": true,
"requires_cvv": true,
@@ -162,6 +163,7 @@
},
{
"card_brand": "american_express",
+ "dynamic_info": false,
"support_auth_capture": true,
"requires_full_name": false,
"requires_cvv": false,
diff --git a/src/test/resources/responses/checkoutInfo/post-dynamic-brands-alipay-plus-online.json b/src/test/resources/responses/checkoutInfo/post-dynamic-brands-alipay-plus-online.json
new file mode 100644
index 00000000..1ed421db
--- /dev/null
+++ b/src/test/resources/responses/checkoutInfo/post-dynamic-brands-alipay-plus-online.json
@@ -0,0 +1,46 @@
+{
+ "brands": [
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "ALIPAY_HK",
+ "sub_brand_logo": "http://localhost/icon/ALIPAY_HK.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "BPI",
+ "sub_brand_logo": "http://localhost/icon/BPI.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "GCASH",
+ "sub_brand_logo": "http://localhost/icon/GCASH.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "KAKAOPAY",
+ "sub_brand_logo": "http://localhost/icon/KAKAOPAY.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "RABBIT_LINE_PAY",
+ "sub_brand_logo": "http://localhost/icon/RABBIT_LINE_PAY.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "TNG",
+ "sub_brand_logo": "http://localhost/icon/TNG.svg"
+ },
+ {
+ "brand_name": "CONNECT_WALLET",
+ "brand_logo": "http://localhost/CONNECT_WALLET.svg",
+ "sub_brand_name": "TRUEMONEY",
+ "sub_brand_logo": "http://localhost/icon/TRUEMONEY.svg"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/test/resources/responses/checkoutInfo/post-dynamic-brands-empty.json b/src/test/resources/responses/checkoutInfo/post-dynamic-brands-empty.json
new file mode 100644
index 00000000..a1bd9737
--- /dev/null
+++ b/src/test/resources/responses/checkoutInfo/post-dynamic-brands-empty.json
@@ -0,0 +1,3 @@
+{
+ "brands": []
+}
\ No newline at end of file
diff --git a/src/test/resources/responses/issuerToken/get-issuer-token-alipay-plus-app.json b/src/test/resources/responses/issuerToken/get-issuer-token-alipay-plus-app.json
new file mode 100644
index 00000000..c391ca26
--- /dev/null
+++ b/src/test/resources/responses/issuerToken/get-issuer-token-alipay-plus-app.json
@@ -0,0 +1,4 @@
+{
+ "issuer_token" : "alipayconnect://schemeUrl",
+ "call_method" : "app"
+}
\ No newline at end of file
diff --git a/src/test/resources/responses/transactiontoken/post-online-alipay-plus-dynamic-brand.json b/src/test/resources/responses/transactiontoken/post-online-alipay-plus-dynamic-brand.json
new file mode 100644
index 00000000..00d1d9ea
--- /dev/null
+++ b/src/test/resources/responses/transactiontoken/post-online-alipay-plus-dynamic-brand.json
@@ -0,0 +1,13 @@
+{
+ "id": "004b391f-1c98-43f8-87de-28b21aaaca00",
+ "store_id": "bf75472e-7f2d-4745-a66d-9b96ae031c7a",
+ "mode": "live",
+ "type": "one_time",
+ "created_on": "2017-06-22T16:00:55.436116+09:00",
+ "payment_type": "online",
+ "data": {
+ "brand": "KAKAOPAY",
+ "call_site" : "sdk",
+ "os_type" : "i_os"
+ }
+}
\ No newline at end of file