Skip to content

Commit

Permalink
Merge pull request #13 from silverl/master
Browse files Browse the repository at this point in the history
Many many changes...
  • Loading branch information
silverl authored Feb 5, 2019
2 parents da44c99 + 01f91a7 commit 5b5a50e
Show file tree
Hide file tree
Showing 12 changed files with 3,590 additions and 410 deletions.
3 changes: 3 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"esversion": 6
}
18 changes: 17 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
// Place your settings in this file to overwrite default and user settings.
{
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
// we want to use the TS server from our node_modules folder to control its version
"typescript.tsdk": "./node_modules/typescript/lib",

// OAuth NetSuite Token ID
"netSuiteUpload.netSuiteKey": "<INTEGRATION KEY>",

// OAuth NetSuite Token Secret
"netSuiteUpload.netSuiteSecret": "<INTEGRATION SECRET>",

// OAuth NetSuite Consumer Key
"netSuiteUpload.consumerToken": "<CONSUMER KEY>",

// OAuth NetSuite Consumer Secret
"netSuiteUpload.consumerSecret": "<CONSUMER SECRET>",

// Account number
"netSuiteUpload.realm": "<ACCOUNT NUMBER>"
}
59 changes: 44 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
**netsuite-upload** is a Visual Studio Code extension that allows you to manage your SuiteScript files directly from the IDE & helps you with defining of new momdules & module dependecies

## Features

### 1. NetSuite File Cabinet Management

Right-click the file/folder in the navigation panel to see the options:

- `Pull file from NetSuite` - downloads file from NetSuite
Expand All @@ -14,40 +16,67 @@ Right-click the file/folder in the navigation panel to see the options:
- `Compare file with NetSuite` - compares your local version with the NetSuite one
- `Pull folder from NetSuite` - Download the folder content from NetSuite

![Snippet & commands](img/netsuite_upload.gif)
![Snippet & commands](img/netsuite_upload.gif)

### 2. Snippets & commands

- `Snippets for module initialization` - type *defineRestlet...*, choose your module type and hit enter
- `Snippets for module initialization` - type _defineRestlet..._, choose your module type and hit enter
- `Commands for adding new NetSuite/custom dependencies` - open command line (`Ctrl`-`Shift`-`P`) and type
- *add netsuite dependency* for choosing of the NetSuite built-in module from the list
- *add custom dependency* for defining od custom dependecies
- _add netsuite dependency_ for choosing of the NetSuite built-in module from the list
- _add custom dependency_ for defining od custom dependecies

![Snippet & commands](img/snippet_addModule.gif)
![Snippet & commands](img/snippet_addModule.gif)

## Setup
##### NetSuite setup

### NetSuite setup

- Upload `netSuiteRestlet/vscodeExtensionRestlet.js` file somewhere in the `SuiteScripts` folder in NetSuite
- Create and deploy RESTlet using the file. (RESTlet URL will be set in the `settings.json`)

##### VSCode project setup
### VSCode project setup

- Open your local root **SuiteScripts** folder in VSCode
- If not yet created, create one or update the project `settings.json` inside the `.vscode` folder
- Copy the following code to `settings.json` and update with your settings

**settings.json**
### OAuth Authentication

I attempted to implement OAuth, but have failed. If anyone would like to help me figure out what the deal is, I'm open.

To experiment with OAuth, leave the setting for `netSuiteUpload.authentication` unset or commented out.

- If you wish to use OAuth authentication instead of basic authentication you can leave the authentication header blank and use the OAuth settings properties.
- First generate an Integration record in NetSuite, make sure the 'token based authentication' scheme is checked, and save the token and secret
- Second log into a role you wish to use for authentication and from the manage tokens center generate a new token and secret using the Integration from the previous step
- Input the 4 values from above in the corresponding settings options along with the account number in the realm property

### settings.json

```javascript
{
// Authentication header
"netSuiteUpload.authentication": "NLAuth nlauth_account=<ACCOUNTID>, nlauth_email=<LOGIN>, nlauth_signature=<PASSWORD>, nlauth_role=<ROLE>",
// Authentication header
"netSuiteUpload.authentication": "NLAuth nlauth_account=<ACCOUNTID>, nlauth_email=<LOGIN>, nlauth_signature=<PASSWORD>, nlauth_role=<ROLE>",

// Restlet URL
"netSuiteUpload.restlet": "<RESTlet URL>",

// Restlet URL
"netSuiteUpload.restlet": "<RESTlet URL>",
// Temporary folder (e.g. C:\\temp or /tmp) - used for storing compared file
"netSuiteUpload.tempFolder": "<TEMP FOLDER PATH>"

// Temporary folder (e.g. C:\\temp) - used for storing compared file
"netSuiteUpload.tempFolder": "<TEMP FOLDER PATH>"
// Oauth NetSuite Key or Token ID
"netSuiteUpload.netSuiteKey": "<NETSUITE TOKEN KEY>",
// Oauth NetSuite Secret
"netSuiteUpload.netSuiteSecret": "<NETSUITE SECRET>",
// Oauth NetSuite Consumer Key
"netSuiteUpload.consumerToken": "<CONSUMER TOKEN>",
// Oauth NetSuite Consumer Secret
"netSuiteUpload.consumerSecret": "<CONSUMER SECRET>",
// Account number
"netSuiteUpload.realm": "<NETSUITE ACCOUNT NUMBER>"
}
```

