Merge pull request #1151 from sharetribe/fix-changing-country-in-payout-details

Use stripe config to determine US specific fields
This commit is contained in:
Jenni Laakso 2019-08-19 11:07:05 +03:00 committed by GitHub
commit f0fdc46ef3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 64 additions and 27 deletions

View file

@ -14,6 +14,10 @@ way to update this template, but currently, we follow a pattern:
## Upcoming version 2019-XX-XX ## Upcoming version 2019-XX-XX
- [fix] Don't send personal id number or business profile to Stripe API when creating a Stripe
customer if they are not required in `stripe-config.js`. This happened e.g. if someone filled the
form after selecting the US and then before sending changed the country to Finland.
[#1151](https://github.com/sharetribe/flex-template-web/pull/1151)
- [add] Add new French and Spanish translations related to keyword search and Spanish translations - [add] Add new French and Spanish translations related to keyword search and Spanish translations
related to payment intents. [#1148](https://github.com/sharetribe/flex-template-web/pull/1148) related to payment intents. [#1148](https://github.com/sharetribe/flex-template-web/pull/1148)
- [add] Add new French translations related to payment intents. Also few small changes to en.json - [add] Add new French translations related to payment intents. Also few small changes to en.json

View file

@ -256,7 +256,7 @@ const formatAddress = address => {
}; };
// Util: rename personToken params to match Stripe API specifications // Util: rename personToken params to match Stripe API specifications
const personTokenParams = (personData, country) => { const personTokenParams = (personData, companyConfig) => {
const { const {
isAccountOpener, isAccountOpener,
fname: firstName, fname: firstName,
@ -274,12 +274,15 @@ const personTokenParams = (personData, country) => {
const addressMaybe = address ? { address: formatAddress(address) } : {}; const addressMaybe = address ? { address: formatAddress(address) } : {};
const emailMaybe = email ? { email } : {}; const emailMaybe = email ? { email } : {};
const phoneMaybe = phone ? { phone } : {}; const phoneMaybe = phone ? { phone } : {};
const idNumberMaybe =
country === 'US' const personalIdNumberRequired = companyConfig && companyConfig.personalIdNumberRequired;
? { ssn_last_4: personalIdNumber } const ssnLast4Required = companyConfig && companyConfig.ssnLast4Required;
: personalIdNumber
? { id_number: personalIdNumber } const idNumberMaybe = ssnLast4Required
: {}; ? { ssn_last_4: personalIdNumber }
: personalIdNumberRequired
? { id_number: personalIdNumber }
: {};
const accountOpenerMaybe = isAccountOpener ? { account_opener: true } : {}; const accountOpenerMaybe = isAccountOpener ? { account_opener: true } : {};
const jobTitleMaybe = title ? { title } : {}; const jobTitleMaybe = title ? { title } : {};
@ -314,11 +317,11 @@ const personTokenParams = (personData, country) => {
}; };
}; };
const createStripePerson = (personParams, country, stripe) => (dispatch, getState, sdk) => { const createStripePerson = (personParams, companyConfig, stripe) => (dispatch, getState, sdk) => {
const { isAccountOpener } = personParams; const { isAccountOpener } = personParams;
let personToken = 'no-token'; let personToken = 'no-token';
return stripe return stripe
.createToken('person', personTokenParams(personParams, country)) .createToken('person', personTokenParams(personParams, companyConfig))
.then(response => { .then(response => {
personToken = response.token.id; personToken = response.token.id;
@ -358,10 +361,16 @@ const createStripePerson = (personParams, country, stripe) => (dispatch, getStat
// accountData should be either individual or company // accountData should be either individual or company
const bankAccountTokenParams = accountData => accountData.bankAccountToken; const bankAccountTokenParams = accountData => accountData.bankAccountToken;
const businessProfileParams = accountData => { const businessProfileParams = (accountData, accountConfig) => {
const businessProfileRequired =
accountConfig && accountConfig.mccForUS && accountConfig.businessURL;
const { mcc, url } = const { mcc, url } =
accountData && accountData.businessProfile ? accountData.businessProfile : {}; accountData && accountData.businessProfile ? accountData.businessProfile : {};
return mcc && url
const hasInformation = mcc && url;
return businessProfileRequired && hasInformation
? { ? {
businessProfileMCC: mcc, businessProfileMCC: mcc,
businessProfileURL: url, businessProfileURL: url,
@ -386,7 +395,11 @@ const accountTokenParamsForCompany = company => {
}; };
}; };
export const createStripeCompanyAccount = (payoutDetails, stripe) => (dispatch, getState, sdk) => { export const createStripeCompanyAccount = (payoutDetails, companyConfig, stripe) => (
dispatch,
getState,
sdk
) => {
const { company, country, accountOpener, persons = [] } = payoutDetails; const { company, country, accountOpener, persons = [] } = payoutDetails;
const state = getState(); const state = getState();
let stripeAccount = let stripeAccount =
@ -396,8 +409,10 @@ export const createStripeCompanyAccount = (payoutDetails, stripe) => (dispatch,
const createPersons = () => { const createPersons = () => {
return Promise.all([ return Promise.all([
dispatch(createStripePerson({ ...accountOpener, isAccountOpener: true }, country, stripe)), dispatch(
...persons.map(p => dispatch(createStripePerson(p, country, stripe))), createStripePerson({ ...accountOpener, isAccountOpener: true }, companyConfig, stripe)
),
...persons.map(p => dispatch(createStripePerson(p, companyConfig, stripe))),
]); ]);
}; };
@ -430,7 +445,7 @@ export const createStripeCompanyAccount = (payoutDetails, stripe) => (dispatch,
accountToken, accountToken,
bankAccountToken, bankAccountToken,
country, country,
...businessProfileParams(company), ...businessProfileParams(company, companyConfig),
}; };
return sdk.stripeAccount.create(stripeAccountParams, { expand: true }); return sdk.stripeAccount.create(stripeAccountParams, { expand: true });
}) })
@ -458,7 +473,7 @@ export const createStripeCompanyAccount = (payoutDetails, stripe) => (dispatch,
}); });
}; };
const accountTokenParamsForIndividual = (individual, country) => { const accountTokenParamsForIndividual = (individual, individualConfig) => {
const { const {
fname: firstName, fname: firstName,
lname: lastName, lname: lastName,
@ -468,16 +483,20 @@ const accountTokenParamsForIndividual = (individual, country) => {
email, email,
personalIdNumber, personalIdNumber,
} = individual; } = individual;
const addressMaybe = address ? { address: formatAddress(address) } : {}; const addressMaybe = address ? { address: formatAddress(address) } : {};
const dobMaybe = birthDate ? { dob: birthDate } : {}; const dobMaybe = birthDate ? { dob: birthDate } : {};
const emailMaybe = email ? { email } : {}; const emailMaybe = email ? { email } : {};
const phoneMaybe = phone ? { phone } : {}; const phoneMaybe = phone ? { phone } : {};
const idNumberMaybe =
country === 'US' const personalIdNumberRequired = individualConfig && individualConfig.personalIdNumberRequired;
? { ssn_last_4: personalIdNumber } const ssnLast4Required = individualConfig && individualConfig.ssnLast4Required;
: personalIdNumber
? { id_number: personalIdNumber } const idNumberMaybe = ssnLast4Required
: {}; ? { ssn_last_4: personalIdNumber }
: personalIdNumberRequired
? { id_number: personalIdNumber }
: {};
return { return {
business_type: 'individual', business_type: 'individual',
@ -494,7 +513,7 @@ const accountTokenParamsForIndividual = (individual, country) => {
}; };
}; };
export const createStripeIndividualAccount = (payoutDetails, stripe) => ( export const createStripeIndividualAccount = (payoutDetails, individualConfig, stripe) => (
dispatch, dispatch,
getState, getState,
sdk sdk
@ -504,7 +523,7 @@ export const createStripeIndividualAccount = (payoutDetails, stripe) => (
dispatch(stripeAccountCreateRequest()); dispatch(stripeAccountCreateRequest());
return stripe return stripe
.createToken('account', accountTokenParamsForIndividual(individual, country)) .createToken('account', accountTokenParamsForIndividual(individual, individualConfig))
.then(response => { .then(response => {
const accountToken = response.token.id; const accountToken = response.token.id;
const bankAccountToken = bankAccountTokenParams(individual); const bankAccountToken = bankAccountTokenParams(individual);
@ -512,7 +531,7 @@ export const createStripeIndividualAccount = (payoutDetails, stripe) => (
accountToken, accountToken,
bankAccountToken, bankAccountToken,
country, country,
...businessProfileParams(individual), ...businessProfileParams(individual, individualConfig),
}; };
return sdk.stripeAccount.create(stripeAccountParams, { expand: true }); return sdk.stripeAccount.create(stripeAccountParams, { expand: true });
}) })
@ -540,10 +559,15 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) =>
const stripe = window.Stripe(config.stripe.publishableKey); const stripe = window.Stripe(config.stripe.publishableKey);
const country = payoutDetails.country;
const countryConfig = config.stripe.supportedCountries.find(c => c.code === country);
const individualConfig = countryConfig.individualConfig;
const companyConfig = countryConfig.companyConfig;
if (payoutDetails.accountType === 'individual') { if (payoutDetails.accountType === 'individual') {
return dispatch(createStripeIndividualAccount(payoutDetails, stripe)); return dispatch(createStripeIndividualAccount(payoutDetails, individualConfig, stripe));
} else { } else {
return dispatch(createStripeCompanyAccount(payoutDetails, stripe)); return dispatch(createStripeCompanyAccount(payoutDetails, companyConfig, stripe));
} }
}; };

View file

@ -47,6 +47,7 @@ const PayoutDetailsAccountOpener = props => {
showPhoneNumberField={showPhoneNumberField} showPhoneNumberField={showPhoneNumberField}
sectionTitle={intl.formatMessage({ id: 'PayoutDetailsForm.accountOpenerTitle' })} sectionTitle={intl.formatMessage({ id: 'PayoutDetailsForm.accountOpenerTitle' })}
values={values} values={values}
form={form}
/> />
{showPersonalAddressField ? ( {showPersonalAddressField ? (
<PayoutDetailsAddress <PayoutDetailsAddress

View file

@ -74,6 +74,7 @@ const PayoutDetailsAdditionalPersons = props => {
showPersonalIdNumberField={showPersonalIdNumberField} showPersonalIdNumberField={showPersonalIdNumberField}
showPhoneNumberField={showPhoneNumberField} showPhoneNumberField={showPhoneNumberField}
showRoleField showRoleField
form={form}
/> />
{showPersonalAddressField ? ( {showPersonalAddressField ? (
<PayoutDetailsAddress <PayoutDetailsAddress

View file

@ -28,6 +28,10 @@ const PayoutDetailsBusinessProfile = props => {
intl.formatMessage({ id: 'PayoutDetailsForm.businessURLRequired' }) intl.formatMessage({ id: 'PayoutDetailsForm.businessURLRequired' })
); );
// By default, all merchant category codes (MCC) are listed in the select field. You can edit the
// merchantCategoryCodesUS.js and remove the codes that are not relevant to your marketplace or use a hard-coded
// value if there is only one code you want to use.
return isBusinessProfileNeeded ? ( return isBusinessProfileNeeded ? (
<React.Fragment> <React.Fragment>
{showMCCForUSField ? ( {showMCCForUSField ? (

View file

@ -65,6 +65,7 @@ const PayoutDetailsIndividualAccountComponent = props => {
showEmailField={showEmailField} showEmailField={showEmailField}
showPersonalIdNumberField={showPersonalIdNumberField} showPersonalIdNumberField={showPersonalIdNumberField}
showPhoneNumberField={showPhoneNumberField} showPhoneNumberField={showPhoneNumberField}
form={form}
/> />
<PayoutDetailsAddress <PayoutDetailsAddress

View file

@ -23,6 +23,7 @@ const PayoutDetailsPersonalDetails = props => {
showOwnershipPercentageField, showOwnershipPercentageField,
showPersonalIdNumberField, showPersonalIdNumberField,
showPhoneNumberField, showPhoneNumberField,
form,
} = props; } = props;
const organizationTitleLabel = intl.formatMessage({ const organizationTitleLabel = intl.formatMessage({
@ -261,6 +262,7 @@ const PayoutDetailsPersonalDetails = props => {
label={personalIdNumberLabel} label={personalIdNumberLabel}
placeholder={personalIdNumberPlaceholder} placeholder={personalIdNumberPlaceholder}
validate={personalIdNumberValid} validate={personalIdNumberValid}
onUnmount={() => form.change(`${fieldId}.personalIdNumber`, undefined)}
/> />
) : null} ) : null}