Hye there,
I'm trying to prepare a scheduled script in NetSuite which will pick a particular directory from file cabinet and deploy it on SFTP server. I'm using 2.0 module and here is my code -
require(["N/sftp",'N/record','N/file'], function(sftp,record,file) {
function onRequest() {
var myPwdGuid = "13139ac567b14f74bdaXXXXXXX";
var myHostKey = "AAAAB3NzaC1ycXXXXX";
var connection = sftp.createConnection({
username: 'Your user name',
passwordGuid: myPwdGuid,
url: 'Your host name',
directory: '/directory to upload files/',
hostKey: myHostKey
});
var myFileToUpload = file.create({
name: 'originalname.js',
fileType: file.fileType.PLAINTEXT,
contents: 'I am a test file. Hear me roar.'
});
connection.upload({
directory: 'relative/path/to/remote/dir',
filename: 'newFileNameOnServer.js',
file: myFileToUpload,
replaceExisting: true
});
var downloadedFile = connection.download({
directory: 'relative/path/to/file',
filename: 'downloadMe.js'
});
}
onRequest();
return {
onRequest: onRequest
};
});
Now the issue is when i try to run these lines of code i get an error saying "AN_ERROR_OCCURRED_WHILE_DECRYPT_PASSWORDGUID".
What i've found so far through my research is GUID can only be generated by SuitLet form having credential field which will again require GET and POST method. However i Dont want to create a suitelet and invoke it manually in order to generate GUID. All i want to to do is - Run a scheduled script which will Establish connection to SFTP. Pick a directory in file cabinet and upload it on SFTP.
Any help would be greatly appreciated! Thanks in advance!
Its easier and faster than you might think. Take the below code and load it to NetSuite. Create a script file and deployment quick, run the SUITElet to get your GUID, paste that value into your Scheduled Script and don't mess with it again unless the password changes.
/**
*#NApiVersion 2.x
*#NScriptType Suitelet
*/
define([
'N/ui/serverWidget',
'N/https'
],
function (
ui,
https
) {
var HOST_KEY_TOOL_URL = 'https://ursuscode.com/tools/sshkeyscan.php?url=';
function getFormTemplate() {
var form;
form = ui.createForm({
title: 'Password Form'
});
form.addSubmitButton({
label: 'Submit'
});
return form;
}
function addSelectorFields(form) {
var select = form.addField({
id: 'selectaction',
type: ui.FieldType.SELECT,
label: 'Select Action'
});
select.addSelectOption({
value: 'getpasswordguid',
text: 'Get Password GUID'
});
select.addSelectOption({
value: 'gethostkey',
text: 'Get Host Key'
});
return form;
}
function addPasswordGUID1Fields(form) {
var frm = form;
frm.addField({
id: 'restricttoscriptids',
type: ui.FieldType.TEXT,
label: 'Restrict To Script Ids'
}).isMandatory = true;
frm.addField({
id: 'restricttodomains',
type: ui.FieldType.TEXT,
label: 'Restrict To Domains'
}).isMandatory = true;
return frm;
}
function addPasswordGUID2Fields(form, restrictToScriptIds, restrictToDomains) {
form.addCredentialField({
id: 'password',
label: 'Password',
restrictToScriptIds: restrictToScriptIds.replace(' ', '').split(','),
restrictToDomains: restrictToDomains.replace(' ', '').split(',')
});
return form;
}
function addHostKeyFields(form) {
form.addField({
id: 'url',
type: ui.FieldType.TEXT,
label: 'URL (Required)'
});
form.addField({
id: 'port',
type: ui.FieldType.INTEGER,
label: 'Port (Optional)'
});
form.addField({
id: 'hostkeytype',
type: ui.FieldType.TEXT,
label: 'Type (Optional)'
});
return form;
}
function onRequest(option) {
var method;
var form;
var selectAction;
var port;
var hostKeyType;
var restricttoscriptids;
var restricttodomains;
var password;
var theResponse;
var myUrl;
var url;
method = option.request.method;
form = getFormTemplate(method);
if (method === 'GET') {
form = addSelectorFields(form);
}
if (method === 'POST') {
selectAction = option.request.parameters.selectaction;
if (selectAction === 'getpasswordguid') {
form = addPasswordGUID1Fields(form);
} else if (selectAction === 'gethostkey') {
form = addHostKeyFields(form);
} else {
password = option.request.parameters.password;
url = option.request.parameters.url;
port = option.request.parameters.port;
hostKeyType = option.request.parameters.hostkeytype;
restricttoscriptids = option.request.parameters.restricttoscriptids;
restricttodomains = option.request.parameters.restricttodomains;
if (restricttoscriptids && restricttodomains) {
form = addPasswordGUID2Fields(form, restricttoscriptids, restricttodomains);
}
if (password) {
form.addField({
id: 'passwordguidresponse',
type: ui.FieldType.LONGTEXT,
label: 'PasswordGUID Response',
displayType: ui.FieldDisplayType.INLINE
}).defaultValue = password;
}
if (url) {
myUrl = HOST_KEY_TOOL_URL + url + '&port=' + port + '&type=' + hostKeyType;
theResponse = https.get({ url: myUrl }).body;
form.addField({
id: 'hostkeyresponse',
type: ui.FieldType.LONGTEXT,
label: 'Host Key Response',
displayType: ui.FieldDisplayType.INLINE
}).defaultValue = theResponse;
}
}
}
option.response.writePage(form);
}
return {
onRequest: onRequest
};
});
The ability to directly hard-code an SFTP password is not supported in NetSuite. NetSuite uses password tokenization in order to prevent scripts from having access to user credentials. For this reason, only an authenticated user may store a password, and a script may only access it via an identifier (GUID/Token).
Related
When utilizing a User Event Script, I am attempting to loop through a context object to find all newRecord objects that are selected by a user in the Inventory Print screen. I am able to retrieve a single record within the context object, however, if a user selects multiple invoices to print, I am unable to retrieve the additional invoices.
When looking at the Execution log, I am unable to see the entire context object.
My script is as follows:
/** #NApiVersion 2.0 #NScriptType UserEventScript
*/
define(['N/record'], function (record) { function
beforeLoad(context) {
try {
var arrInvoiceIds= []
var arrFileNames= []
var r = context.newRecord
var nrf = r.getFields()
//fetch invoice record
var invoiceRecord = record.load({ type: record.Type.INVOICE, id: r.id })
for(var i=0; i < nrf.length; i++){
var customerName = ""
var invNo = ""
var fileName = ""
if(nrf[i] == "entity"){
customerName = invoiceRecord.getValue('entity');
}
if(nrf[i] == "tranid"){
invNo = invoiceRecord.getValue('tranid');
}
if(customerName != "" && invNo != ""){
fileName = customerName + "_" + invNo;
}
}
log.debug ({
title: 'r.id',
details: r.id //arrInvoiceIds //arrFileNames
});
log.debug ({
title: 'nrf',
details: nrf //arrInvoiceIds //arrFileNames
});
log.debug ({
title: 'nrf.length',
details: nrf.length //arrInvoiceIds //arrFileNames
});
log.debug ({
title: 'context',
details: context //arrInvoiceIds //arrFileNames
});
log.debug ({
title: 'file',
details: fileName //arrInvoiceIds //arrFileNames
});
} catch (e) {
log.error ({
title: e.name,
details: e.message
});
}
}
return {
beforeLoad: beforeLoad
}; });
When you print multiple invoices, the UserEvent is simply triggered multiple times. You should see that in your logs. The invoices are not combined on a single instance of context within a single UserEvent.
I need to save and submit the information for a form for enrollment > employees, each time it is filled out. I need to save and submit the information for a form for enrollment > employees each time it is filled out. I sent an image of where I want the information to be stored. I created a send button, but it doesn’t send
ImageExample
/**
*#NApiVersion 2.x
*#NScriptType Suitelet
*/
define(['N/ui/serverWidget'], function (serverWidget) {
function onRequest(context) {
var formulario = serverWidget.createForm({
title: 'Formulário',
hideNavBar: false
});
formulario.addButton({
id: 'buttonid',
label: 'Cancelar'
})
formulario.addSubmitButton({
label: 'Enviar'
});
/*
formulario.addField({
id: 'field_test',
type: serverWidget.FieldType.INTEGER,
label: 'campo teste',
container: 'fieldgroupcapture'
})
*/
formulario.addField({
id: 'sublista_campo1',
label: 'Código empresa',
type: serverWidget.FieldType.INTEGER
});
formulario.addField({
id: 'sublista_campo2',
label: 'Código funcionário',
type: serverWidget.FieldType.TEXT
})
formulario.maxLength = 5;
formulario.addField({
id: 'sublista_campo3',
label: 'Código evento',
type: serverWidget.FieldType.INTEGER
});
var fieldReference = formulario.addField({
id: 'sublista_campo4',
label: 'Referência',
type: serverWidget.FieldType.INTEGER
});
var fieldValue = formulario.addField({
id: 'sublista_campo5',
label: 'Valor',
type: serverWidget.FieldType.FLOAT
});
formulario.addField({
id: 'sublista_campo6',
label: 'Mês e ano',
type: serverWidget.FieldType.DATE
});
if (fieldReference === '' && fieldReference === null) {
fieldReference.defaultValue = '0000'
};
if (fieldValue === '' && fieldValue === null) {
fieldValue.defaultValue = '0000'
}
context.response.writePage(formulario);
};
return {
onRequest: onRequest
};
});
Your script would need to handle a POST request. Right now it doesn't distinguish between GET and POST so it just shows the form over and over.
function onRequest(context){
if (context.request.method === 'GET') {
... your current code
}else{ // assumes POST
handle creating/updating an employee record
}
}
Another approach to consider would be to just have a heavily edited standard employee form linked to a role. That is then code free except possibly a UserEvent script that forces the edited form to be shown based on user and context.
I have a Suitelet script to create a form, there I pull the information contained in a "Custom Record type" as the default value for the form fields.
Also create a ClientScript for the Suitelet form with the functions that are executed by clicking a button.
The function works, but I don't know how to update the information of the custom record type.
Here is part of my code:
Suitelet:
/**
*#NApiVersion 2.0
*#NScriptType Suitelet
*/
define(['N/record', 'N/search', 'N/ui/serverWidget'],
function(record, search, serverWidget) {
function onRequest(context) {
try {
if (context.request.method === 'GET') {
var form = serverWidget.createForm({
title: 'SKU Information'
});
form.clientScriptFileId = 3060;
//create fields groups to organize the fields
var itemgroup = form.addFieldGroup({
id : 'itemgroup',
label : 'Next item SKU Number'
});
var usegroup = form.addFieldGroup({
id : 'usegroup',
label : 'Who is using this?'
});
//Add the fields
var skufield = form.addField({
id: 'skufield',
type: serverWidget.FieldType.TEXT,
label: 'SKU Number',
container: 'itemgroup'
});
skufield.isMandatory = true;
// create a field with the user using this numbers when clicking the button
var whousingskunumber = form.addField({
id: 'namefield',
type: serverWidget.FieldType.TEXT,
label: 'User:',
container: 'usegroup'
});
whousingskunumber.updateDisplayType({
displayType: serverWidget.FieldDisplayType.DISABLED
});
var usingsince = form.addField({
id: 'sincefield',
type: serverWidget.FieldType.TEXT,
label: 'Using since',
container: 'usegroup'
});
usingsince.updateDisplayType({
displayType: serverWidget.FieldDisplayType.DISABLED
});
// Add the buttons
form.addSubmitButton({
label: 'Update Number'
});
form.addResetButton({
label: 'Cancel'
});
var useNumber = form.addButton({
label: 'Use this number',
id: 'useNumber',
functionName: 'useNumberFunction',
});
var releaseNumber = form.addButton({
label: 'Release usage',
id: 'relaseNumber',
functionName: 'relaseNumberFunction',
});
context.response.writePage(form);
} else {
// Section Four - Output - Used in all sections
var delimiter = /\u0001/;
var skuField = context.request.parameters.skufield;
var whoField = context.request.parameters.whofield;
var ccField = context.request.parameters.cctypefield;
context.response.write('You have entered:'
+ '<br/> New SKU Number: '+ whoField + skuField);
}
var skuNumObj = search.lookupFields({
type: 'customrecordere_lw_lastskunum',
id: 2,
columns: ['custrecord_ere_lw_usingsince', 'custrecordere_lw_nextskunum', 'custrecord_ere_lw_whousingskunum']
});
var usingSince = skuNumObj.custrecord_ere_lw_usingsince;
var whoIsUsing = skuNumObj.custrecord_ere_lw_whousingskunum;
var nextSku = skuNumObj.custrecordere_lw_nextskunum;
skufield.defaultValue = nextSku;
whousingskunumber.defaultValue = 'Nobody';
usingsince.defaultValue = 'You can use it!';
} catch (error) {
log.error({title: 'Failed to get items to update', details: error});
}
}
return {
onRequest: onRequest
};
});
ClientScript
/**
* #NApiVersion 2.x
* #NScriptType ClientScript
*/
//Noslen Pena
define(['N/runtime', 'N/currentRecord', 'N/ui/dialog', 'N/search'],
function (runtime, currentRecord, dialog, search) {
function pageInit(context){
try {
} catch (error) {
log.error({title: 'Failed initializing', details: error});
}
}
function useNumberFunction(){
try {
var skuNumObj = search.lookupFields({
type: 'customrecordere_lw_lastskunum',
id: 2,
columns: ['custrecord_ere_lw_usingsince', 'custrecordere_lw_nextskunum', 'custrecord_ere_lw_whousingskunum']
});
var nextSku = skuNumObj.custrecordere_lw_nextskunum[0].value;
skuNumObj.custrecordere_lw_nextskunum[0].value = Number(nextSku)+1;
dialog.alert({
title: "Information",
message: 'Remember to unlock after you have used'
});
context.skufield.updateDisplayType({
displayType: serverWidget.FieldDisplayType.DISABLED
});
} catch (error) {
log.error({title: 'Failed clicking the button', details: error});
}
}
function relaseNumberFunction(){
dialog.alert({
title: "Thank you!",
message: "Remember to update the number and save the changes"
});
record.namefield.setValue('Nobody');
log.debug({title: 'liberaron el uso', details:'Nobody is using the number now'})
}
return {
pageInit : pageInit,
useNumberFunction : useNumberFunction,
relaseNumberFunction : relaseNumberFunction
};
});
I figured it out, The way to save the changes or submit a new value to the custom record type is like this:
var id = record.submitFields({
type: 'customrecordere_lw_lastskunum',
id: 2,
values: {
custrecord_ere_lw_usingsince : since,
custrecord_ere_lw_whousingskunum : username
},
options: {
enableSourcing: false,
ignoreMandatoryFields : true
}
});
I am writing small node.js script that will run multiple command & if any one fails, it will report an issue on the mentis. I am using following code to report issue in mantis bugtracker. Mantis bug tracker comes with an bunch of SOAP api to do stuffs like this. http://www.mantisbt.org/bugs/api/soap/mantisconnect.php?wsdl#op.idp90022480
var soap = require('soap');
var url = 'http://localhost/mantisbt-1.2.19/api/soap/mantisconnect.php?wsdl';
var user = 'administrator';
var password = 'root';
var args = {
username: user,
password: password,
project: {
id: 1
},
category: 'General',
summary: 'Test summary',
description: 'test description'
};
soap.createClient(url, function(err, client) {
client.mc_issue_add(args, function(err1, result) {
if(err1)
console.log( err1 );
else
console.log('Issue successfully created');
});
});
But I am getting following error log:
<faultstring>Project \'\' does not exist.</faultstring>
I have a project with id 1, & I can create an issue with same data using php. My understanding is project id is not being send properly. Equivalent php code is as follow.
$c = new SoapClientDebug("http://localhost/mantisbt-1.2.19/api/soap/mantisconnect.php?wsdl", ['trace' => true]);
$username = 'administrator';
$password = 'root';
$issue = array (
'summary' => 'PHP test issue',
'description' => 'PHP test description',
'project'=> array(
'id'=>1
),
'category'=>'General',
);
$c->mc_issue_add($username, $password, $issue);
The php code is functional.
Your args should be like this:
var args = {
username: user,
password: password,
issue: {
project: {
id: 1
},
category: 'General',
summary: 'Test summary',
description: 'test description'
}
};
I'm having trouble understanding how to retrieve an XMPP roster (and eventually the presence state of each contact) in node-xmpp (GTalk account).
My example code can login and connect, but I'm a bit lost as to what to send and listen for:
var xmpp = require('node-xmpp')
jid = 'example#gmail.com'
password = 'xxxxxxxxxxxxxx'
// Establish a connection
var conn = new xmpp.Client({
jid: jid,
password: password,
host: 'talk.google.com',
port: 5222
})
conn.on('online', function() {
console.log('ONLINE')
var roster = new xmpp.Element('iq', {
type: 'get',
from: jid,
id: new Date().getTime()
}).c('query', { xmlns: 'jabber:iq:roster' })
conn.send(roster) // Now what?
})
conn.on('error', function(e) {
console.log(e)
})
Looks like the structure of my roster query was wrong, this works correctly:
conn.on('online', function() {
console.log('ONLINE')
var roster = new xmpp.Element('iq', {
id: 'roster_0',
type: 'get'
}).c('query', {
xmlns: 'jabber:iq:roster'
})
conn.send(roster)
})