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