Stripe Connect module API explorer

/api/user/connect/update-person (PATCH)

await global.api.user.connect.UpdatePerson.patch(req)

Returns object

Exceptions

These exceptions are thrown (NodeJS) or returned as JSON (HTTP) if you provide incorrect data or do not meet the requirements:

Exception Circumstances
invalid querystring personid
invalid-personid missing querystring personid
invalid-account ineligible accessing account
invalid-person ineligible querystring person has no required information
invalid posted token
invalid-token missing posted token

Receives

API routes may receive parameters from the URL and POST supporting simple and multipart:

Field Value Required Type
string required URL
string required URL

NodeJS source (edit on github)

If you see a problem with the source submit a pull request on Github.

const connect = require('../../../../../index.js')
const stripeCache = require('../../../../stripe-cache.js')

module.exports = {
  patch: async (req) => {
    if (!req.query || !req.query.personid) {
      throw new Error('invalid-personid')
    }
    const person = await global.api.user.connect.Person.get(req)
    if (!person) {
      throw new Error('invalid-personid')
    }
    if (global.stripeJS === 3 && !req.body.token) {
      throw new Error('invalid-token')
    }
    req.query.stripeid = person.account
    const stripeAccount = await global.api.user.connect.StripeAccount.get(req)
    let requiresInfo = false
    for (const requirement of stripeAccount.requirements.currently_due) {
      requiresInfo = requirement.startsWith(person.id)
      if (requiresInfo) {
        break
      }
    }
    if (!requiresInfo) {
      for (const requirement of stripeAccount.requirements.eventually_due) {
        requiresInfo = requirement.startsWith(person.id)
        if (requiresInfo) {
          break
        }
      }
    }
    if (!requiresInfo) {
      throw new Error('invalid-person')
    }
    const updateInfo = {}
    if (global.stripeJS === 3) {
      updateInfo.person_token = req.body.token
    } else {
      updateInfo.metadata = {
        token: false
      }
      let validateDOB = false
      if (req.body.dob_day) {
        validateDOB = true
        try {
          const day = parseInt(req.body.dob_day, 10)
          if (!day || day < 1 || day > 31) {
            throw new Error('invalid-dob_day')
          }
        } catch (s) {
          throw new Error('invalid-dob_day')
        }
      }
      if (req.body.dob_month) {
        validateDOB = true
        try {
          const month = parseInt(req.body.dob_month, 10)
          if (!month || month < 1 || month > 12) {
            throw new Error('invalid-dob_month')
          }
        } catch (s) {
          throw new Error('invalid-dob_month')
        }
      }
      if (req.body.dob_year) {
        validateDOB = true
        try {
          const year = parseInt(req.body.dob_year, 10)
          const now = new Date().getFullYear()
          if (!year || year < now - 120 || year > now - 18) {
            throw new Error('invalid-dob_year')
          }
        } catch (s) {
          throw new Error('invalid-dob_year')
        }
      }
      if (validateDOB) {
        if (!req.body.dob_day) {
          throw new Error('invalid-dob_day')
        }
        if (!req.body.dob_month) {
          throw new Error('invalid-dob_month')
        }
        if (!req.body.dob_year) {
          throw new Error('invalid-dob_year')
        }
        try {
          Date.parse(`${req.body.dob_year}/${req.body.dob_month}/${req.body.dob_day}`)
        } catch (error) {
          throw new Error('invalid-dob_day')
        }
      }
      if (req.uploads) {
        if (req.uploads.verification_document_front) {
          const frontData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_document_front.name,
              data: req.uploads.verification_document_front.buffer
            }
          }
          const front = await stripeCache.execute('files', 'create', frontData, req.stripeKey)
          req.body.verification_document_front = front.id
        }
        if (req.uploads.verification_document_back) {
          const backData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_document_back.name,
              data: req.uploads.verification_document_back.buffer
            }
          }
          const back = await stripeCache.execute('files', 'create', backData, req.stripeKey)
          req.body.verification_document_back = back.id
        }
        if (req.uploads.verification_additional_document_front) {
          const frontData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_additional_document_front.name,
              data: req.uploads.verification_additional_document_front.buffer
            }
          }
          const front = await stripeCache.execute('files', 'create', frontData, req.stripeKey)
          req.body.verification_additional_document_front = front.id
        }
        if (req.uploads.verification_additional_document_back) {
          const backData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_additional_document_back.name,
              data: req.uploads.verification_additional_document_back.buffer
            }
          }
          const back = await stripeCache.execute('files', 'create', backData, req.stripeKey)
          req.body.verification_additional_document_back = back.id
        }
      }
      for (const fullField of stripeAccount.requirements.currently_due) {
        if (!fullField.startsWith(person.id)) {
          continue
        }
        const field = fullField.substring(`${person.id}.`.length)
        const posted = field.split('.').join('_')
        if (!req.body[posted]) {
          if (field === 'address.line2' ||
              field === 'verification.document' ||
              field === 'verification.additional_document') {
            continue
          }
          throw new Error(`invalid-${posted}`)
        }
        if (field.startsWith('dob.')) {
          const property = field.substring('dob.'.length)
          updateInfo.dob = updateInfo.dob || {}
          updateInfo.dob[property] = req.body[posted]
        } else if (field.startsWith('address_kanji.')) {
          const property = field.substring('address_kanji.'.length)
          updateInfo.address_kanji = updateInfo.address_kanji || {}
          updateInfo.address_kanji[property] = req.body[posted]
        } else if (field.startsWith('address_kana.')) {
          const property = field.substring('address_kana.'.length)
          updateInfo.address_kana = updateInfo.address_kana || {}
          updateInfo.address_kana[property] = req.body[posted]
        } else if (field.startsWith('address.')) {
          const property = field.substring('address.'.length)
          updateInfo.address = updateInfo.address || {}
          updateInfo.address[property] = req.body[posted]
        } else if (field.startsWith('verification.document.')) {
          const property = field.substring('verification.document'.length)
          updateInfo.verification = updateInfo.verification || {}
          updateInfo.verification.document = updateInfo.verification.document || {}
          updateInfo.verification.document[property] = req.body[posted]
        } else if (field.startsWith('verification.additional_document.')) {
          const property = field.substring('verification.additional_document'.length)
          updateInfo.verification = updateInfo.verification || {}
          updateInfo.verification.additional_document = updateInfo.verification.additional_document || {}
          updateInfo.verification.additional_document[property] = req.body[posted]
        } else {
          updateInfo[field] = req.body[posted]
        }
      }
      for (const fullField of stripeAccount.requirements.eventually_due) {
        if (!fullField.startsWith(person.id)) {
          continue
        }
        const field = fullField.substring(`${person.id}.`.length)
        if (stripeAccount.requirements.currently_due.indexOf(field) > -1) {
          continue
        }
        const posted = field.split('.').join('_')
        if (!req.body[posted]) {
          continue
        }
        if (field.startsWith('dob.')) {
          const property = field.substring('dob.'.length)
          updateInfo.dob = updateInfo.dob || {}
          updateInfo.dob[property] = req.body[posted]
        } else if (field.startsWith('address_kanji.')) {
          const property = field.substring('address_kanji.'.length)
          updateInfo.address_kanji = updateInfo.address_kanji || {}
          updateInfo.address_kanji[property] = req.body[posted]
        } else if (field.startsWith('address_kana.')) {
          const property = field.substring('address_kana.'.length)
          updateInfo.address_kana = updateInfo.address_kana || {}
          updateInfo.address_kana[property] = req.body[posted]
        } else if (field.startsWith('address.')) {
          const property = field.substring('address.'.length)
          updateInfo.address = updateInfo.address || {}
          updateInfo.address[property] = req.body[posted]
        } else if (field.startsWith('verification.document.')) {
          const property = field.substring('verification.document'.length)
          updateInfo.verification = updateInfo.verification || {}
          updateInfo.verification.document = updateInfo.verification.document || {}
          updateInfo.verification.document[property] = req.body[posted]
        } else if (field.startsWith('verification.additional_document.')) {
          const property = field.substring('verification.additional_document'.length)
          updateInfo.verification = updateInfo.verification || {}
          updateInfo.verification.additional_document = updateInfo.verification.additional_document || {}
          updateInfo.verification.additional_document[property] = req.body[posted]
        } else {
          updateInfo[field] = req.body[posted]
        }
      }
      // TODO: these fields are optional but not represented in requirements
      // so when Stripe updates to have something like an 'optionally_due' array
      // the manual checks can be removed
      if (req.body.relationship_title) {
        updateInfo.relationship = updateInfo.relationship || {}
        updateInfo.relationship.title = req.body.relationship_title
      }
      if (req.body.relationship_executive) {
        updateInfo.relationship = updateInfo.relationship || {}
        updateInfo.relationship.executive = true
      }
      if (req.body.relationship_director) {
        updateInfo.relationship = updateInfo.relationship || {}
        updateInfo.relationship.director = true
      }
      if (req.body.relationship_owner) {
        updateInfo.relationship = updateInfo.relationship || {}
        updateInfo.relationship.owner = true
      }
      if (req.body.relationship_percent_ownership) {
        try {
          const percent = parseFloat(req.body.relationship_percent_ownership, 10)
          if ((!percent && percent !== 0) || percent > 100 || percent < 0) {
            throw new Error('invalid-relationship_percent_ownership')
          }
        } catch (s) {
          throw new Error('invalid-relationship_percent_ownership')
        }
        updateInfo.relationship = updateInfo.relationship || {}
        updateInfo.relationship.percent_ownership = req.body.relationship_percent_ownership
      }
      if (req.body.address_line2) {
        updateInfo.address = updateInfo.address || {}
        updateInfo.address.line2 = req.body.address_line2
      }
      if (req.body.address_country && req.body.address_country.length) {
        if (!connect.countryNameIndex[req.body.address_country]) {
          throw new Error('invalid-address_country')
        }
        updateInfo.address = updateInfo.address || {}
        updateInfo.address.country = req.body.address_country
      }
      if (req.body.address_state && req.body.address_state.length) {
        const states = connect.countryDivisions[req.body.address_country || stripeAccount.country]
        let found
        for (const state of states) {
          found = state.value === req.body.address_state
          if (found) {
            break
          }
        }
        if (!found) {
          throw new Error('invalid-address_state')
        }
        updateInfo.address = updateInfo.address || {}
        updateInfo.address.state = req.body.address_state
      }
      if (req.body.address_postal_code) {
        updateInfo.address = updateInfo.address || {}
        updateInfo.address.postal_code = req.body.address_postal_code
      }
      // TODO: not sure what a valid id number constraint would be
      if (req.body.id_number && req.body.id_number.length < 5) {
        throw new Error('invalid-id_number')
      }
      if (req.body.ssn_last_4 && req.body.ssn_last_4.length !== 4) {
        throw new Error('invalid-ssn_last_4')
      }
      if (req.body.verification_document_back) {
        updateInfo.verification = updateInfo.verification || {}
        updateInfo.verification.document = updateInfo.verification.document || {}
        updateInfo.verification.document.back = req.body.verification_document_back
      }
      if (req.body.verification_document_front) {
        updateInfo.verification = updateInfo.verification || {}
        updateInfo.verification.document = updateInfo.verification.document || {}
        updateInfo.verification.document.front = req.body.verification_document_front
      }
      if (req.body.verification_additional_document_back) {
        updateInfo.verification = updateInfo.verification || {}
        updateInfo.verification.additional_document = updateInfo.verification.additional_document || {}
        updateInfo.verification.additional_document.back = req.body.verification_additional_document_back
      }
      if (req.body.verification_additional_document_front) {
        updateInfo.verification = updateInfo.verification || {}
        updateInfo.verification.additional_document = updateInfo.verification.additional_document || {}
        updateInfo.verification.additional_document.front = req.body.verification_additional_document_front
      }
    }
    const personNow = await stripeCache.execute('accounts', 'updatePerson', person.account, person.id, updateInfo, req.stripeKey)
    await stripeCache.delete(person.id)
    return personNow
  }
}

