#marcoprouve-express-onboarding

1 messages ยท Page 1 of 1 (latest)

ivory orbit
#

Hello!

summer shell
#

Okay great thats what i thought, is there another field for item "b"

#

?

ivory orbit
summer shell
#

Thank you so much! One more thing just to clarify. Im assuming creating account links should be done pretty frequently? Should I be creating an account link every time a user clicks the button to update or setup their stripe account?

worthy flume
#

As a user: I sort of have a multi-stage process - I have an "account"page where I gather a lot of information on my own platform, keeping the user informed of what might be missing (address, email, phone number, etc). I don't present a button for the onboarding link (just a place-holder) until what information I can collect has been collected. messages below this inform the user of what's missing.

After that, I check the status of their account (I have a couple server-side routines for this), and re-present the onboarding link if they haven't completed it.

When onboarded, I present an account link (separate API call) for them to access their limited dashboard. I also add notes below this button/link to give them a summary of what they need to update to stay current.

#

I could share my server-side checks, if you want.

summer shell
#

Thank you sorry on a call quick but will respond when done ๐Ÿ™‚

summer shell
#

@worthy flume Thank you for the response this helps a lot!

worthy flume
#

my routine is pretty brute force (there really isn't another way), but I can show you some of them if you want...

#

For the Stripe account status, I pull an account object from the API, and send it to:

/**
 * Builds a status report of open and pending issues for an account
 * @async
 * @function
 * @param {accountHash} paymentAccount
 * @returns {string} text report
 */
export const stripeAccountStatusReport = (paymentAccount) => {
  return statusSummary({
    requirements: paymentAccount.requirements,
    tos_acceptance: paymentAccount.tos_acceptance,
    details_submitted: paymentAccount.details_submitted,
    future_requirements: paymentAccount.future_requirements,
    payouts_enabled: paymentAccount.payouts_enabled
  });
};

...just pulling out the relevant sections. This gets sent to a summary routine (following)

#

This gets built up into a string (not an object) as so:

/**
 * @function
 * @param {accountStatusHash} accountStatus
 * @returns {string}
 */
export const statusSummary = (accountStatus) => {
  let returnString = "";

  returnString = returnString.concat(
    requirementsSummary(
      `Your Account has issues that must be resolved`,
      accountStatus.requirements
    )
  );
  returnString = returnString.concat(
    requirementsSummary(
      `Your Account has issues that will need resolved`,
      accountStatus.future_requirements
    )
  );

  return returnString;
};
#

The requirements part (which is similar between current and future) is:

const requirementsSummary = (msg, requirements) => {
  let returnString = "";

  if (requirements?.disabled_reason) {
    returnString = `\n${msg} immediately\n`;
    returnString = requirements.past_due.reduce((result, due) => {
      return result.concat(`=> ${due}\n`);
    }, returnString);
    return returnString;
  }

  if (requirements?.current_deadline) {
    returnString = `\n${msg} by ${dayjs
      .unix(requirements?.current_deadline)
      .format("MMM DD, YYYY")}\n`;
    returnString = requirements.currently_due.reduce((result, due) => {
      return result.concat(`=> ${due}\n`);
    }, returnString);
    if (requirements?.errors?.length) {
      returnString = returnString.concat(
        `\nThese requirements were in part caused by the following errors:\n`
      );
      returnString = requirements.errors.reduce((result, error) => {
        return result.concat(`=> ${error.requirement}: ${error.reason}\n`);
      }, returnString);
    }
  }
  return returnString;
};
summer shell
#

Oh this is very helpful, I was only going o check payout_enabled and details_provided

#

you use tos_acceptance and future_requirements checks, what are these for?

worthy flume
#

And finally, to respond to account.update events, I set a flag in my database accounts::

/**
 * Responds to account.updated events.
 * If the status has any issues to report, the application account will
 * add a flag {openIssues: true}
 * If the status has no issues to report, the application account will
 * add a flag {openIssues: false}
 * Management systems can query for {openIssues: true} to find delinquent
 * accounts; both missing flag and {openIssues: false} will be ignored
 * @async
 * @function
 * @param {accountHash} paymentAccount
 * @returns {null}
 */
export const accountUpdate = async (paymentAccount) => {
  const statusReport = await stripeAccountStatusReport(paymentAccount);

  const businessRefPath = paymentAccount.metadata.account_refPath;
  const business_account = refPathToBaseRecord(businessRefPath);
  if (statusReport && statusReport.length) {
    return setOpenIssues(business_account);
    //set {openIssues: true} in application account.
  } else {
    return clearOpenIssues(business_account);
  }
};
summer shell
#

This is extremely helpful. Definitely wouldnt have checked requirements until i figured out the use case later

#

thank you ๐Ÿ™‚

worthy flume
#

tos_acceptance is whether they have accepted "Terms of Service", which can change if there's a change in their bank account or debit. future_requirements is same as current requirements, but may be more based on things like rising account volume, etc

summer shell
#

Got it

worthy flume
#

Basically, I'm trying to let them know what to go fix, rather than just signalling "It broke. Go Fix."

summer shell
#

Yeah for sure, Thats always better

worthy flume
#

I also use a single entry-point/call for onboarding & account link, which is differentiated with

paymentAccount.requirements?.disabled_reason
#

i.e. if disabled for any reason (or not enabled yet) send them to onboarding

#

the status report gets sent back with the requested link for display

summer shell
#

Amazing!

#

so disabled_reason is the main field to check in requirements for errors?

worthy flume
#

well, it seems to differentiated onboarded accounts and not onboarded accounts