async perform(id) {
        const job = await this.getJob(id);

        if (job.status === 'complete') {
            throw new errors.BadRequestError(tpl(messages.jobAlreadyComplete));
        }

        const rows = membersCSV.parse(job.filename);

        const membersApi = await this._getMembersApi();

        const defaultProductPage = await membersApi.productRepository.list({
            limit: 1
        });

        const defaultProduct = defaultProductPage.data[0];

        const result = await rows.reduce(async (resultPromise, row) => {
            const resultAccumulator = await resultPromise;

            const trx = await this._knex.transaction();
            const options = {
                transacting: trx
            };

            try {
                const existingMember = await membersApi.members.get({email: row.email}, {
                    ...options,
                    withRelated: ['labels']
                });
                let member;
                if (existingMember) {
                    const existingLabels = existingMember.related('labels') ? existingMember.related('labels').toJSON() : [];
                    member = await membersApi.members.update({
                        ...row,
                        labels: existingLabels.concat(row.labels)
                    }, {
                        ...options,
                        id: existingMember.id
                    });
                } else {
                    member = await membersApi.members.create(row, options);
                }

                if (row.stripe_customer_id) {
                    await membersApi.members.linkStripeCustomer({
                        customer_id: row.stripe_customer_id,
                        member_id: member.id
                    }, options);
                } else if (row.complimentary_plan) {
                    if (!this._isSet('multipleProducts')) {
                        await membersApi.members.setComplimentarySubscription(member, options);
                    } else if (!row.products) {
                        await membersApi.members.update({
                            products: [{id: defaultProduct.id}]
                        }, {
                            ...options,
                            id: member.id
                        });
                    }
                }

                if (this._isSet('multipleProducts')) {
                    if (row.products) {
                        await membersApi.members.update({
                            products: row.products
                        }, {
                            ...options,
                            id: member.id
                        });
                    }
                }

                await trx.commit();
                return {
                    ...resultAccumulator,
                    imported: resultAccumulator.imported + 1
                };
            } catch (error) {
                // The model layer can sometimes throw arrays of errors
                const errorList = [].concat(error);
                const errorMessage = errorList.map(({message}) => message).join(', ');
                await trx.rollback();
                return {
                    ...resultAccumulator,
                    errors: [...resultAccumulator.errors, {
                        ...row,
                        error: errorMessage
                    }]
                };
            }
        }, Promise.resolve({
            imported: 0,
            errors: []
        }));

        return {
            total: result.imported + result.errors.length,
            ...result
        };
    }
/**
     * Performs an import of a CSV file
     *
     * @param {JobID} id - The id of the job to perform
     */