Test source (edit on github)

Tests perform real HTTP requests against a running Dashboard server.

/* eslint-env mocha */
const assert = require('assert')
// const connect = require('../../../../../index.js')
const TestHelper = require('../../../../../test-helper.js')
const TestStripeAccounts = require('../../../../../test-stripe-accounts.js')
// const DashboardTestHelper = require('@userdashboard/dashboard/test-helper.js')

describe('/api/user/connect/update-person', function () {
  after(TestHelper.deleteOldWebhooks)
  before(TestHelper.setupWebhook)
  // TODO: requirements do not correctly show up in
  // the Stripe account.requirements or person.requirements

  // Note:  this test requires about a half-hour
  // this.timeout(30 * 60 * 1000)
  // const updateResponses = {}
  // const fields = [
  //   'address_city',
  //   'address_line1',
  //   'address_postal_code',
  //   'dob_day',
  //   'dob_month',
  //   'dob_year',
  //   'phone',
  //   'first_name',
  //   'last_name',
  //   'email',
  //   'address_state',
  //   'address_kana_city',
  //   'address_kana_line1',
  //   'address_kana_postal_code',
  //   'address_kana_state',
  //   'address_kana_town',
  //   'address_kanji_city',
  //   'address_kanji_line1',
  //   'address_kanji_postal_code',
  //   'address_kanji_state',
  //   'address_kanji_town',
  //   'first_name_kana',
  //   'first_name_kanji',
  //   'gender',
  //   'last_name_kana',
  //   'last_name_kanji',
  //   'id_number',
  //   'ssn_last_4'
  // ]
  // const uploadFields = [
  //   'verification_document_front',
  //   'verification_document_back',
  //   'verification_additional_document_front',
  //   'verification_additional_document_back'
  // ]
  // const testedMissingFields = [
  //   'relationship_title',
  //   'relationship_director',
  //   'relationship_executive',
  //   'relationship_representative',
  //   'relationship_owner'
  // ]
  // // TODO: invalid values marked as 'false' are skipped until they can be verified
  // const invalidValues = {
  //   address_line1: false,
  //   address_city: false,
  //   address_state: 'invalid',
  //   address_country: 'invalid',
  //   address_postal_code: false,
  //   address_kana_line1: false,
  //   address_kana_city: false,
  //   address_kana_town: 'invalid',
  //   address_kana_state: 'invalid',
  //   address_kana_postal_code: 'invalid',
  //   address_kanji_line1: false,
  //   address_kanji_city: false,
  //   // TODO: submitting an invalid kanji town
  //   // doesn't work because Stripe takes the kana
  //   // value and applies that to the kanji field
  //   // while ignoring the invalid value
  //   address_kanji_town: false,
  //   address_kanji_state: 'invalid',
  //   // TODO: submitting an invalid kanji postal code
  //   // doesn't work because Stripe takes the kana
  //   // value and applies that to the kanji field
  //   // while ignoring the invalid value
  //   address_kanji_postal_code: false,
  //   dob_day: '32',
  //   dob_month: '15',
  //   dob_year: new Date().getFullYear() - 17,
  //   first_name: false,
  //   first_name_kana: false,
  //   first_name_kanji: false,
  //   gender: 'invalid',
  //   last_name: false,
  //   last_name_kana: false,
  //   last_name_kanji: false,
  //   email: false,
  //   phone: false,
  //   id_number: false,
  //   relationship_title: false,
  //   relationship_director: 'false',
  //   relationship_executive: false,
  //   relationship_representative: false,
  //   relationship_owner: 'false',
  //   ssn_last_4: 'invalid'
  // }
  // const missingMessages = {}
  // const errorMessages = {}
  // const users = {}
  // before(async () => {
  //   await DashboardTestHelper.setupBeforeEach()
  //   await TestHelper.setupBeforeEach()
  //   for (const country of connect.countrySpecs) {
  //     const payload = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData[country.id])
  //     if (payload === false) {
  //       continue
  //     }
  //     for (const field in payload) {
  //       if (testedMissingFields.indexOf(field) > -1) {
  //         continue
  //       }
  //       testedMissingFields.push(field)
  //       let user = users[country.id]
  //       if (!user) {
  //         user = users[country.id] = await TestHelper.createUser()
  //         await TestHelper.createStripeAccount(user, {
  //           country: country.id,
  //           type: 'company'
  //         })
  //         await TestHelper.createPerson(user, {
  //           relationship_representative: 'true',
  //           relationship_executive: 'true',
  //           relationship_title: 'SVP Testing',
  //           relationship_percent_ownership: '0'
  //         })
  //       }
  //       let property = field.replace('address_kana_', 'address_kana.')
  //         .replace('address_kanji_', 'address_kanji.')
  //         .replace('dob_', 'dob.')
  //         .replace('relationship_', 'relationship.')
  //       if (property.indexOf('address_') > -1) {
  //         if (property.indexOf('_ka') === -1) {
  //           property = property.replace('address_', 'address.')
  //           property = property.substring(0, property.indexOf('.'))
  //         } else {
  //           property = property.substring(0, property.indexOf('_'))
  //         }
  //       }
  //       // await TestHelper.waitForAccountRequirement(user, `${user.representative.id}.${property}`)
  //       // await TestHelper.waitForPersonRequirement(user, user.representative.id, property)
  //       const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
  //       req.account = user.account
  //       req.session = user.session
  //       const body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData[country.id])
  //       delete (body[field])
  //       req.body = TestHelper.createMultiPart(req, body, {
  //         verification_document_back: TestHelper['success_id_scan_back.png'],
  //         verification_document_front: TestHelper['success_id_scan_front.png']
  //       })
  //       try {
  //         await req.patch()
  //       } catch (error) {
  //         errorMessages[field] = error.message
  //       }
  //       body[field] = invalidValues[field]
  //       req.body = TestHelper.createMultiPart(req, body, {
  //         verification_document_back: TestHelper['success_id_scan_back.png'],
  //         verification_document_front: TestHelper['success_id_scan_front.png']
  //       })
  //       try {
  //         await req.patch()
  //       } catch (error) {
  //         errorMessages[field] = error.message
  //       }
  //     }
  //     if (!users[country.id]) {
  //       continue
  //     }
  //     const user = users[country.id]
  //     const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
  //     req.account = user.account
  //     req.session = user.session
  //     req.body = TestHelper.createMultiPart(req, payload, {
  //       verification_document_back: TestHelper['success_id_scan_back.png'],
  //       verification_document_front: TestHelper['success_id_scan_front.png']
  //     })
  //     const response = await req.patch()
  //     for (const field in payload) {
  //       updateResponses[field] = response
  //     }
  //   }
  //   const user = await TestHelper.createUser()
  //   await TestHelper.createStripeAccount(user, {
  //     country: 'GB',
  //     type: 'company'
  //   })
  //   await TestHelper.createPerson(user, {
  //     relationship_representative: 'true',
  //     relationship_executive: 'true',
  //     relationship_title: 'SVP Testing',
  //     relationship_percent_ownership: '0'
  //   })
  //   const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
  //   req.account = user.account
  //   req.session = user.session
  //   req.body = TestHelper.createMultiPart(req, TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.GB), {
  //     verification_document_back: TestHelper['success_id_scan_back.png'],
  //     verification_document_front: TestHelper['success_id_scan_front.png']
  //   })
  //   global.stripeJS = 3
  //   try {
  //     await req.patch()
  //   } catch (error) {
  //     missingMessages['invalid-token'] = error.message
  //   }
  //   req.body.token = 'invalid'
  //   try {
  //     await req.patch()
  //   } catch (error) {
  //     errorMessages['invalid-token'] = error.message
  //   }
  //   global.stripeJS = false
  //   upload fields
  //   const uploader1 = await TestHelper.createUser()
  //   await TestHelper.createStripeAccount(uploader1, {
  //     country: 'AT',
  //     type: 'company'
  //   })
  //   await TestHelper.createPerson(uploader1, {
  //     relationship_representative: 'true',
  //     relationship_executive: 'true',
  //     relationship_title: 'SVP Testing',
  //     relationship_percent_ownership: '0'
  //   })
  //   await TestHelper.updatePerson(uploader1, uploader1.representative, TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.AT))
  //   const uploader2 = await TestHelper.createUser()
  //   await TestHelper.createStripeAccount(uploader2, {
  //     country: 'AT',
  //     type: 'company'
  //   })
  //   await TestHelper.createPerson(uploader2, {
  //     relationship_representative: 'true',
  //     relationship_executive: 'true',
  //     relationship_title: 'SVP Testing',
  //     relationship_percent_ownership: '0'
  //   })
  //   await TestHelper.updatePerson(uploader2, uploader2.representative, TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.AT), {
  //     verification_document_front: TestHelper['success_id_scan_back.png'],
  //     verification_document_back: TestHelper['success_id_scan_back.png']
  //   })
  //   for (const field of uploadFields) {
  //     const user = await TestHelper.createUser()
  //     await TestHelper.createStripeAccount(user, {
  //       country: 'AT',
  //       type: 'company'
  //     })
  //     await TestHelper.createPerson(user, {
  //       relationship_representative: 'true',
  //       relationship_executive: 'true',
  //       relationship_title: 'SVP Testing',
  //       relationship_percent_ownership: '0'
  //     })
  //     await TestHelper.updatePerson(user, user.representative, TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.AT))
  //     const property = field.replace('verification_', 'verification.').replace('_front', '').replace('_back', '')
  //     await TestHelper.waitForAccountRequirement(user, `${user.representative.id}.${property}`)
  //     await TestHelper.waitForPersonRequirement(user, user.representative.id, property)
  //     const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
  //     req.account = user.account
  //     req.session = user.session
  //     req.body = TestHelper.createMultiPart(req, {}, {
  //       [field]: TestHelper['success_id_scan_back.png']
  //     })
  //     updateResponses[field] = await req.patch()
  //   }
  // })
  describe('exceptions', () => {
    describe('invalid-personid', () => {
      it('missing querystring personid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/connect/update-person')
        req.account = user.account
        req.session = user.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.US)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-personid')
      })

      it('invalid querystring personid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/connect/update-person?personid=invalid')
        req.account = user.account
        req.session = user.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.US)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-personid')
      })
    })

    describe('invalid-account', () => {
      it('ineligible accessing account', async () => {
        const user = await TestStripeAccounts.createCompanyWithRepresentative('DE')
        const user2 = await TestHelper.createUser()
        const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
        req.account = user2.account
        req.session = user2.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.DE)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-account')
      })
    })

    describe('invalid-person', () => {
      it('ineligible querystring person has no required information', async () => {
        const user = await TestStripeAccounts.createSubmittedCompany('DE')
        const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
        req.account = user.account
        req.session = user.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.DE)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-person')
      })
    })
  //   for (const field of fields) {
  //     describe(`invalid-${field}`, async () => {
  //       it(`missing posted ${field}`, async () => {
  //         const errorMessage = missingMessages[field]
  //         assert.strictEqual(errorMessage, `invalid-${field}`)
  //       })
  //       it(`invalid posted ${field}`, async () => {
  //         const errorMessage = errorMessages[field]
  //         assert.strictEqual(errorMessage, `invalid-${field}`)
  //       })
  //     })
  //   }
  //   describe('invalid-token', () => {
  //     it('missing posted token', async () => {
  //       const errorMessage = missingMessages['invalid-token']
  //       assert.strictEqual(errorMessage, 'invalid-token')
  //     })
  //     it('invalid posted token', async () => {
  //       const errorMessage = errorMessages['invalid-token']
  //       assert.strictEqual(errorMessage, 'invalid-token')
  //     })
  //   })
  // })
  // describe('receives', async () => {
  //   const testedRequiredFields = [
  //     'relationship_title',
  //     'relationship_director',
  //     'relationship_executive',
  //     'relationship_representative',
  //     'relationship_owner'
  //   ]
  //   for (const country of connect.countrySpecs) {
  //     const payload = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData[country.id])
  //     if (payload === false) {
  //       continue
  //     }
  //     for (const field in payload) {
  //       if (testedRequiredFields.indexOf(field) > -1) {
  //         continue
  //       }
  //       testedRequiredFields.push(field)
  //       it(`optionally-required posted ${field}`, async () => {
  //         const representative = updateResponses[field]
  //         if (field.startsWith('address_kana')) {
  //           const property = field.substring('address_kana_'.length)
  //           assert.strictEqual(representative.address_kana[property], payload[field])
  //         } else if (field.startsWith('address_kanji')) {
  //           const property = field.substring('address_kanji_'.length)
  //           // TODO: Stripe applies the submitted kana postal code value
  //           // and when it returns it is transformed from 1500001 to
  //           // 1500001 with a different charset so this is just wrong
  //           if (property === 'postal_code') {
  //             assert.strictEqual(representative.address_kanji[property], '1500001')
  //           } else {
  //             assert.strictEqual(representative.address_kanji[property], payload[field])
  //           }
  //         } else if (field.startsWith('address_')) {
  //           const property = field.substring('address_'.length)
  //           assert.strictEqual(representative.address[property], payload[field])
  //         } else if (field.startsWith('dob_')) {
  //           const property = field.substring('dob_'.length)
  //           assert.strictEqual(representative.dob[property], parseInt(payload[field], 10))
  //         } else if (field.startsWith('relationship_')) {
  //           const property = field.substring('relationship_'.length)
  //           if (payload[field] === 'true') {
  //             assert.strictEqual(representative.relationship[property], true)
  //           } else {
  //             assert.strictEqual(representative.relationship[property], payload[field])
  //           }
  //         } else if (field === 'id_number') {
  //           assert.strictEqual(representative.id_number_provided, true)
  //         } else if (field === 'ssn_last_4') {
  //           assert.strictEqual(representative.ssn_last_4_provided, true)
  //         } else {
  //           // TODO: Stripe may or may not transform the phone number
  //           // by removing hyphons and adding the country dial code
  //           // but submitting in that format is not allowed too
  //           if (field === 'phone') {
  //             if (representative[field] === payload[field]) {
  //               assert.strictEqual(representative[field], payload[field])
  //             } else {
  //               const withCountryCode = `+1${payload[field]}`
  //               assert.strictEqual(representative[field], withCountryCode)
  //             }
  //           } else {
  //             assert.strictEqual(representative[field], payload[field])
  //           }
  //         }
  //       })
  //     }
  //   }
  //   for (const field of uploadFields) {
  //     it(`optionally-required posted upload ${field}`, async () => {
  //       const representative = updateResponses[field]
  //       if (field.indexOf('additional_document') > -1) {
  //         if (field === 'verification_additional_document_front') {
  //           assert.notStrictEqual(representative.verification.additional_document.front, undefined)
  //           assert.notStrictEqual(representative.verification.additional_document.front, null)
  //         } else {
  //           assert.notStrictEqual(representative.verification.additional_document.back, undefined)
  //           assert.notStrictEqual(representative.verification.additional_document.back, null)
  //         }
  //       } else {
  //         if (field === 'verification_document_front') {
  //           assert.notStrictEqual(representative.verification.document.front, undefined)
  //           assert.notStrictEqual(representative.verification.document.front, null)
  //         } else {
  //           assert.notStrictEqual(representative.verification.document.back, undefined)
  //           assert.notStrictEqual(representative.verification.document.back, null)
  //         }
  //       }
  //     })
  //   }
  })

  describe('returns', () => {
    it('object', async () => {
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'GB',
        type: 'company'
      })
      await TestHelper.createPerson(user, {
        relationship_representative: 'true',
        relationship_executive: 'true',
        relationship_title: 'SVP Testing',
        relationship_percent_ownership: '0'
      })
      await TestHelper.waitForAccountRequirement(user, `${user.representative.id}.first_name`)
      await TestHelper.waitForPersonRequirement(user, user.representative.id, 'first_name')
      const req = TestHelper.createRequest(`/api/user/connect/update-person?personid=${user.representative.id}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.GB)
      req.filename = __filename
      req.saveResponse = true
      const personNow = await req.patch()
      assert.strictEqual(personNow.object, 'person')
    })
  })

  describe('configuration', () => {
    it('environment STRIPE_JS', async () => {
      global.stripeJS = 3
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'GB',
        type: 'company'
      })
      const identity = TestHelper.nextIdentity()
      const req = TestHelper.createRequest(`/account/connect/create-person?stripeid=${user.stripeAccount.id}`)
      req.account = user.account
      req.session = user.session
      req.body = {
        relationship_representative: 'true',
        relationship_executive: 'true',
        relationship_title: 'SVP Testing',
        relationship_percent_ownership: '0'
      }
      req.uploads = {
        verification_document_back: TestHelper['success_id_scan_back.png'],
        verification_document_front: TestHelper['success_id_scan_front.png']
      }
      await req.post()
      const representatives = await global.api.user.connect.Persons.get(req)
      const representative = representatives[0]
      await TestHelper.waitForAccountRequirement(user, `${representative.id}.first_name`)
      await TestHelper.waitForPersonRequirement(user, representative.id, 'first_name')
      const req2 = TestHelper.createRequest(`/account/connect/edit-person?personid=${representative.id}`)
      req2.account = user.account
      req2.session = user.session
      req2.body = TestStripeAccounts.createPostData(TestStripeAccounts.representativeData.GB, identity)
      req2.uploads = {
        verification_document_back: TestHelper['success_id_scan_back.png'],
        verification_document_front: TestHelper['success_id_scan_front.png']
      }
      await req2.post()
      // TODO: verifying information was submitted by token is not possible
      // so for now when objects are created/updated without a token they
      // have a metadata.token = false flag set
      const personNow = await global.api.user.connect.Person.get(req2)
      assert.strictEqual(personNow.metadata.token, undefined)
    })
  })
})