Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bindings to support Custom Connect onboarding in Europe #492

Merged
merged 3 commits into from
Dec 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ licenses:

group: deprecated-2017Q3

before_install:
- yes | sdkmanager "platforms;android-27"

script:
- ./gradlew clean test
- ./gradlew clean :stripe:checkstyle
69 changes: 68 additions & 1 deletion stripe/src/main/java/com/stripe/android/Stripe.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.stripe.android.exception.CardException;
import com.stripe.android.exception.InvalidRequestException;
import com.stripe.android.exception.StripeException;
import com.stripe.android.model.AccountParams;
import com.stripe.android.model.BankAccount;
import com.stripe.android.model.Card;
import com.stripe.android.model.Source;
Expand All @@ -29,7 +30,7 @@
import static com.stripe.android.StripeNetworkUtils.hashMapFromPersonalId;

/**
* Class that handles {@link Token} creation from charges and {@link Card} models.
* Class that handles {@link Token} creation from charges, {@link Card}, and accounts.
*/
public class Stripe {

Expand Down Expand Up @@ -543,6 +544,72 @@ public Token createPiiTokenSynchronous(@NonNull String personalId, String publis
mLoggingResponseListener);
}

/**
* Blocking method to create a {@link Token} for a Connect Account. Do not call this on the UI
* thread or your app will crash. The method uses the currently set
* {@link #mDefaultPublishableKey}.
*
* @param accountParams params to use for this token.
* @return a {@link Token} that can be used for this account.
*
* @throws AuthenticationException failure to properly authenticate yourself (check your key)
* @throws InvalidRequestException your request has invalid parameters
* @throws APIConnectionException failure to connect to Stripe's API
* @throws APIException any other type of problem (for instance, a temporary issue with
* Stripe's servers)
*/
public Token createAccountTokenSynchronous(@NonNull final AccountParams accountParams)
throws AuthenticationException,
InvalidRequestException,
APIConnectionException,
APIException {
return createAccountTokenSynchronous(accountParams, mDefaultPublishableKey);
}