Performs an import of a CSV file
@param {JobID} id - The id of the job to perform
Performs an import of a CSV file @param { JobID } id - The id of the job to perform
async perform(id) {
        const job = await this.getJob(id);
        if (job.status === 'complete') {
            throw new errors.BadRequestError(tpl(messages.jobAlreadyComplete));
        }
        const rows = membersCSV.parse(job.filename);
        const membersApi = await this._getMembersApi();
        const defaultProductPage = await membersApi.productRepository.list({
            limit: 1
        });
        const defaultProduct = defaultProductPage.data[0];
        const result = await rows.reduce(async (resultPromise, row) => {
            const resultAccumulator = await resultPromise;
            const trx = await this._knex.transaction();
            const options = {
                transacting: trx
            };
            try {
                const existingMember = await membersApi.members.get({email: row.email}, {
                    ...options,
                    withRelated: ['labels']
                });
                let member;
                if (existingMember) {
                    const existingLabels = existingMember.related('labels') ? existingMember.related('labels').toJSON() : [];
                    member = await membersApi.members.update({
                        ...row,
                        labels: existingLabels.concat(row.labels)
                    }, {
                        ...options,
                        id: existingMember.id
                    });
                } else {
                    member = await membersApi.members.create(row, options);
                }
                if (row.stripe_customer_id) {
                    await membersApi.members.linkStripeCustomer({
                        customer_id: row.stripe_customer_id,
                        member_id: member.id
                    }, options);
                } else if (row.complimentary_plan) {
                    if (!this._isSet('multipleProducts')) {
                        await membersApi.members.setComplimentarySubscription(member, options);
                    } else if (!row.products) {
                        await membersApi.members.update({
                            products: [{id: defaultProduct.id}]
                        }, {
                            ...options,
                            id: member.id
                        });
                    }
                }
                if (this._isSet('multipleProducts')) {
                    if (row.products) {
                        await membersApi.members.update({
                            products: row.products
                        }, {
                            ...options,
                            id: member.id
                        });
                    }
                }
                await trx.commit();
                return {
                    ...resultAccumulator,
                    imported: resultAccumulator.imported + 1
                };
            } catch (error) {
                const errorList = [].concat(error);
                const errorMessage = errorList.map(({message}) => message).join(', ');
                await trx.rollback();
                return {
                    ...resultAccumulator,
                    errors: [...resultAccumulator.errors, {
                        ...row,
                        error: errorMessage
                    }]
                };
            }
        }, Promise.resolve({
            imported: 0,
            errors: []
        }));
        return {
            total: result.imported + result.errors.length,
            ...result
        };
    }
async perform ( id ) { const job = await this . getJob ( id ) ; if ( job . status === 'complete' ) { throw new errors . BadRequestError ( tpl ( messages . jobAlreadyComplete ) ) ; } const rows = membersCSV . parse ( job . filename ) ; const membersApi = await this . _getMembersApi ( ) ; const defaultProductPage = await membersApi . productRepository . list ( { limit : 1 } ) ; const defaultProduct = defaultProductPage . data [ 0 ] ; const result = await rows . reduce ( async ( resultPromise , row ) => { const resultAccumulator = await resultPromise ; const trx = await this . _knex . transaction ( ) ; const options = { transacting : trx } ; try { const existingMember = await membersApi . members . get ( { email : row . email } , { ... options , withRelated : [ 'labels' ] } ) ; let member ; if ( existingMember ) { const existingLabels = existingMember . related ( 'labels' ) ? existingMember . related ( 'labels' ) . toJSON ( ) : [ ] ; member = await membersApi . members . update ( { ... row , labels : existingLabels . concat ( row . labels ) } , { ... options , id : existingMember . id } ) ; } else { member = await membersApi . members . create ( row , options ) ; } if ( row . stripe_customer_id ) { await membersApi . members . linkStripeCustomer ( { customer_id : row . stripe_customer_id , member_id : member . id } , options ) ; } else if ( row . complimentary_plan ) { if ( ! this . _isSet ( 'multipleProducts' ) ) { await membersApi . members . setComplimentarySubscription ( member , options ) ; } else if ( ! row . products ) { await membersApi . members . update ( { products : [ { id : defaultProduct . id } ] } , { ... options , id : member . id } ) ; } } if ( this . _isSet ( 'multipleProducts' ) ) { if ( row . products ) { await membersApi . members . update ( { products : row . products } , { ... options , id : member . id } ) ; } } await trx . commit ( ) ; return { ... resultAccumulator , imported : resultAccumulator . imported + 1 } ; } catch ( error ) { const errorList = [ ] . concat ( error ) ; const errorMessage = errorList . map ( ( { message } ) => message ) . join ( ', ' ) ; await trx . rollback ( ) ; return { ... resultAccumulator , errors : [ ... resultAccumulator . errors , { ... row , error : errorMessage } ] } ; } } , Promise . resolve ( { imported : 0 , errors : [ ] } ) ) ; return { total : result . imported + result . errors . length , ... result } ; }
Performs an import of a CSV file
 @param {JobID} id - The id of the job to perform
Performs an import of a CSV file @param { JobID } id - The id of the job to perform
// The model layer can sometimes throw arrays of errors