Skip to content

Commit

Permalink
Merge pull request #968 from sharetribe/add-missing-stripe-countries
Browse files Browse the repository at this point in the history
Add missing stripe countries
  • Loading branch information
OtterleyW authored Dec 11, 2018
2 parents 1b83809 + ffa3c7e commit 2625b44
Show file tree
Hide file tree
Showing 14 changed files with 852 additions and 256 deletions.
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) => {
// 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

0 comments on commit 2625b44

Please sign in to comment.