/**
* Blocking method to create a {@link Token} for a Connect Account. Do not call this on the UI
* thread.
*
* @param accountParams params to use for this token.
* @param publishableKey the publishable key to use with this request. If null is passed in as
* the publishable key, we will use the default publishable key.
* @return a {@link Token} that can be used for this account.
*
* @throws AuthenticationException failure to properly authenticate yourself (check your key)
* @throws InvalidRequestException your request has invalid parameters
* @throws APIConnectionException failure to connect to Stripe's API
* @throws APIException any other type of problem (for instance, a temporary issue with
* Stripe's servers)
*/
public Token createAccountTokenSynchronous(
@NonNull final AccountParams accountParams,
@Nullable String publishableKey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might document what this does if publishableKey is null.

throws AuthenticationException,
InvalidRequestException,
APIConnectionException,
APIException {
String apiKey = publishableKey == null ? mDefaultPublishableKey : publishableKey;
if (apiKey == null) {
return null;
}
validateKey(publishableKey);
RequestOptions requestOptions = RequestOptions.builder(
publishableKey,
mStripeAccount,
RequestOptions.TYPE_QUERY).build();
try {
return StripeApiHandler.createToken(
mContext,
accountParams.toParamMap(),
requestOptions,
Token.TYPE_ACCOUNT,
mLoggingResponseListener);
} catch (CardException exception) {
// Should never occur. CardException is only for card related requests.
}
return null;
}

public void logEventSynchronous(
@NonNull List<String> productUsageTokens,
@NonNull StripePaymentSource paymentSource) {
Expand Down
16 changes: 7 additions & 9 deletions stripe/src/main/java/com/stripe/android/StripeApiHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ static Source retrieveSource(
}

/**
* Create a {@link Token} using the input card parameters.
* Create a {@link Token} using the input token parameters.
*
* @param context the {@link Context} in which this method is working
* @param cardParams a mapped set of parameters representing the object for which this token
* @param tokenParams a mapped set of parameters representing the object for which this token
* is being created
* @param options a {@link RequestOptions} object that contains connection data like the api
* key, api version, etc
Expand All @@ -243,7 +243,7 @@ static Source retrieveSource(
@SuppressWarnings("unchecked")
static Token createToken(
@NonNull Context context,
@NonNull Map<String, Object> cardParams,
@NonNull Map<String, Object> tokenParams,
@NonNull RequestOptions options,
@NonNull @Token.TokenType String tokenType,
@Nullable LoggingResponseListener listener)
Expand All @@ -260,8 +260,8 @@ static Token createToken(
}

List<String> loggingTokens =
(List<String>) cardParams.get(LoggingUtils.FIELD_PRODUCT_USAGE);
cardParams.remove(LoggingUtils.FIELD_PRODUCT_USAGE);
(List<String>) tokenParams.get(LoggingUtils.FIELD_PRODUCT_USAGE);
tokenParams.remove(LoggingUtils.FIELD_PRODUCT_USAGE);

setTelemetryData(context, listener);

Expand All @@ -270,10 +270,10 @@ static Token createToken(
logApiCall(loggingParams, options, listener);
} catch (ClassCastException classCastEx) {
// This can only happen if someone puts a weird object in the map.
cardParams.remove(LoggingUtils.FIELD_PRODUCT_USAGE);
tokenParams.remove(LoggingUtils.FIELD_PRODUCT_USAGE);
}

return requestToken(POST, getApiUrl(), cardParams, options);
return requestToken(POST, getApiUrl(), tokenParams, options);
}

@Nullable
Expand Down Expand Up @@ -768,7 +768,6 @@ private static List<Parameter> flattenParamsMap(Map<String, Object> params, Stri
for (Map.Entry<String, Object> entry : params.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();

String newPrefix = key;
if (keyPrefix != null) {
newPrefix = String.format("%s[%s]", keyPrefix, key);
Expand All @@ -783,7 +782,6 @@ private static List<Parameter> flattenParamsMap(Map<String, Object> params, Stri
private static List<Parameter> flattenParamsValue(Object value, String keyPrefix)
throws InvalidRequestException {
List<Parameter> flatParams;

if (value instanceof Map<?, ?>) {
flatParams = flattenParamsMap((Map<String, Object>) value, keyPrefix);
} else if (value instanceof List<?>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.stripe.android.model;

import android.support.annotation.NonNull;

import java.util.HashMap;
import java.util.Map;

import static com.stripe.android.StripeNetworkUtils.removeNullAndEmptyParams;

/**
* Represents a grouping of parameters needed to create a Token for a Connect account on the server.
*/
public class AccountParams {

static final String API_PARAM_LEGAL_ENTITY = "legal_entity";
static final String API_TOS_SHOWN_AND_ACCEPTED = "tos_shown_and_accepted";
private Boolean mTosShownAndAccepted;
private Map<String, Object> mLegalEntity;

/**
* @param tosShownAndAccepted indicates that the platform showed the user the appropriate text
* and links to Stripe's terms of service. Tokens will only generated
* when this is true.
* @param legalEntity map that specifies the legal entity for which the connect account is being
* created. Can contain any of the fields specified by legal_entity in the
* API docs.
*
* See {@linktourl https://stripe.com/docs/api#account_object-legal_entity}
*
* The object in the map is expected to be a string or a list or map of
* strings. All {@link StripeJsonModel} types have a toMap() function that
* can be used to convert the {@link StripeJsonModel} to map representation
* that can be passed in here.
*/
public static AccountParams createAccountParams(
boolean tosShownAndAccepted,
Map<String, Object> legalEntity) {
AccountParams accountParams = new AccountParams()
.setTosShownAndAccepted(tosShownAndAccepted)
.setLegalEntity(legalEntity);
return accountParams;
}

/**
* @param tosShownAndAccepted whether the platform showed the user the appropriate text
* and links to Stripe's terms of service. Tokens will only generated
* when this is true.
* @return {@code this}, for chaining purposes
*/
public AccountParams setTosShownAndAccepted(boolean tosShownAndAccepted) {
mTosShownAndAccepted = tosShownAndAccepted;
return this;
}

/**
* @param legalEntity map that specifies the legal entity for which the connect account is being
* created. Can contain any of the fields specified by legal_entity in the
* API docs.
*
* See {@linktourl https://stripe.com/docs/api#account_object-legal_entity}
*
* The object in the map is expected to be a string or a list or map of
* strings. All {@link StripeJsonModel} types have a toMap() function that
* can be used to convert the {@link StripeJsonModel} to map representation
* that can be passed in here.
* @return {@code this}, for chaining purposes
*/
public AccountParams setLegalEntity(Map<String, Object> legalEntity) {
mLegalEntity = legalEntity;
return this;
}

/**
* Create a string-keyed map representing this object that is
* ready to be sent over the network.
*
* @return a String-keyed map
*/
@NonNull
public Map<String, Object> toParamMap() {
Map<String, Object> networkReadyMap = new HashMap<>();
Map<String, Object> tokenMap = new HashMap<>();
tokenMap.put(API_TOS_SHOWN_AND_ACCEPTED, mTosShownAndAccepted);
tokenMap.put(API_PARAM_LEGAL_ENTITY, mLegalEntity);
networkReadyMap.put("account", tokenMap);
removeNullAndEmptyParams(networkReadyMap);
return networkReadyMap;
}

}
17 changes: 11 additions & 6 deletions stripe/src/main/java/com/stripe/android/model/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@
import java.util.Date;

/**
* The model of a Stripe card token.
* Tokenization is the process Stripe uses to collect sensitive card, bank account details, Stripe
* account details or personally identifiable information (PII), directly from your customers in a
* secure manner. A Token representing this information is returned to you to use.
*/
public class Token implements StripePaymentSource {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation of the Token class should be updated. It's no longer just a card. I'd also link to the docs for Token, which is probably a good place to borrow text from. https://stripe.com/docs/api#tokens


@Retention(RetentionPolicy.SOURCE)
@StringDef({TYPE_CARD, TYPE_BANK_ACCOUNT, TYPE_PII})
@StringDef({TYPE_CARD, TYPE_BANK_ACCOUNT, TYPE_PII, TYPE_ACCOUNT})
public @interface TokenType {}
public static final String TYPE_CARD = "card";
public static final String TYPE_BANK_ACCOUNT = "bank_account";
public static final String TYPE_PII = "pii";
public static final String TYPE_ACCOUNT = "account";

// The key for these object fields is identical to their retrieved values
// from the Type field.
Expand Down Expand Up @@ -85,12 +88,13 @@ public Token(
*/
public Token(
String id,
String type,
boolean livemode,
Date created,
Boolean used
) {
mId = id;
mType = TYPE_PII;
mType = type;
mCreated = created;
mCard = null;
mBankAccount = null;
Expand Down Expand Up @@ -192,10 +196,9 @@ public static Token fromJson(@Nullable JSONObject jsonObject) {
}
Card card = Card.fromJson(cardObject);
token = new Token(tokenId, liveMode, date, used, card);
} else if (Token.TYPE_PII.equals(tokenType)) {
token = new Token(tokenId, liveMode, date, used);
} else if (Token.TYPE_PII.equals(tokenType) || Token.TYPE_ACCOUNT.equals(tokenType)) {
token = new Token(tokenId, tokenType, liveMode, date, used);
}

return token;
}

Expand All @@ -219,6 +222,8 @@ static String asTokenType(@Nullable String possibleTokenType) {
return Token.TYPE_BANK_ACCOUNT;
} else if (Token.TYPE_PII.equals(possibleTokenType)) {
return Token.TYPE_PII;
} else if (Token.TYPE_ACCOUNT.equals(possibleTokenType)) {
return Token.TYPE_ACCOUNT;
}

return null;
Expand Down
Loading