Skip to content

Commit

Permalink
Create SourceParams.createCardParamsFromGooglePay() (#1315)
Browse files Browse the repository at this point in the history
* Create SourceParams.createCardParamsFromGooglePay()

Create a SourceParams object from Google Pay result
  • Loading branch information
mshafrir-stripe authored Aug 6, 2019
1 parent 2540cda commit 104cacc
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 63 deletions.
110 changes: 104 additions & 6 deletions stripe/src/main/java/com/stripe/android/model/SourceParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
import android.support.annotation.Nullable;
import android.support.annotation.Size;

import com.stripe.android.utils.ObjectUtils;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.stripe.android.StripeNetworkUtils.removeNullAndEmptyParams;
import static com.stripe.android.model.Source.SourceType;
Expand Down Expand Up @@ -42,6 +48,7 @@ public final class SourceParams {
private static final String FIELD_LINE_2 = "line2";
private static final String FIELD_NAME = "name";
private static final String FIELD_NUMBER = "number";
private static final String FIELD_PHONE = "phone";
private static final String FIELD_POSTAL_CODE = "postal_code";
private static final String FIELD_RETURN_URL = "return_url";
private static final String FIELD_STATE = "state";
Expand Down Expand Up @@ -247,10 +254,9 @@ public static SourceParams createCustomParams() {
*/
@NonNull
public static SourceParams createSourceFromTokenParams(@NonNull String tokenId) {
SourceParams sourceParams = SourceParams.createCustomParams();
sourceParams.setType(SourceType.CARD);
sourceParams.setToken(tokenId);
return sourceParams;
return SourceParams.createCustomParams()
.setType(SourceType.CARD)
.setToken(tokenId);
}

/**
Expand All @@ -276,7 +282,7 @@ public static SourceParams createCardParams(@NonNull Card card) {

params.setApiParameterMap(basicInfoMap);

final Map<String, Object> addressMap = new HashMap<>();
final AbstractMap<String, Object> addressMap = new HashMap<>();
addressMap.put(FIELD_LINE_1, card.getAddressLine1());
addressMap.put(FIELD_LINE_2, card.getAddressLine2());
addressMap.put(FIELD_CITY, card.getAddressCity());
Expand All @@ -286,7 +292,7 @@ public static SourceParams createCardParams(@NonNull Card card) {
removeNullAndEmptyParams(addressMap);

// If there are any keys left...
final Map<String, Object> ownerMap = new HashMap<>();
final AbstractMap<String, Object> ownerMap = new HashMap<>();
ownerMap.put(FIELD_NAME, card.getName());
if (addressMap.keySet().size() > 0) {
ownerMap.put(FIELD_ADDRESS, addressMap);
Expand All @@ -304,6 +310,73 @@ public static SourceParams createCardParams(@NonNull Card card) {
return params;
}

/**
* @param googlePayPaymentData a {@link JSONObject} derived from Google Pay's
* <a href="https://developers.google.com/pay/api/android/reference/client#tojson">PaymentData#toJson()</a>
*/
@NonNull
public static SourceParams createCardParamsFromGooglePay(
@NonNull JSONObject googlePayPaymentData)
throws JSONException {
final JSONObject paymentMethodData = googlePayPaymentData
.getJSONObject("paymentMethodData");
final JSONObject googlePayBillingAddress = paymentMethodData
.getJSONObject("info")
.optJSONObject("billingAddress");
final String paymentToken = paymentMethodData
.getJSONObject("tokenizationData")
.getString("token");
final Token stripeToken = Token.fromJson(new JSONObject(paymentToken));
final String stripeTokenId = Objects.requireNonNull(stripeToken).getId();

final SourceParams params = new SourceParams()
.setType(SourceType.CARD)
.setToken(stripeTokenId);
final Map<String, Object> addressMap;
final String phone;
final String name;
if (googlePayBillingAddress != null) {
name = googlePayBillingAddress.optString("name");
phone = googlePayBillingAddress.optString("phoneNumber");
addressMap = new HashMap<>();
addressMap.put(FIELD_LINE_1,
googlePayBillingAddress.optString("address1"));
addressMap.put(FIELD_LINE_2,
googlePayBillingAddress.optString("address2"));
addressMap.put(FIELD_CITY,
googlePayBillingAddress.optString("locality"));
addressMap.put(FIELD_COUNTRY,
googlePayBillingAddress.optString("countryCode"));
addressMap.put(FIELD_STATE,
googlePayBillingAddress.optString("administrativeArea"));
addressMap.put(FIELD_POSTAL_CODE,
googlePayBillingAddress.optString("postalCode"));
removeNullAndEmptyParams(addressMap);
} else {
name = null;
phone = null;
addressMap = null;
}

final Map<String, Object> ownerMap = new HashMap<>();
ownerMap.put(FIELD_EMAIL, googlePayPaymentData.optString("email"));
if (name != null) {
ownerMap.put(FIELD_NAME, name);
}
if (phone != null) {
ownerMap.put(FIELD_PHONE, phone);
}
if (addressMap != null && !addressMap.isEmpty()) {
ownerMap.put(FIELD_ADDRESS, addressMap);
}
removeNullAndEmptyParams(ownerMap);
if (!ownerMap.isEmpty()) {
params.setOwner(ownerMap);
}

return params;
}

/**
* Create parameters necessary for creating an EPS source.
*
Expand Down Expand Up @@ -877,4 +950,29 @@ private static Map<String, Object> createSimpleMap(
simpleMap.put(key2, value2);
return simpleMap;
}

@Override
public int hashCode() {
return ObjectUtils.hash(mAmount, mApiParameterMap, mCurrency, mTypeRaw, mOwner, mMetaData,
mRedirect, mExtraParams, mToken, mUsage, mType);
}

@Override
public boolean equals(@Nullable Object obj) {
return this == obj || (obj instanceof SourceParams && typedEquals((SourceParams) obj));
}

private boolean typedEquals(@NonNull SourceParams params) {
return ObjectUtils.equals(mAmount, params.mAmount) &&
ObjectUtils.equals(mApiParameterMap, params.mApiParameterMap) &&
ObjectUtils.equals(mCurrency, params.mCurrency) &&
ObjectUtils.equals(mTypeRaw, params.mTypeRaw) &&
ObjectUtils.equals(mOwner, params.mOwner) &&
ObjectUtils.equals(mMetaData, params.mMetaData) &&
ObjectUtils.equals(mRedirect, params.mRedirect) &&
ObjectUtils.equals(mExtraParams, params.mExtraParams) &&
ObjectUtils.equals(mToken, params.mToken) &&
ObjectUtils.equals(mUsage, params.mUsage) &&
ObjectUtils.equals(mType, params.mType);
}
}
10 changes: 5 additions & 5 deletions stripe/src/test/java/com/stripe/android/StripeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ public void create(@NonNull Map<String, Object> tokenParams,
@Test
public void createCardTokenSynchronous_withValidData_returnsToken()
throws StripeException {
final Stripe stripe = createLoggingStripe();
final Stripe stripe = createNonLoggingStripe();
final Token token = stripe.createTokenSynchronous(CARD);

assertNotNull(token);
Expand Down Expand Up @@ -320,9 +320,9 @@ public void createToken_createSource_returnsSource()
final Token token = stripe.createTokenSynchronous(CARD);
assertNotNull(token);

final SourceParams sourceParams = SourceParams.createCustomParams();
sourceParams.setType(Source.SourceType.CARD);
sourceParams.setToken(token.getId());
final SourceParams sourceParams = SourceParams.createCustomParams()
.setType(Source.SourceType.CARD)
.setToken(token.getId());

final Source source = stripe.createSourceSynchronous(sourceParams);
assertNotNull(source);
Expand Down Expand Up @@ -963,7 +963,7 @@ public void retrieveSourceSynchronous_withValidData_passesIntegrationTest()
@Test
public void createTokenSynchronous_withValidPersonalId_passesIntegrationTest()
throws StripeException {
final Stripe stripe = createLoggingStripe();
final Stripe stripe = createNonLoggingStripe();
final Token token = stripe.createPiiTokenSynchronous("0123456789");
assertNotNull(token);
assertEquals(Token.TokenType.PII, token.getType());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.stripe.android.model;

import android.support.annotation.NonNull;

import org.json.JSONException;
import org.json.JSONObject;

final class GooglePayFixtures {
@NonNull private static final String GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS_RAW = "{\n" +
"\t\"apiVersionMinor\": 0,\n" +
"\t\"apiVersion\": 2,\n" +
"\t\"paymentMethodData\": {\n" +
"\t\t\"description\": \"Visa •••• 1234\",\n" +
"\t\t\"tokenizationData\": {\n" +
"\t\t\t\"type\": \"PAYMENT_GATEWAY\",\n" +
"\t\t\t\"token\": \"{\\n \\\"id\\\": \\\"tok_1F4ACMCRMbs6FrXf6fPqLnN7\\\",\\n \\\"object\\\": \\\"token\\\",\\n \\\"card\\\": {\\n \\\"id\\\": \\\"card_1F4AzKCRMbs6FrXf1nX87nde\\\",\\n \\\"object\\\": \\\"card\\\",\\n \\\"address_city\\\": null,\\n \\\"address_country\\\": null,\\n \\\"address_line1\\\": null,\\n \\\"address_line1_check\\\": null,\\n \\\"address_line2\\\": null,\\n \\\"address_state\\\": null,\\n \\\"address_zip\\\": null,\\n \\\"address_zip_check\\\": null,\\n \\\"brand\\\": \\\"Visa\\\",\\n \\\"country\\\": \\\"US\\\",\\n \\\"cvc_check\\\": null,\\n \\\"dynamic_last4\\\": \\\"4242\\\",\\n \\\"exp_month\\\": 12,\\n \\\"exp_year\\\": 2024,\\n \\\"funding\\\": \\\"credit\\\",\\n \\\"last4\\\": \\\"1234\\\",\\n \\\"metadata\\\": {\\n },\\n \\\"name\\\": \\\"Stripe Johnson\\\",\\n \\\"tokenization_method\\\": \\\"android_pay\\\"\\n },\\n \\\"client_ip\\\": \\\"74.125.113.96\\\",\\n \\\"created\\\": 1565029974,\\n \\\"livemode\\\": false,\\n \\\"type\\\": \\\"card\\\",\\n \\\"used\\\": false\\n}\\n\"\n" +
"\t\t},\n" +
"\t\t\"type\": \"CARD\",\n" +
"\t\t\"info\": {\n" +
"\t\t\t\"cardNetwork\": \"VISA\",\n" +
"\t\t\t\"cardDetails\": \"1234\"\n" +
"\t\t}\n" +
"\t}\n" +
"}";

@NonNull private static final String GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS_RAW = "{\n" +
"\t\"apiVersionMinor\": 0,\n" +
"\t\"apiVersion\": 2,\n" +
"\t\"paymentMethodData\": {\n" +
"\t\t\"description\": \"Visa •••• 1234\",\n" +
"\t\t\"tokenizationData\": {\n" +
"\t\t\t\"type\": \"PAYMENT_GATEWAY\",\n" +
"\t\t\t\"token\": \"{\\n \\\"id\\\": \\\"tok_1F4VSjBbvEcIpqUbSsbEtBap\\\",\\n \\\"object\\\": \\\"token\\\",\\n \\\"card\\\": {\\n \\\"id\\\": \\\"card_1F4B7Q\\\",\\n \\\"object\\\": \\\"card\\\",\\n \\\"address_city\\\": \\\"San Francisco\\\",\\n \\\"address_country\\\": \\\"US\\\",\\n \\\"address_line1\\\": \\\"510 Townsend Street\\\",\\n \\\"address_line1_check\\\": \\\"unchecked\\\",\\n \\\"address_line2\\\": null,\\n \\\"address_state\\\": \\\"CA\\\",\\n \\\"address_zip\\\": \\\"20895\\\",\\n \\\"address_zip_check\\\": \\\"unchecked\\\",\\n \\\"brand\\\": \\\"Visa\\\",\\n \\\"country\\\": \\\"US\\\",\\n \\\"cvc_check\\\": null,\\n \\\"dynamic_last4\\\": \\\"4242\\\",\\n \\\"exp_month\\\": 12,\\n \\\"exp_year\\\": 2024,\\n \\\"funding\\\": \\\"credit\\\",\\n \\\"last4\\\": \\\"1234\\\",\\n \\\"metadata\\\": {\\n },\\n \\\"name\\\": \\\"Stripe Johnson\\\",\\n \\\"tokenization_method\\\": \\\"android_pay\\\"\\n },\\n \\\"client_ip\\\": \\\"74.125.113.98\\\",\\n \\\"created\\\": 1565030476,\\n \\\"livemode\\\": false,\\n \\\"type\\\": \\\"card\\\",\\n \\\"used\\\": false\\n}\\n\"\n" +
"\t\t},\n" +
"\t\t\"type\": \"CARD\",\n" +
"\t\t\"info\": {\n" +
"\t\t\t\"cardNetwork\": \"VISA\",\n" +
"\t\t\t\"cardDetails\": \"1234\",\n" +
"\t\t\t\"billingAddress\": {\n" +
"\t\t\t\t\"phoneNumber\": \"1-888-555-1234\",\n" +
"\t\t\t\t\"address3\": \"\",\n" +
"\t\t\t\t\"sortingCode\": \"\",\n" +
"\t\t\t\t\"address2\": \"\",\n" +
"\t\t\t\t\"countryCode\": \"US\",\n" +
"\t\t\t\t\"address1\": \"510 Townsend St\",\n" +
"\t\t\t\t\"postalCode\": \"94103\",\n" +
"\t\t\t\t\"name\": \"Stripe Johnson\",\n" +
"\t\t\t\t\"locality\": \"San Francisco\",\n" +
"\t\t\t\t\"administrativeArea\": \"CA\"\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t},\n" +
"\t\"email\": \"stripe@example.com\"" +
"}";

@NonNull
static final JSONObject GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS;

@NonNull
static final JSONObject GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS;

static {
try {
GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS =
new JSONObject(GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS_RAW);
GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS =
new JSONObject(GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS_RAW);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}

private GooglePayFixtures() {}
}
Original file line number Diff line number Diff line change
@@ -1,60 +1,12 @@
package com.stripe.android.model;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class PaymentMethodCreateParamsTest {

private static final String GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS = "{\n" +
"\t\"apiVersionMinor\": 0,\n" +
"\t\"apiVersion\": 2,\n" +
"\t\"paymentMethodData\": {\n" +
"\t\t\"description\": \"Visa •••• 1234\",\n" +
"\t\t\"tokenizationData\": {\n" +
"\t\t\t\"type\": \"PAYMENT_GATEWAY\",\n" +
"\t\t\t\"token\": \"{\\n \\\"id\\\": \\\"tok_1F4AzK\\\",\\n \\\"object\\\": \\\"token\\\",\\n \\\"card\\\": {\\n \\\"id\\\": \\\"card_1F4AzKCRMbs6FrXf1nX87nde\\\",\\n \\\"object\\\": \\\"card\\\",\\n \\\"address_city\\\": null,\\n \\\"address_country\\\": null,\\n \\\"address_line1\\\": null,\\n \\\"address_line1_check\\\": null,\\n \\\"address_line2\\\": null,\\n \\\"address_state\\\": null,\\n \\\"address_zip\\\": null,\\n \\\"address_zip_check\\\": null,\\n \\\"brand\\\": \\\"Visa\\\",\\n \\\"country\\\": \\\"US\\\",\\n \\\"cvc_check\\\": null,\\n \\\"dynamic_last4\\\": \\\"4242\\\",\\n \\\"exp_month\\\": 12,\\n \\\"exp_year\\\": 2024,\\n \\\"funding\\\": \\\"credit\\\",\\n \\\"last4\\\": \\\"1234\\\",\\n \\\"metadata\\\": {\\n },\\n \\\"name\\\": \\\"Stripe Johnson\\\",\\n \\\"tokenization_method\\\": \\\"android_pay\\\"\\n },\\n \\\"client_ip\\\": \\\"74.125.113.96\\\",\\n \\\"created\\\": 1565029974,\\n \\\"livemode\\\": false,\\n \\\"type\\\": \\\"card\\\",\\n \\\"used\\\": false\\n}\\n\"\n" +
"\t\t},\n" +
"\t\t\"type\": \"CARD\",\n" +
"\t\t\"info\": {\n" +
"\t\t\t\"cardNetwork\": \"VISA\",\n" +
"\t\t\t\"cardDetails\": \"1234\"\n" +
"\t\t}\n" +
"\t}\n" +
"}";

private static final String GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS = "{\n" +
"\t\"apiVersionMinor\": 0,\n" +
"\t\"apiVersion\": 2,\n" +
"\t\"paymentMethodData\": {\n" +
"\t\t\"description\": \"Visa •••• 1234\",\n" +
"\t\t\"tokenizationData\": {\n" +
"\t\t\t\"type\": \"PAYMENT_GATEWAY\",\n" +
"\t\t\t\"token\": \"{\\n \\\"id\\\": \\\"tok_1F4B7Q\\\",\\n \\\"object\\\": \\\"token\\\",\\n \\\"card\\\": {\\n \\\"id\\\": \\\"card_1F4B7Q\\\",\\n \\\"object\\\": \\\"card\\\",\\n \\\"address_city\\\": \\\"San Francisco\\\",\\n \\\"address_country\\\": \\\"US\\\",\\n \\\"address_line1\\\": \\\"510 Townsend Street\\\",\\n \\\"address_line1_check\\\": \\\"unchecked\\\",\\n \\\"address_line2\\\": null,\\n \\\"address_state\\\": \\\"CA\\\",\\n \\\"address_zip\\\": \\\"20895\\\",\\n \\\"address_zip_check\\\": \\\"unchecked\\\",\\n \\\"brand\\\": \\\"Visa\\\",\\n \\\"country\\\": \\\"US\\\",\\n \\\"cvc_check\\\": null,\\n \\\"dynamic_last4\\\": \\\"4242\\\",\\n \\\"exp_month\\\": 12,\\n \\\"exp_year\\\": 2024,\\n \\\"funding\\\": \\\"credit\\\",\\n \\\"last4\\\": \\\"1234\\\",\\n \\\"metadata\\\": {\\n },\\n \\\"name\\\": \\\"Stripe Johnson\\\",\\n \\\"tokenization_method\\\": \\\"android_pay\\\"\\n },\\n \\\"client_ip\\\": \\\"74.125.113.98\\\",\\n \\\"created\\\": 1565030476,\\n \\\"livemode\\\": false,\\n \\\"type\\\": \\\"card\\\",\\n \\\"used\\\": false\\n}\\n\"\n" +
"\t\t},\n" +
"\t\t\"type\": \"CARD\",\n" +
"\t\t\"info\": {\n" +
"\t\t\t\"cardNetwork\": \"VISA\",\n" +
"\t\t\t\"cardDetails\": \"1234\",\n" +
"\t\t\t\"billingAddress\": {\n" +
"\t\t\t\t\"phoneNumber\": \"1-888-555-1234\",\n" +
"\t\t\t\t\"address3\": \"\",\n" +
"\t\t\t\t\"sortingCode\": \"\",\n" +
"\t\t\t\t\"address2\": \"\",\n" +
"\t\t\t\t\"countryCode\": \"US\",\n" +
"\t\t\t\t\"address1\": \"510 Townsend St\",\n" +
"\t\t\t\t\"postalCode\": \"94103\",\n" +
"\t\t\t\t\"name\": \"Stripe Johnson\",\n" +
"\t\t\t\t\"locality\": \"San Francisco\",\n" +
"\t\t\t\t\"administrativeArea\": \"CA\"\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t},\n" +
"\t\"email\": \"stripe@example.com\"" +
"}";

@Test
public void card_toPaymentMethodParamsCard() {
final PaymentMethodCreateParams.Card expectedCard =
Expand All @@ -71,10 +23,10 @@ public void card_toPaymentMethodParamsCard() {
public void createFromGooglePay_withNoBillingAddress() throws JSONException {
final PaymentMethodCreateParams createdParams =
PaymentMethodCreateParams.createFromGooglePay(
new JSONObject(GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS));
GooglePayFixtures.GOOGLE_PAY_RESULT_WITH_NO_BILLING_ADDRESS);

final PaymentMethodCreateParams expectedParams = PaymentMethodCreateParams.create(
PaymentMethodCreateParams.Card.create("tok_1F4AzK"),
PaymentMethodCreateParams.Card.create("tok_1F4ACMCRMbs6FrXf6fPqLnN7"),
new PaymentMethod.BillingDetails.Builder()
.setEmail("")
.build()
Expand All @@ -86,10 +38,10 @@ public void createFromGooglePay_withNoBillingAddress() throws JSONException {
public void createFromGooglePay_withFullBillingAddress() throws JSONException {
final PaymentMethodCreateParams createdParams =
PaymentMethodCreateParams.createFromGooglePay(
new JSONObject(GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS));
GooglePayFixtures.GOOGLE_PAY_RESULT_WITH_FULL_BILLING_ADDRESS);

final PaymentMethodCreateParams expectedParams = PaymentMethodCreateParams.create(
PaymentMethodCreateParams.Card.create("tok_1F4B7Q"),
PaymentMethodCreateParams.Card.create("tok_1F4VSjBbvEcIpqUbSsbEtBap"),
new PaymentMethod.BillingDetails.Builder()
.setPhone("1-888-555-1234")
.setEmail("stripe@example.com")
Expand Down
Loading

0 comments on commit 104cacc

Please sign in to comment.