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
- [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
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

View file

@ -256,7 +256,7 @@ const formatAddress = address => {
};
// Util: rename personToken params to match Stripe API specifications
const personTokenParams = (personData, country) => {
const personTokenParams = (personData, companyConfig) => {
const {
isAccountOpener,
fname: firstName,
@ -274,12 +274,15 @@ const personTokenParams = (personData, country) => {
const addressMaybe = address ? { address: formatAddress(address) } : {};
const emailMaybe = email ? { email } : {};
const phoneMaybe = phone ? { phone } : {};
const idNumberMaybe =
country === 'US'
? { ssn_last_4: personalIdNumber }
: personalIdNumber
? { id_number: personalIdNumber }
: {};
const personalIdNumberRequired = companyConfig && companyConfig.personalIdNumberRequired;
const ssnLast4Required = companyConfig && companyConfig.ssnLast4Required;
const idNumberMaybe = ssnLast4Required
? { ssn_last_4: personalIdNumber }
: personalIdNumberRequired
? { id_number: personalIdNumber }
: {};
const accountOpenerMaybe = isAccountOpener ? { account_opener: true } : {};
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;
let personToken = 'no-token';
return stripe
.createToken('person', personTokenParams(personParams, country))
.createToken('person', personTokenParams(personParams, companyConfig))
.then(response => {
personToken = response.token.id;
@ -358,10 +361,16 @@ const createStripePerson = (personParams, country, stripe) => (dispatch, getStat
// accountData should be either individual or company
const bankAccountTokenParams = accountData => accountData.bankAccountToken;
const businessProfileParams = accountData => {
const businessProfileParams = (accountData, accountConfig) => {
const businessProfileRequired =
accountConfig && accountConfig.mccForUS && accountConfig.businessURL;
const { mcc, url } =
accountData && accountData.businessProfile ? accountData.businessProfile : {};
return mcc && url
const hasInformation = mcc && url;
return businessProfileRequired && hasInformation
? {
businessProfileMCC: mcc,
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 state = getState();
let stripeAccount =
@ -396,8 +409,10 @@ export const createStripeCompanyAccount = (payoutDetails, stripe) => (dispatch,
const createPersons = () => {
return Promise.all([
dispatch(createStripePerson({ ...accountOpener, isAccountOpener: true }, country, stripe)),
...persons.map(p => dispatch(createStripePerson(p, country, stripe))),
dispatch(
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,
bankAccountToken,
country,
...businessProfileParams(company),
...businessProfileParams(company, companyConfig),
};
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 {
fname: firstName,
lname: lastName,
@ -468,16 +483,20 @@ const accountTokenParamsForIndividual = (individual, country) => {
email,
personalIdNumber,
} = individual;
const addressMaybe = address ? { address: formatAddress(address) } : {};
const dobMaybe = birthDate ? { dob: birthDate } : {};
const emailMaybe = email ? { email } : {};
const phoneMaybe = phone ? { phone } : {};
const idNumberMaybe =
country === 'US'
? { ssn_last_4: personalIdNumber }
: personalIdNumber
? { id_number: personalIdNumber }
: {};
const personalIdNumberRequired = individualConfig && individualConfig.personalIdNumberRequired;
const ssnLast4Required = individualConfig && individualConfig.ssnLast4Required;
const idNumberMaybe = ssnLast4Required
? { ssn_last_4: personalIdNumber }
: personalIdNumberRequired
? { id_number: personalIdNumber }
: {};
return {
business_type: 'individual',
@ -494,7 +513,7 @@ const accountTokenParamsForIndividual = (individual, country) => {
};
};
export const createStripeIndividualAccount = (payoutDetails, stripe) => (
export const createStripeIndividualAccount = (payoutDetails, individualConfig, stripe) => (
dispatch,
getState,
sdk
@ -504,7 +523,7 @@ export const createStripeIndividualAccount = (payoutDetails, stripe) => (
dispatch(stripeAccountCreateRequest());
return stripe
.createToken('account', accountTokenParamsForIndividual(individual, country))
.createToken('account', accountTokenParamsForIndividual(individual, individualConfig))
.then(response => {
const accountToken = response.token.id;
const bankAccountToken = bankAccountTokenParams(individual);
@ -512,7 +531,7 @@ export const createStripeIndividualAccount = (payoutDetails, stripe) => (
accountToken,
bankAccountToken,
country,
...businessProfileParams(individual),
...businessProfileParams(individual, individualConfig),
};
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 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') {
return dispatch(createStripeIndividualAccount(payoutDetails, stripe));
return dispatch(createStripeIndividualAccount(payoutDetails, individualConfig, stripe));
} else {
return dispatch(createStripeCompanyAccount(payoutDetails, stripe));
return dispatch(createStripeCompanyAccount(payoutDetails, companyConfig, stripe));
}
};

View file

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

View file

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

View file

@ -28,6 +28,10 @@ const PayoutDetailsBusinessProfile = props => {
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 ? (
<React.Fragment>
{showMCCForUSField ? (

View file

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

View file

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