## Limitation
The plugin is using RESTlet for the communication with the NetSuite which is having some governance limitation. Current implementation does not deal with this problem, so there could be a problem to pull folders containing a lot of items from NetSuite.

The plugin is using RESTlet for the communication with the NetSuite which is having some governance limitation. Current implementation does not deal with this problem, so there could be a problem to pull folders containing a lot of items from NetSuite.
138 changes: 85 additions & 53 deletions bl/netSuiteBl.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,86 +7,116 @@ let uiHelper = require('../helpers/uiHelper');
let netsuiteList = require('../helpers/netsuiteList');
let _ = require('underscore');

function hasError(data, message) {
if (data.error) {
var errorMessage = message ? message : JSON.parse(data.error.message).message;
vscode.window.showErrorMessage(errorMessage);
return true;
}
return false;
}

function downloadFileFromNetSuite(file) {
nsRestClient.getFile(file, function(data) {
if (hasError(data)) return;

nsRestClient.getFile(file, function (err, res) {
if (hasNetSuiteError("ERROR downloading file", err, res)) {
return;
}

var relativeFileName = nsRestClient.getRelativePath(file.fsPath);

fs.writeFile(file.fsPath, data[0].content.toString());
vscode.window.showInformationMessage('File "' + relativeFileName + '" downloaded.');
fs.writeFile(file.fsPath, res.body[0].content);
vscode.window.showInformationMessage('SUCCESS! File "' + relativeFileName + '" downloaded.');
});
}

function uploadFileToNetSuite(file) {
var fileContent = fs.readFileSync(file.fsPath, 'utf8');

nsRestClient.postFile(file, fileContent, function(data) {
if (hasError(data)) return;

var relativeFileName = nsRestClient.getRelativePath(file.fsPath);

vscode.window.showInformationMessage('File "' + relativeFileName + '" uploaded.');
nsRestClient.postFile(file, fileContent, function (err, res) {
if (hasNetSuiteError("ERROR uploading file", err, res)) {
return;
}

var relativeFileName = nsRestClient.getRelativePath(file.fsPath);
vscode.window.showInformationMessage('SUCCESS! File "' + relativeFileName + '" uploaded.');
});
}

function hasNetSuiteError(custommessage, err, response) {
if (err) {
var msg = custommessage;
var items = [];
if (response && response.body && response.body.error) {
// The body of the response may contain a JSON object containing a NetSuite-specific
// message. We'll parse and display that in addition to the HTTP message.
var code = response.body.error.code;
var nsMessage = JSON.parse(response.body.error.message);
items = [
"NetSuite Error:",
"Code: " + code,
"Type: " + nsMessage.type,
"Name: " + nsMessage.name,
"Message: " + nsMessage.message,
"Stack: " + nsMessage.stack.toString()
];
} else if (err.status && err.stack) {
items = [
"Other Error:",
"Status: " + err.status,
"Stack:" + err.stack
];
}
var errormessage = msg + " " + items.join(" ");
console.log(err);
console.log(errormessage);
vscode.window.showErrorMessage(errormessage);
return true;
}
return false;
}

function deleteFileInNetSuite(file) {
nsRestClient.deleteFile(file, function(data) {
if (hasError(data)) return;

var relativeFileName = nsRestClient.getRelativePath(file.fsPath);
nsRestClient.deleteFile(file, function (err, res) {
if (hasNetSuiteError("ERROR deleting file", err, res)) {
return;
}

vscode.window.showInformationMessage('File "' + relativeFileName + '" deleted.');
var relativeFileName = nsRestClient.getRelativePath(file.fsPath);
vscode.window.showInformationMessage('SUCCESS! Deleted file "' + relativeFileName + '".');
});
}

function previewFileFromNetSuite(file) {
nsRestClient.getFile(file, function(data) {
if (hasError(data, 'File does not exist in NetSuite')) return;

nsRestClient.getFile(file, function (err, res) {
if (hasNetSuiteError("ERROR downloading file!", err, res)) {
return;
}

var relativeFileName = nsRestClient.getRelativePath(file.fsPath);
var tempFolder = vscode.workspace.getConfiguration('netSuiteUpload')['tempFolder'];
var filePathArray = (relativeFileName.split('.')[0] + '.preview.' + relativeFileName.split('.')[1]).split('\\');
var newPreviewFile = tempFolder + '\\' + filePathArray[filePathArray.length-1];
var tempFolder = vscode.workspace.getConfiguration('netSuiteUpload').tempFolder;
var filePathArray = (relativeFileName.split('.')[0] + '.preview.' + relativeFileName.split('.')[1]).split(path.sep);
var newPreviewFile = path.join(tempFolder, filePathArray[filePathArray.length - 1]);

fs.writeFile(newPreviewFile, data[0].content.toString());
fs.writeFile(newPreviewFile, res.body[0].content);

var nsFile = vscode.Uri.file(newPreviewFile);
vscode.commands.executeCommand('vscode.diff', file, nsFile, 'Local <--> NetSuite');
});
}

function downloadDirectoryFromNetSuite(directory) {
nsRestClient.getDirectory(directory, function(data) {
// TODO: fix another error messages + check other functions and fix there as well
if (hasError(data, 'Folder does not exist in NetSuite')) return;
nsRestClient.getDirectory(directory, function (err, res) {
if (hasNetSuiteError("ERROR downloading directory!", err, res)) {
return;
}

data.forEach(function(file) {
var fullFilePath = vscode.workspace.rootPath + file.fullPath.split('/').join('\\');
res.body.forEach(function (file) {
var fullFilePath = path.join(vscode.workspace.rootPath, file.fullPath.split('/').join(path.sep));

createDirectoryIfNotExist(fullFilePath + (file.type == 'folder' ? path.sep + '_' : ''));

createDirectoryIfNotExist(fullFilePath + (file.type == 'folder' ? '\\_' : ''));

if (file.type == 'file') {
fs.writeFile(fullFilePath, file.content.toString());
fs.writeFile(fullFilePath, file.content);
}
});

vscode.window.showInformationMessage('Folder successfully downloaded.');
vscode.window.showInformationMessage('SUCCESS: Downloaded ' + res.body.length + ' file(s).');
});
}

function createDirectoryIfNotExist(filePath) {
var dirname = path.dirname(filePath);

if (fs.existsSync(dirname)) {
return true;
}
Expand All @@ -98,37 +128,39 @@ function createDirectoryIfNotExist(filePath) {
function addCustomDependencyToActiveFile(editor) {
uiHelper.askForCustomDependency()
.then(values => {
addDependency(editor, values.depPath, values.depParam);
})
addDependency(editor, values.depPath, values.depParam);
});
}

function addNetSuiteDependencyToActiveFile(editor) {
let netsuiteLibs = netsuiteList.getSuiteScriptDependecies();

uiHelper.showListOfNetSuiteDependecies(_.pluck(netsuiteLibs, 'path'))
.then(value => {
var depRecord = _.findWhere(netsuiteLibs, { path: value });
var depRecord = _.findWhere(netsuiteLibs, {
path: value
});
addDependency(editor, depRecord.path, depRecord.param);
})
});
}

function addDependency(editor, pathText, paramText) {
let docContent = editor.document.getText();
let coords = codeChangeHelper.getCoords(docContent);
let oldParamsString = docContent.substring(coords.depParam.range[0], coords.depParam.range[1]);

let newParamsString = codeChangeHelper.getUpdatedFunctionParams(paramText, oldParamsString);
let newPathArrayString = codeChangeHelper.getUpdatedDepPath(pathText,
let newPathArrayString = codeChangeHelper.getUpdatedDepPath(pathText,
coords.depPath ? docContent.substring(coords.depPath.range[0], coords.depPath.range[1]) : null);

if (coords.depPath) {
codeChangeHelper.updateDocument(editor, coords.depParam.start.row - 1, coords.depParam.start.col,
codeChangeHelper.updateDocument(editor, coords.depParam.start.row - 1, coords.depParam.start.col,
coords.depParam.end.row - 1, coords.depParam.end.col, newParamsString);

codeChangeHelper.updateDocument(editor, coords.depPath.start.row - 1, coords.depPath.start.col,
codeChangeHelper.updateDocument(editor, coords.depPath.start.row - 1, coords.depPath.start.col,
coords.depPath.end.row - 1, coords.depPath.end.col, newPathArrayString);
} else { // Path array not defined
codeChangeHelper.updateDocument(editor, coords.depParam.start.row - 1, coords.depParam.start.col,
codeChangeHelper.updateDocument(editor, coords.depParam.start.row - 1, coords.depParam.start.col,
coords.depParam.end.row - 1, coords.depParam.end.col, newPathArrayString + ', ' + newParamsString);
}
}
Expand All @@ -139,4 +171,4 @@ exports.downloadDirectoryFromNetSuite = downloadDirectoryFromNetSuite;
exports.uploadFileToNetSuite = uploadFileToNetSuite;
exports.deleteFileInNetSuite = deleteFileInNetSuite;
exports.addCustomDependencyToActiveFile = addCustomDependencyToActiveFile;
exports.addNetSuiteDependencyToActiveFile = addNetSuiteDependencyToActiveFile;
exports.addNetSuiteDependencyToActiveFile = addNetSuiteDependencyToActiveFile;
Loading

0 comments on commit 5b5a50e

Please sign in to comment.