diff --git a/src/api/platforms/platforms.js b/src/api/platforms/platforms.js index a89f202..f350144 100644 --- a/src/api/platforms/platforms.js +++ b/src/api/platforms/platforms.js @@ -1,6 +1,6 @@ import fetch from 'node-fetch'; import { determineError } from '../../services/errors'; -import {get, patch, post, put} from '../../services/http'; +import { get, patch, post, put } from '../../services/http'; import { PLATFORMS_FILES_LIVE_URL, PLATFORMS_FILES_SANDBOX_URL } from '../../config'; const FormData = require('form-data'); @@ -76,6 +76,112 @@ export default class Platforms { } } + /** + * Our Platforms solution provides an easy way to upload documentation required for full due diligence. + * Use this endpoint to generate a file upload link, which you can then upload a file to using a data-binary type request. + * See the https://www.checkout.com/docs/platforms/onboard-sub-entities/full-sub-entity-onboarding/upload-a-file#Upload_a_file for more information. + * + * @memberof Platforms + * @param {string} entityId The ID of the sub-entity. + * @param {Object} body The body + * @param {string} body.purpose The purpose of the file upload. + * @returns {Promise} + */ + async uploadAFile(entityId, body) { + try { + const response = await post( + fetch, + `${this.config.host}/accounts/entities/${entityId}/files`, + this.config, + this.config.sk, + body + ); + return await response.json; + } catch (err) { + const error = await determineError(err); + throw error; + } + } + + /** + * Retrieve information about a previously uploaded file. + * + * @memberof Platforms + * @param {string} entityId The ID of the sub-entity. + * @param {string} fileId The ID of the file. The value is always prefixed with file_. + * @returns {Promise} + */ + async retrieveAFile(entityId, fileId) { + try { + const response = await get( + fetch, + `${this.config.host}/accounts/entities/${entityId}/files/${fileId}`, + this.config, + this.config.sk + ); + return await response.json; + } catch (err) { + const error = await determineError(err); + throw error; + } + } + + /** + * Retrieve information on all users of a sub-entity that has been invited through Hosted Onboarding + * (https://www.checkout.com/docs/platforms/onboard-sub-entities/onboard-with-hosted-onboarding). Only + * one user can be invited to onboard the sub-entity through Hosted Onboarding. + * + * To enable the Hosted Onboarding feature, contact your Customer Success Manager. + * + * @memberof Platforms + * @param {string} entityId Sub-entity id. + * @return {Promise} A promise to the Platforms response. + */ + async getSubEntityMembers(entityId) { + try { + const response = await get( + fetch, + `${this.config.host}/accounts/entities/${entityId}/members`, + this.config, + this.config.sk + ); + return await response.json; + } catch (err) { + const error = await determineError(err); + throw error; + } + } + + /** + * Resend an invitation to the user of a sub-entity. The user will receive another email to continue their + * Hosted Onboarding (https://www.checkout.com/docs/platforms/onboard-sub-entities/onboard-with-hosted-onboarding) + * application. An invitation can only be resent to the user originally registered to the + * sub-entity. + * + * To enable the Hosted Onboarding feature, contact your Customer Success Manager. + * + * @memberof Platforms + * @param {string} entityId The ID of the sub-entity. + * @param {string} userId The ID of the invited user. + * @param {Object} body The body (Reinvite sub-entity member) + * @return {Promise} A promise to the Platforms response. + */ + async reinviteSubEntityMember(entityId, userId, body) { + try { + const response = await put( + fetch, + `${this.config.host}/accounts/entities/${entityId}/members/${userId}`, + this.config, + this.config.sk, + body + ); + return await response.json; + } catch (err) { + const error = await determineError(err); + throw error; + } + } + /** * Use this endpoint to retrieve a sub-entity and its full details. * diff --git a/test/platforms/platforms.js b/test/platforms/platforms.js index b15c998..74d3fbd 100644 --- a/test/platforms/platforms.js +++ b/test/platforms/platforms.js @@ -389,6 +389,141 @@ describe('Platforms', () => { } }); + it('should upload a file', async () => { + nock('https://access.sandbox.checkout.com').post('/connect/token').reply(201, { + access_token: '1234', + expires_in: 3600, + token_type: 'Bearer', + scope: 'flow', + }); + nock('https://api.sandbox.checkout.com') + .post('/accounts/entities/ent_aneh5mtyobxzazriwuevngrz6y/files') + .reply(200, { + "id": "file_6lbss42ezvoufcb2beo76rvwly", + "maximum_size_in_bytes": 4194304, + "document_types_for_purpose": [ + "image/jpeg", + "image/png", + "image/jpg" + ], + "_links": { + "upload": { + "href": null + }, + "self": { + "href": "https://files.checkout.com/files/file_6lbss42ezvoufcb2beo76rvwly" + } + } + }); + + let cko = new Checkout(platforms_secret, { + client: platforms_ack, + scope: ['accounts'], + environment: 'sandbox', + }); + let platform = await cko.platforms.uploadAFile('ent_aneh5mtyobxzazriwuevngrz6y', { + purpose: "bank_verification" + }); + expect(platform.id).to.equal('file_6lbss42ezvoufcb2beo76rvwly'); + expect(platform.maximum_size_in_bytes).to.equal(4194304); + }); + + it('should retrieve a file', async () => { + nock('https://access.sandbox.checkout.com').post('/connect/token').reply(201, { + access_token: '1234', + expires_in: 3600, + token_type: 'Bearer', + scope: 'flow', + }); + nock('https://api.sandbox.checkout.com') + .get('/accounts/entities/ent_aneh5mtyobxzazriwuevngrz6y/files/file_6lbss42ezvoufcb2beo76rvwly') + .reply(200, { + "id": "file_6lbss42ezvoufcb2beo76rvwly", + "status": "invalid", + "status_reasons": [ + "InvalidMimeType" + ], + "size": 1024, + "mime_type": "application/pdf", + "uploaded_on": "2020-12-01T15:01:01Z", + "purpose": "identity_verification", + "_links": { + "download": { + "href": "https://s3.eu-west-1.amazonaws.com/mp-files-api-clean-prod/ent_ociwguf5a5fe3ndmpnvpnwsi3e/file_6lbss42ezvoufcb2beo76rvwly?X-Amz-Expires=3600&x-amz-security-token=some_token" + }, + "self": { + "href": "https://files.checkout.com/files/file_6lbss42ezvoufcb2beo76rvwly" + } + } + }); + + let cko = new Checkout(platforms_secret, { + client: platforms_ack, + scope: ['accounts'], + environment: 'sandbox', + }); + + let file = await cko.platforms.retrieveAFile('ent_aneh5mtyobxzazriwuevngrz6y', 'file_6lbss42ezvoufcb2beo76rvwly'); + expect(file.id).to.equal('file_6lbss42ezvoufcb2beo76rvwly'); + expect(file.status).to.equal('invalid'); + expect(file.size).to.equal(1024); + expect(file.mime_type).to.equal('application/pdf'); + expect(file.purpose).to.equal('identity_verification'); + }); + + it('should get a sub-entity members', async () => { + nock('https://access.sandbox.checkout.com').post('/connect/token').reply(201, { + access_token: '1234', + expires_in: 3600, + token_type: 'Bearer', + scope: 'flow', + }); + nock('https://api.sandbox.checkout.com') + .get('/accounts/entities/ent_aneh5mtyobxzazriwuevngrz6y/members') + .reply(200, { + "data": [ + { + "user_id": "usr_eyk754cqieqexfh6u46no5nnha" + } + ] + }); + + let cko = new Checkout(platforms_secret, { + client: platforms_ack, + scope: ['accounts'], + environment: 'sandbox', + }); + + let response = await cko.platforms.getSubEntityMembers('ent_aneh5mtyobxzazriwuevngrz6y'); + expect(response.data[0].user_id).to.equal('usr_eyk754cqieqexfh6u46no5nnha'); + }); + + it('should reinvite a sub-entity member', async () => { + nock('https://access.sandbox.checkout.com').post('/connect/token').reply(201, { + access_token: '1234', + expires_in: 3600, + token_type: 'Bearer', + scope: 'flow', + }); + nock('https://api.sandbox.checkout.com') + .put('/accounts/entities/ent_aneh5mtyobxzazriwuevngrz6y/members/usr_eyk754cqieqexfh6u46no5nnha') + .reply(200, { + "id": "usr_eyk754cqieqexfh6u46no5nnha" + }); + + let cko = new Checkout(platforms_secret, { + client: platforms_ack, + scope: ['accounts'], + environment: 'sandbox', + }); + + let member = await cko.platforms.reinviteSubEntityMember( + 'ent_aneh5mtyobxzazriwuevngrz6y', + 'usr_eyk754cqieqexfh6u46no5nnha'); + + expect(member.id).to.equal('usr_eyk754cqieqexfh6u46no5nnha'); + }); + it('should get sub-entity details', async () => { nock('https://access.sandbox.checkout.com').post('/connect/token').reply(201, { access_token: '1234',