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

Add missing stripe countries #968

Merged
merged 13 commits into from
Dec 11, 2018
2 changes: 2 additions & 0 deletions .env-template
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

# Mandatory configuration
#
# Note: You also need to set Stripe secret key in Flex Console.
#
REACT_APP_SHARETRIBE_SDK_CLIENT_ID=
REACT_APP_STRIPE_PUBLISHABLE_KEY=
REACT_APP_MAPBOX_ACCESS_TOKEN=
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ way to update this template, but currently, we follow a pattern:

## Upcoming version 2018-XX-XX

- [add] Add Stripe support for new countries: Canada, New Zealand, Switzerland, Norway, and Hong
Kong. Also add more required fields for US and Australia.
- StripeBankAccountTokenInputField component and PayoutDetailsForm have some changes
- Stripe related configuration is separated to new stripe-config.js file.
- Multiple new translation keys were added and they might not be translated into French yet. If
you use French translation check PR for the changed keys.
[#968](https://github.com/sharetribe/flex-template-web/pull/968)
- [change] Remove generic perUnit translations and replace them with specific night, day and unit
translations depending on booking unit chosen in config.
[#970](https://github.com/sharetribe/flex-template-web/pull/970)

- [fix] Formatting docs with newest Prettier - related commit was lost in #967 at some point.
[#975](https://github.com/sharetribe/flex-template-web/pull/975)
- [change] Improved documents related to onboarding: env.md, deploying-to-production.md,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,20 @@ export const AU_AUD = {
},
group: 'custom inputs',
};

// CA
export const CA_CAD = {
component: formComponent('CA'),
props: {
formName: 'CA_CAD',
onChange: formState => {
if (formState.dirty) {
console.log('form values changed to:', formState.values);
}
},
onSubmit: values => {
console.log('values submitted:', values);
},
},
group: 'custom inputs',
};
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,8 @@ class TokenInputFieldComponent extends Component {
};

// Include input values with correct stripe keys
inputsNeeded.forEach(inputType => {
// Stripe fails if there are spaces within the number, this is
// why we have to clean value up first.
const inputValueObj = mapInputsToStripeAccountKeys(
inputType,
cleanedString(values[inputType])
);
accountData = { ...accountData, ...inputValueObj };
});
const inputValueObj = mapInputsToStripeAccountKeys(country, values);
accountData = { ...accountData, ...inputValueObj };

// https://stripe.com/docs/stripe-js/reference#collecting-bank-account-details
this.stripe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import config from '../../config';
export const ACCOUNT_NUMBER = 'accountNumber';
// Australian equivalent for routing number
export const BSB = 'bsb';
// Needed for creating full routing number in Canada
export const INSTITUTION_NUMBER = 'institutionNumber';
// Needed for creating full routing number in Canada
export const TRANSIT_NUMBER = 'transitNumber';
// Needed for creating full routing number in Hong Kong
export const CLEARING_CODE = 'clearingCode';
// Needed for creating full routing number in Hong Kong
export const BRANCH_CODE = 'branchCode';
// International bank account number (e.g. EU countries use this)
export const IBAN = 'iban';
// Routing number to separate bank account in different areas
Expand All @@ -15,7 +23,17 @@ export const SORT_CODE = 'sortCode';

// Currently supported bank account inputs
// the order here matters: account number input is asked after routing number and its equivalents
export const BANK_ACCOUNT_INPUTS = [BSB, SORT_CODE, ROUTING_NUMBER, ACCOUNT_NUMBER, IBAN];
export const BANK_ACCOUNT_INPUTS = [
BSB,
TRANSIT_NUMBER,
INSTITUTION_NUMBER,
CLEARING_CODE,
BRANCH_CODE,
SORT_CODE,
ROUTING_NUMBER,
ACCOUNT_NUMBER,
IBAN,
];

export const supportedCountries = config.stripe.supportedCountries.map(c => c.code);

Expand Down Expand Up @@ -117,7 +135,7 @@ export const translateStripeError = (country, intl, stripeError) => {
*
* @return {Object} key - value in Object literal.
*/
export const mapInputsToStripeAccountKeys = (inputType, value) => {
export const mapInputsToStripeAccountKeys = (country, values) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Remember to update the function doc ☝️

// Stripe documentation speaks about actual bank account terms of different countries
// (like BSB, sort code, routing number), but all of those get mapped to one of
// the two different request keys: routing_number or account_number
Expand All @@ -126,17 +144,63 @@ export const mapInputsToStripeAccountKeys = (inputType, value) => {
// We use those country specific terms since we want to show correct labels and errors for users,
// so this mapping is needed before sending data to Stripe.

switch (inputType) {
case IBAN:
case ACCOUNT_NUMBER:
return { account_number: value };
case BSB:
case SORT_CODE:
case ROUTING_NUMBER:
return { routing_number: value };
// Stripe fails if there are spaces within the number, this is
// why we have to clean value up first.

switch (country) {
case 'AT':
case 'BE':
case 'DK':
case 'FI':
case 'FR':
case 'DE':
case 'IE':
case 'IT':
case 'LU':
case 'NL':
case 'PT':
case 'ES':
case 'SE':
case 'CH':
case 'NO':
return { account_number: cleanedString(values[IBAN]) };
case 'NZ':
// NZ account number is typically presented in the format xx-xxxx-xxxxxxx-xxx
// '-' separators must be removed before sending value to Stripe API
return { account_number: cleanedString(values[ACCOUNT_NUMBER]).replace(/-/g, '') };
case 'AU':
return {
routing_number: cleanedString(values[BSB]),
account_number: cleanedString(values[ACCOUNT_NUMBER]),
};
case 'CA':
return {
routing_number: cleanedString(values[TRANSIT_NUMBER]).concat(
cleanedString(values[INSTITUTION_NUMBER])
),
account_number: cleanedString(values[ACCOUNT_NUMBER]),
};
case 'GB':
return {
routing_number: cleanedString(values[SORT_CODE]),
account_number: cleanedString(values[ACCOUNT_NUMBER]),
};
case 'US':
return {
routing_number: cleanedString(values[ROUTING_NUMBER]),
account_number: cleanedString(values[ACCOUNT_NUMBER]),
};
case 'HK':
return {
routing_number: cleanedString(values[CLEARING_CODE]).concat(
'-',
cleanedString(values[BRANCH_CODE])
),
account_number: cleanedString(values[ACCOUNT_NUMBER]),
};

default:
throw new Error(`Unknown inputType (${inputType}) given to validator`);
throw new Error(`Not supported country (${country}) given to validator`);
}
};

Expand Down
157 changes: 1 addition & 156 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as custom from './marketplace-custom-config.js';
import defaultLocationSearches from './default-location-searches';
import { stripePublishableKey, stripeSupportedCountries } from './stripe-config';

const env = process.env.REACT_APP_ENV;
const dev = process.env.REACT_APP_ENV === 'development';
Expand Down Expand Up @@ -79,162 +80,6 @@ const currencyConfig = {
maximumFractionDigits: 2,
};

const stripePublishableKey = process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY;

// Stripe only supports payments in certain countries, see full list
// at https://stripe.com/global
//
// We currently only support EU countries, US, and AU.
const stripeSupportedCountries = [
{
// Australia
code: 'AU',
currency: 'AUD',
payoutAddressRequired: false,
accountConfig: {
bsb: true,
accountNumber: true,
},
},
{
// Austria
code: 'AT',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Belgium
code: 'BE',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Denmark
code: 'DK',
currency: 'DKK',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Finland
code: 'FI',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// France
code: 'FR',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Germany
code: 'DE',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Ireland
code: 'IE',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Italy
code: 'IT',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Luxembourg
code: 'LU',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Netherlands
code: 'NL',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Portugal
code: 'PT',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Spain
code: 'ES',
currency: 'EUR',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// Sweden
code: 'SE',
currency: 'SEK',
payoutAddressRequired: true,
accountConfig: {
iban: true,
},
},
{
// United Kingdom
code: 'GB',
currency: 'GBP',
payoutAddressRequired: true,
accountConfig: {
sortCode: true,
accountNumber: true,
},
},
{
// United States
code: 'US',
currency: 'USD',
payoutAddressRequired: false,
accountConfig: {
routingNumber: true,
accountNumber: true,
},
},
];

// Address information is used in SEO schema for Organization (http://schema.org/PostalAddress)
const addressCountry = 'FI';
const addressRegion = 'Helsinki';
Expand Down
10 changes: 10 additions & 0 deletions src/ducks/user.duck.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,15 +397,24 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) =>
streetAddress,
postalCode,
city,
state,
province,
bankAccountToken,
personalIdNumber,
} = payoutDetails;

const hasProvince = province && !state;

const address = {
city,
line1: streetAddress,
postal_code: postalCode,
state: hasProvince ? province : state,
};

const idNumber =
country === 'US' ? { ssn_last_4: personalIdNumber } : { personal_id_number: personalIdNumber };

// Params for Stripe SDK
const params = {
legal_entity: {
Expand All @@ -414,6 +423,7 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) =>
address: omitBy(address, isUndefined),
dob: birthDate,
type: 'individual',
...idNumber,
},
tos_shown_and_accepted: true,
};
Expand Down
Loading