@twec/node-suite
Version:
Generic functionality for connecting to NetSuite Web Services from Node
186 lines (163 loc) • 5.82 kB
JavaScript
const path = require('path');
const fs = require('fs');
const util = require('util');
const debug = require('debug')('node-suite');
const soap = require('./soap');
const foldersUtils = require('./folders');
const readFile = util.promisify(fs.readFile);
// const DEFAULT_SUITETALK_VERSION = 'v17_2';
// https://webservices.netsuite.com/wsdl/v2017_2_0/netsuite.wsdl
const DEFAULT_VERSION = 'v2017_2';
class NetSuite {
constructor(config, errorHandler) {
const defaultConfig = {
concurrency: 5,
version: DEFAULT_VERSION,
domain: '',
passport: { account: '' },
oauth: {
consumer: { key: '', secret: '' },
token: { key: '', secret: '' },
},
};
this.config = { ...defaultConfig, ...config };
this.handleError = errorHandler || ((error) => { throw error; });
}
// ----- Error Handling
handleResponseError(status) {
const error = new Error('Unsuccessful response from NetSuite');
const detail = status.statusDetail;
if (detail) {
error.message = detail.message;
error.code = detail.code;
}
this.handleError(error);
}
// ----- Helper methods
static async readFileContent(filePath) {
const file = await readFile(filePath);
return file.toString('base64');
}
// ---- Methods for getting NetSuite-specific Body Formats for SOAP Requests
getUrnFileCabinet() {
return `urn:filecabinet_${this.config.version}.documents.webservices.netsuite.com`;
}
static getRecordBody({ type, internalId, externalId }) {
return {
name: 'platformMsgs:recordRef',
attributes: {
'xsi:type': 'platformCore:RecordRef', type, internalId, externalId,
},
};
}
static getUploadExternalId(filename, folderInternalId) {
const now = (new Date()).getTime();
return `${filename}_${folderInternalId}_${now}`;
}
getUploadBody({ filename, fileContent, folderInternalId }) {
// Based on https://gitlab.com/twec/digital/netsuite-upload-utils/blob/master/src/file-cabinet-client.ts#L295
return {
name: 'platformMsgs:recordRef',
attributes: {
'xmlns:q1': this.getUrnFileCabinet(),
'xsi:type': 'q1:File',
internalId: '',
externalId: NetSuite.getUploadExternalId(filename, folderInternalId),
},
children: [
{ name: 'q1:name', value: filename },
{ name: 'q1:content', value: fileContent },
{
name: 'q1:folder',
attributes: {
internalId: folderInternalId,
type: 'folder',
},
},
],
};
}
getSearchFolderBody() {
// Originally based on https://gitlab.com/twec/digital/netsuite-upload-utils/blob/master/src/file-cabinet-client.ts#L354
return {
name: 'platformMsgs:search',
attributes: {
xmlns: this.getUrnFileCabinet(),
'xsi:type': 'FolderSearch',
// FolderSearch - http://www.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2018_1/schema/search/foldersearch.html?mode=package
},
};
}
// ---- Make Requests
async makeSoapRequest(operation, body) {
debug('Making soap request - ', operation, 'using body:', body);
try {
return await soap({ config: this.config, operation, body });
} catch (err) {
this.handleError(err);
return err;
}
}
checkStatusSuccess(status) {
if (status && status['@isSuccess'] && status['@isSuccess'] !== 'true') {
this.handleResponseError(status);
}
}
async get({ type, internalId, externalId }) {
const body = NetSuite.getRecordBody({ type, internalId, externalId });
const response = await this.makeSoapRequest('get', body);
const { status, record } = (response || {});
this.checkStatusSuccess(status);
return record;
}
async searchFolder(folderPath) {
// Originally based on https://gitlab.com/twec/digital/netsuite-upload-utils/blob/master/src/file-cabinet-client.ts#L340
const folderPathArray = folderPath.split(path.sep);
debug(folderPath, folderPathArray);
const body = this.getSearchFolderBody();
debug('Searching for folder', folderPathArray);
try {
const response = await this.makeSoapRequest('search', body);
const { status, recordList } = (response || {});
this.checkStatusSuccess(status);
debug('response status:', status);
const folderRecords = (recordList || {}).record || [];
// debug(folderRecords);
const folder = foldersUtils.findFolderRecord(folderPathArray, folderRecords);
if (!folder) {
this.handleError(new Error('Folder not found'));
}
return folder;
} catch (err) {
this.handleError(err);
return err;
}
}
async fetchFolderInternalId(targetFilePath) {
const folderPath = path.dirname(targetFilePath);
const folderRecord = await this.searchFolder(folderPath);
debug(folderRecord);
const folderInternalId = folderRecord['@internalId'];
return folderInternalId;
}
async upload(localFilePath, targetFilePath) { // Upload a local file to netsuite
debug('Upload', localFilePath, 'to', targetFilePath);
const fileContent = await NetSuite.readFileContent(localFilePath);
return this.uploadFileContent(fileContent, targetFilePath);
}
async uploadFileContent(fileContent, targetFilePath) {
const folderInternalId = await this.fetchFolderInternalId(targetFilePath);
const filename = path.basename(targetFilePath);
const body = this.getUploadBody({
filename,
folderInternalId,
fileContent,
});
const response = await this.makeSoapRequest('upsert', body);
debug('Upload response:', response);
const { status, baseRef } = (response || {});
this.checkStatusSuccess(status);
return baseRef;
}
}
module.exports = NetSuite;