async prepare(inputFilePath, headerMapping, defaultLabels) {
        const batchSize = 1;

        const siteTimezone = this._getTimezone();
        const currentTime = moment().tz(siteTimezone).format('YYYY-MM-DD HH:mm:ss.SSS');
        const outputFileName = `Members Import ${currentTime}.csv`;
        const outputFilePath = path.join(this._storagePath, '/', outputFileName);

        const pathExists = await fs.pathExists(outputFilePath);

        if (pathExists) {
            throw new errors.DataImportError(tpl(messages.filenameCollision));
        }

        const rows = await membersCSV.parse(inputFilePath, headerMapping, defaultLabels);
        const numberOfBatches = Math.ceil(rows.length / batchSize);
        const mappedCSV = membersCSV.unparse(rows);

        const hasStripeData = rows.find(function rowHasStripeData(row) {
            return !!row.stripe_customer_id || !!row.complimentary_plan;
        });

        await fs.writeFile(outputFilePath, mappedCSV);

        return {
            id: outputFilePath,
            batches: numberOfBatches,
            metadata: {
                hasStripeData
            }
        };
    }
/**
     * Prepares a CSV file for import
     * - Maps headers based on headerMapping, this allows for a non standard CSV
     *   to be imported, so long as a mapping exists between it and a standard CSV
     * - Stores the CSV to be imported in the storagePath
     * - Creates a MemberImport Job and associated MemberImportBatch's
     *
     * @param {string} inputFilePath - The path to the CSV to prepare
     * @param {Object.<string, string>} headerMapping - An object whos keys are headers in the input CSV and values are the header to replace it with
     * @param {Array<string>} defaultLabels - A list of labels to apply to every member
     *
     * @returns {Promise<{id: JobID, batches: number, metadata: Object.<string, any>}>} - A promise resolving to the id of the MemberImport Job
     */
Prepares a CSV file for import
- Maps headers based on headerMapping, this allows for a non standard CSV
to be imported, so long as a mapping exists between it and a standard CSV
- Stores the CSV to be imported in the storagePath
- Creates a MemberImport Job and associated MemberImportBatch's

@param {string} inputFilePath - The path to the CSV to prepare
@param {Object.} headerMapping - An object whos keys are headers in the input CSV and values are the header to replace it with
@param {Array} defaultLabels - A list of labels to apply to every member

@returns {Promise<{id: JobID, batches: number, metadata: Object.}>} - A promise resolving to the id of the MemberImport Job
Prepares a CSV file for import - Maps headers based on headerMapping this allows for a non standard CSV to be imported so long as a mapping exists between it and a standard CSV - Stores the CSV to be imported in the storagePath - Creates a MemberImport Job and associated MemberImportBatch ' s @param { string } inputFilePath - The path to the CSV to prepare @param { Object . } headerMapping - An object whos keys are headers in the input CSV and values are the header to replace it with @param { Array } defaultLabels - A list of labels to apply to every member @returns { Promise< { id : JobID batches : number metadata : Object . } > } - A promise resolving to the id of the MemberImport Job
async prepare(inputFilePath, headerMapping, defaultLabels) {
        const batchSize = 1;
        const siteTimezone = this._getTimezone();
        const currentTime = moment().tz(siteTimezone).format('YYYY-MM-DD HH:mm:ss.SSS');
        const outputFileName = `Members Import ${currentTime}.csv`;
        const outputFilePath = path.join(this._storagePath, '/', outputFileName);
        const pathExists = await fs.pathExists(outputFilePath);
        if (pathExists) {
            throw new errors.DataImportError(tpl(messages.filenameCollision));
        }
        const rows = await membersCSV.parse(inputFilePath, headerMapping, defaultLabels);
        const numberOfBatches = Math.ceil(rows.length / batchSize);
        const mappedCSV = membersCSV.unparse(rows);
        const hasStripeData = rows.find(function rowHasStripeData(row) {
            return !!row.stripe_customer_id || !!row.complimentary_plan;
        });
        await fs.writeFile(outputFilePath, mappedCSV);
        return {
            id: outputFilePath,
            batches: numberOfBatches,
            metadata: {
                hasStripeData
            }
        };
    }
async prepare ( inputFilePath , headerMapping , defaultLabels ) { const batchSize = 1 ; const siteTimezone = this . _getTimezone ( ) ; const currentTime = moment ( ) . tz ( siteTimezone ) . format ( 'YYYY-MM-DD HH:mm:ss.SSS' ) ; const outputFileName = ` ${ currentTime } ` ; const outputFilePath = path . join ( this . _storagePath , '/' , outputFileName ) ; const pathExists = await fs . pathExists ( outputFilePath ) ; if ( pathExists ) { throw new errors . DataImportError ( tpl ( messages . filenameCollision ) ) ; } const rows = await membersCSV . parse ( inputFilePath , headerMapping , defaultLabels ) ; const numberOfBatches = Math . ceil ( rows . length / batchSize ) ; const mappedCSV = membersCSV . unparse ( rows ) ; const hasStripeData = rows . find ( function rowHasStripeData ( row ) { return ! ! row . stripe_customer_id || ! ! row . complimentary_plan ; } ) ; await fs . writeFile ( outputFilePath , mappedCSV ) ; return { id : outputFilePath , batches : numberOfBatches , metadata : { hasStripeData } } ; }
Prepares a CSV file for import
 - Maps headers based on headerMapping, this allows for a non standard CSV
   to be imported, so long as a mapping exists between it and a standard CSV
 - Stores the CSV to be imported in the storagePath
 - Creates a MemberImport Job and associated MemberImportBatch's
Prepares a CSV file for import - Maps headers based on headerMapping this allows for a non standard CSV to be imported so long as a mapping exists between it and a standard CSV - Stores the CSV to be imported in the storagePath - Creates a MemberImport Job and associated MemberImportBatch ' s