I'm trying to create a script file on NetSuite using SuiteScript 2.0 to update the External Id of the classification records. For some reason, NetSuite updates all fields but externalId.
I want to create this script to update the externalIds because mostly of our CSV templates uses the externalIds to look for master data such as accounts and classes. The point is, NetSuite doesn't show the externalIds on the forms and all the records created via UI, has no information in this field. So the idea here is to schedule a script to fill this field automatically based on some other fields.
Here is my code
/**
* #NApiVersion 2.0
* #NScriptType ScheduledScript
*/
define(['N/runtime','N/log','N/record','N/search'], function(runtime,log,record,search) {
var qtyProjects=0;
function execute(context) {
try
{
log.debug('Script Started');
/********** Update Project (Classes) External ID ***********/
var classificationSearchObj = search.create({
type: "classification",
filters:
[
["externalid","is","#NONE#"]
],
columns:
[
search.createColumn({name: "name",label: "Name"}),
search.createColumn({name: "custrecord_proj_full_name",label: "FullName"}),
search.createColumn({name: "custrecord_proj_manager",label: "ProjectManager"}),
search.createColumn({name: "externalid",label: "Externalid"})
]
});
var prj_srch = classificationSearchObj.run().each(processProject);
log.debug('Quantity of projects: ',qtyProjects);
log.debug('Script Finished');
}
catch(e)
{
log.debug('Error',e.message);
}
}
function processProject(result) {
var number = result.getValue({name: "name"});
var fullName = result.getValue({name: "custrecord_proj_full_name"});
var externalid = result.getValue({name: "externalid"});
qtyProjects++;
log.debug('Update Number|Name|ExternalId: ',number + " | " + fullName + " | " + externalid);
record.submitFields({
"type":'classification',
"id": result.id,
"values": {
"externalId": externalid,
"custrecord_proj_full_name": "Test Ale 2",
}
});
/*
var project_id = project.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
*/
//return true;
}
return {
execute: execute
};
});
You mispelled the id of ExtermalId, it is without Capital 'I' as externalid. This should work.
As a rule of thumb native field id's don't have capital letters in it
/**
* #NApiVersion 2.0
* #NScriptType ScheduledScript
*/
define(['N/runtime','N/log','N/record','N/search'], function(runtime,log,record,search) {
function execute(context) {
var so = record.load({
type: record.Type.SALES_ORDER,
id: 12345
});
so.setValue('external','6789');
so.save();
return true;
}
return {
execute: execute
}
});
Have you tried loadig the record, setting the external id then saving it?
Yes i tried loading the record and set external id , it worked for me . Please use record browser for internal id's of fields (externalid).
Your code is searching for classes with no externalid and is updating the class's externalid with the empty value found in the search. It appears you are missing a lookup to get what the new externalid should be.
I've found that SuiteScript 2 syntax does not work for updating externalId. For me, this simply doesn't do anything:
instance.setValue({ fieldId: 'externalid', value: 'FOO1' })
While using the older syntax actually will update externalId:
instance.setValue('externalid', 'FOO1')
You can run this in your browser's console while viewing a record to try it out:
require(['N/record'], function (record) {
const instance = record.load({ type: 'customerpayment', id: 5000 })
instance.setValue('externalid', 'PYMT1234')
instance.save()
})
Related
I have a button that is created in a user event that - when clicked - should create a new transaction using value from the record the button was clicked on. My issue is that I do not know how I can get the values from the old record so I can use them for the new record.
Button Script
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
*/
define([],
function() {
function beforeLoad(scriptContext) {
var form = scriptContext.form;
var cr = scriptContext.newRecord;
scriptContext.form.clientScriptModulePath = 'SuiteScripts/additional_booking.js';
form.addButton({
id: "custpage_addl_booking_button",
label: "Add'l Booking",
functionName: "additionalBooking"
});
}
return {
beforeLoad: beforeLoad,
};
});
Script to create new record
/**
*#NApiVersion 2.1
*#NScriptType ClientScript
*/
define(['N/record', 'N/currentRecord', 'N/url'], (record, currentRecord, url) => {
function pageInit() {};
function additionalBooking(context) {
var redirectUrl = url.resolveRecord({
recordType: 'salesorder',
isEditMode: true,
params: {
'entity': client,
'subsidiary': subsidiary
}
});
window.open(redirectUrl);
}
return {
pageInit: pageInit,
additionalBooking: additionalBooking
};
});
Any guidance is appreciated.
Your client script can extract values and pass them to the new record as parameters.
If they are standard fields Netsuite will populate the new record with them. If they are non-standard fields you would set the values in a before load user event or in a pageInit client event.
This post: How can I have a sales order that is created via suitescript not save but open in browser> shows the formatting of the parameters for creating a new sales order.
I am trying to create a custom sublist with sublist field with source to be States record that is managed in Setup > Company > States/Provinces/Countries section.
Here is the example code that I am using and it doesn't work.
_sublist.addField({
id: 'custpage_license_state,
type: serverWidgetModule.FieldType.SELECT,
label: 'LICENSE STATE',
source: 'state' //not recognizing record id
});
I have tried using 'state', 'states', '-195', -195 (was able to locate that this is the internal id for states record in our instance "-195"), but nothing works.
Does anybody has an idea on how to make that work.
Thanks.
The State/Province record isn't exposed. You'll need to add the options to the field manually. You could either perform a search against the customer records which will only return states currently assigned;
/**
* Gets customers geographical states.
*
* #returns {Array} of state information.
*/
function getStates() {
var records = [];
var customerSearchObj = search.create({
type: "customer",
filters: [
["formulatext: {country}", "isnotempty", ""],
"AND",
["formulatext: {state}", "isnotempty", ""]
],
columns: [
search.createColumn({
name: "statedisplayname",
summary: "GROUP",
sort: search.Sort.ASC
}),
search.createColumn({ // abbreviation
name: "state",
summary: "GROUP"
})
]
});
customerSearchObj.run().each(function (result) {
var rec = {
state: result.getValue({name: 'state', summary: 'GROUP'}),
stateDisplay: result.getValue({name: 'statedisplayname', summary: 'GROUP'})
};
records.push(rec);
return true;
});
return records;
}
Or, create a customer in memory and then get the states; (Sorry, SS1 code, taken from SA 63293.)
function getAllStatesForCountry() {
var customer_record = nlapiCreateRecord('customer', {recordmode: 'dynamic'});
customer_record.selectLineItem('addressbook', 1);
var addrSubrecord = customer_record.createCurrentLineItemSubrecord('addressbook', 'addressbookaddress');
addrSubrecord.setFieldValue('country', 'GB');
var stateField = addrSubrecord.getField('dropdownstate');
return stateField.getSelectOptions();
}
And then loop through the result and add them to your field using mySelect.addSelectOption().
I try to send an email to all users who have the role of engineer,
I would like to find a function that send emails for all users according to their roles,
or any function that returns me all the users by their role,
Is suite script includes one of those functions?
Search for all employees with a particular role, then loop through them to send the email. Here's an example of a scheduled script and a custom module that does this.
emailUtils.js
/**
* #NAPIVersion 2.0
* #NModuleScope Public
*/
define(['N/email', 'N/search'], function(email, search) {
function sendEmailToRole(emailObject, roleId) {
var employeeIds = getEmployeesByRole(roleId);
employeeIds.forEach(function(employeeId) {
emailObject.recipients = employeeId;
email.send(emailObject)
});
}
function getEmployeesByRole(roleId) {
var results = search.create({
type: 'employee',
filters: [
['isinactive', 'is', 'F'],
'and', ['role', 'anyof', roleId]
]
}).run().getRange({ start: 0, end: 1000 });
return (results || []).map(function(result) {
return result.id;
})
}
return {
sendEmailToRole: sendEmailToRole
};
});
emailSchedule.js
/**
* #NAPIVersion 2.0
* #NModuleScope Public
* #NScriptType ScheduledScript
*/
define(['./emailUtils'], function(emailUtils) {
function execute() {
var ADMINISTRATOR = 3;
var email = {
author: 1073,
subject: 'SUBJ: This is a test email',
body: 'This is the body of the test email',
};
emailUtils.sendEmailToRole(email, ADMINISTRATOR);
}
return {
execute: execute
}
});
The approach I recommend would be to make a new Saved Search of the Employees with this role (and any other criteria you'd like met), then use that Saved Search to define a dynamic Entity Group (Lists > Relationships > Groups > New). You can then set this Group as the recipient of your email.
You should do a saved search of employees where their role is Engineer. You can then use the sendEmail function to email each of those people
I have created a saved search for transaction in netsuite and with suitescript 2.0 I am showing saved search data in my application. In application user can apply filter on any fields (please see the attached screenshot). For example user select "Aug 2011" for posting period, only transactions of Aug 2011 should be loaded. This works fine if I create a filter with internalid of "Aug 2011", but on UI I dont have internal id.
sample code:
/*
here is my required module
*/
function getTransactionData(datain)
{
try
{
var objSearch = search.load
({
id: datain.savedsearchid
});
/***** Work *****/
objSearch.filters.push(search.createFilter({ name: "postingperiod", operator: "ANYOF", values: "1" })); //here 1 is internalid of periodname "Aug 2011"
/***** Not Work (SSS_INVALID_SRCH_FILTER_JOIN) *****/
//objSearch.filters.push(search.createFilter({ name: "postingperiod", join: "accountingperiod", operator: "ANYOF", values: "Aug 2011" }));
objSearch.run();
}
catch(ex)
{
log.error("getTransactionData", ex);
throw ex;
}
}
I tried with join but seeing "SSS_INVALID_SRCH_FILTER_JOIN" error from Netsuite.
Can any one please help me regarding this.
Thanks in advance
I edited your code to a more simplified one to understand better.
If you get the gist of how it works, you can edit/customize the way you want.
I assume there is join 'accountingperiod' option available for 'postingperiod' and this works perfectly in your saved search you created in netsuite without using suitescript.
/*
here is my required module
*/
function getTransactionData(datain) {
try {
var objSearch = search.load({
id: datain.savedsearchid
});
var defaultFilters = objSearch.filters;
var customFilters = [];
//Adding filter
customFilters = ['postingperiod', 'ANYOF', '1'];
defaultFilters.push(customFilters);
customFilters = undefined;
customFilters = [];
//Adding filter
/*
customFilters = ['postingperiod.accountingperiod', 'ANYOF', 'Aug 2011'];
defaultFilters.push(customFilters);
*/
objSearch.filters = defaultFilters;
var objSearch_run = objSearch.run().getRange({
start: 0,
end: 10
});
} catch (ex) {
log.error("getTransactionData", ex);
throw ex;
}
}
If you want to know how filters is stored in saved search you created in netsuite, you can use the script debugger.
The following code is suitescript 1.0
//Load Saved Search
get();
function get() {
var search = nlapiLoadSearch('transaction', ' ENTER SAVED SEARCH ID HERE ');
log.debug('search',search);
var searchFilters = search.getFilterExpression();
log.debug('searchFilters',searchFilters);
return search;
}
I assume your application is a Suitelet? If so, you need to do a select field type of your record. So probably of 'posting periods'. This will show your periods in a drop down.
When the user selects it, have a client side script auto refresh the data and load your saved search.
Alternatively, you can load all the data and do the filtering client side DOM filtering. Really need a bit more information about your "application".
My company runs several different types of projects and would like to view the project record differently depending on the type of project being run in the selected project record.
I have the field that selects the form to use, which is titled "custom form" (this is a select field) and a field that our staff enter the type of project "custentityjt_fie_pro_projecttype" (also a select field).
I have created the following before load user event script to try to achieve this:
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(["N/record"], function(r) {
function beforeLoad(context) {
var currentRecord = context.newRecord;
var projectType = currentRecord.getValue({
fieldId: "custentityjt_fie_pro_projecttype",
});
currentRecord.setValue({
fieldID: 'customform',
value: projectType
})
}
return {
beforeLoad: beforeLoad,
}
})
When loading the project record in edit mode, the custom form selection does not change, and when loading the project record in view mode, I get the following:
{"type":"error.SuiteScriptError","name":"UNEXPECTED_ERROR","message":null,"stack":["anonymous(N/recordService)","beforeLoad(/SuiteScripts/setForm.js:13)"],"cause":{"type":"internal error","code":"UNEXPECTED_ERROR","details":null,"userEvent":"beforeload","stackTrace":["anonymous(N/recordService)","beforeLoad(/SuiteScripts/setForm.js:13)"],"notifyOff":false},"id":"","notifyOff":false}
I'm very new to Netsuite and programming in general so please be gentle :)
You need to use a Client Script in order to change the Custom Form. Best bet would be to do it in two places, a pageInit() and a fieldChanged(). Another potential issue would be trying to set the Custom form value to a value that was retrieved in the getValue of your field custentityjt_fie_pro_projecttype. The value returned from the currentRecord.getValue() from your example will be the internal id of the custom list value for the Project Type that is set there (go back to your custom list and you will see the internal id values listed). That is an issue because when setting the value of Custom Form field you will need to reference the Internal Id of the Custom Form you wish to use. It would be remarkable if the Internal ID of the Project Type referenced ever matched the Custom Form Internal Id. My recommendation would be to create a hash table in your code to store the references (assuming your list of Project Types didn't frequently change). Give this a try (just make sure you update the values in the lookup variable as those are made up.
/**
*#NApiVersion 2.x
*#NScriptType ClientScript
*/
define([
'N/record'
],
function (
nsRecord
) {
//
// lookup table where the object property represents the internal IDs of the
// custom list values, and the value of each property represents the
// internal id's of the Custom Forms you wish to associate with each list value.
//
var lookup = {
1: 122,
2: 123,
3: 125,
4: 136
};
function fieldChanged(context) {
var field = context.fieldId;
var rec = context.currentRecord;
var projId;
if (field === 'custentityjt_fie_pro_projecttype' && rec.getValue('custentityjt_fie_pro_projecttype')) {
projId = rec.getValue('custentityjt_fie_pro_projecttype');
if (lookup[projId]) {
rec.setValue({
fieldId: 'customform',
value: lookup[projId],
ignoreFieldChange: true,
fireSlavingSync: true
});
}
}
}
function pageInit(context) {
var rec = context.currentRecord;
var mode = context.mode;
var projId;
var formId;
if (mode !== 'create') {
formId = rec.getValue('customform');
projId = rec.getValue('custentityjt_fie_pro_projecttype');
if (lookup[projId] && lookup[projId] !== formId) {
rec.setValue({
fieldId: 'customform',
value: lookup[projId],
ignoreFieldChange: true,
fireSlavingSync: true
});
}
}
}
return {
fieldChanged: fieldChanged,
pageInit: pageInit
};
});