I am trying to update a field after a record is submitted but the field is not updating. I know the script is firing because the debug is showing the oldweight value. Can you not update a field in an AfterSubmit userevent.
// 2.0 - Fluent
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(["N/record"], function (r) {
function onAfterSubmit(context) {
var oldweight = context.newRecord.getValue({ fieldId: 'custbody93' });
log.debug({
title: 'Old Weight',
details: oldweight
});
if (oldweight) {
var fixWeight = context.newRecord;
context.newRecord.setValue('custbody103', 'oldweight');
};
}
return {
afterSubmit: onAfterSubmit
};
});
In an afterSubmit event, the record has already been submitted and stored in the database, so you cannot update fields directly on the record in memory.
You'll need to use N/record to load() and save() the record or use submitFields() in order to update the database correctly.
Best practice for changing fields on the same record which triggered the User Event is to use beforeSubmit instead; within that entry point, your current code would work as you expect.
I have a video series on understanding User Events and one on how to work with records on my YouTube channel.
Related
guys!
I'm writing an email template for the invoices. On the invoice form I have a "Project" (internalId: Job) field -> on the "Project" form I have a "custom entity" field with employee-type. I can get an employee's name with ${transaction.job.custentity5}. But I can't get access to related fields such as email, phone number and etc. The code ${transaction.job.custentity5.email} gives me nothing. The code ${transaction.job.custentity5.mobilephone} gives me a strange error like "field job.mobilephone not found" (netsuite hides custentity5 in this objects chain), but I see this field in employee's profile.
How do i get child values from custentity field?
Unfortunately, you can't go into such a deep level with the standard data provided.
You can however fetch the data with a search.lookupFields during a beforeLoad and set it as default value on a custom field of the form.
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
*/
define(['N/ui/serverWidget', 'N/search'], function(serverWidget, search) {
function beforeLoad(context) {
var invoice = context.newRecord;
var form = context.form;
var type = context.type;
var UserEventType = context.UserEventType;
// only execute during printing...
if (type != UserEventType.PRINT) return
var jobID = invoice.getValue({fieldId: 'job'});
// return when no job/project is set on the invoice...
if (!jobID) return
var job = search.lookupFields({
type: search.Type.JOB,
id: jobID,
columns: ["custentity5"]
})
// return when no employee is set on the project...
if (!(job.custentity5 && job.custentity5[0] && job.custentity5[0].value)) return
var employee = search.lookupFields({
type: search.Type.JOB,
id: job.custentity5[0].value,
columns: ["email", "phone"]
})
var field = form.addField({
id : 'custpage_custom_data_employee',
label: 'Employee',
type : serverWidget.FieldType.LONGTEXT
});
field.defaultValue = JSON.stringify(employee);
}
return {
beforeLoad: beforeLoad
};
})
You can access the data within the template through:
<#if record.custpage_custom_data_employee?has_content>
<#assign employee = record.custpage_custom_data_employee?eval />
</#if>
Netsuite doesn't drill down that far for you. Generally you get one step away from the primary record so you see a name using ${transaction.job.custentity5} because you'd see a name if you opened the associated job record.
How you can show the details from custentity5 depends on a bunch of factors like who is sending this email? Is is special enough to have its own button? Is the email being sent batch etc.
Options:
A before load user event script can check whether the record is being printed or emailed the standard way. That script can load and populate custom fields on the main record so you may be able to reference ${transaction.custpage_ent5.mobilephone} where you'd added the job's custom entity to the transaction
fully script your email using n/Render. You'll likely need to script everything but you can look up and add arbitrary records and datastructures to your renderer. This would be triggered by a custom button or batched script.
Have been a developer for years, but just getting into NetSuite scripting. I wanted to start simple and create a script that would update the COMMENT field for all items on a purchase order. I started off by following the tutorial found here.
My modified script is below - it should update the MEMO field at the PO header and then every line's COMMENT field. I followed the steps in the article to save the script, create a Mass Update and then run it. In my criteria I set: "Transaction Number/ID" and "has keyword 90999" (just so it would only run on one specific purchase order). I confirmed my criteria was correct by clicking "Preview" and it only returns that one PO.
When I run the Mass Update, it runs fine and says it has been run successfully on 1 record (which is good). The MEMO field at the PO header DOES get updated, but the COMMENT field for each line does not. Am I doing something wrong or missing something simple? Is the getLineCount call not the correct one to use?
Note that I was doing all this in our Sandbox environment in case that makes any difference
UPDATE:
I know the getLineCount call is returning the correct number because if I move the poRec.setValue call inside the for loop, it gets run. So something must be wrong with my poRec.setSublistValue call?
/**
*#NApiVersion 2.0
*#NScriptType MassUpdateScript
*/
define(['N/record'],
function (record) {
function each(params) {
// Need to LOAD each record and SAVE it for changes to take effect
// LOAD the PO
var poRec = record.load({
type: params.type,
id: params.id
});
//var mainDepartment = poRec.getValue('department');
var mainDepartment = 'Hello World';
poRec.setValue({
fieldId: 'memo',
value: mainDepartment
});
// get a count of the line items
var lineCount = poRec.getLineCount({
sublistId: 'item'
});
// go through each of the line items and set the department to the main level department
for (var i = 0; i < lineCount; i++) {
poRec.setSublistValue({
sublistId: 'item',
fieldId: 'comment',
line: i,
value: mainDepartment
});
}
// SAVE the PO
poRec.save();
}
return {
each: each
};
});
There is no 'comment' field on the item sublist. The field you probably mean is 'description' (which expresses on searches as the line level 'memo' field - Netsuite for the win!)
Hi I'm currently developing a REST API using this generator.
https://github.com/diegohaz/rest?fbclid=IwAR3FwvhJuKpAtCrywOIRkpts8ZvZ_36Gk9b8ksSv2_MEgFtJnl4G7QZvGNI
But I'm kind of new with the MEAN stack environment especially mongoDB.
I just want to ask how to use the search query parameter described in this auto generated document of my project.
https://www.screencast.com/t/4wR7qyxj5ZP
I'm trying to search all the menu by list_id
for MYSQL something like this.
Select * from menu where list_id = '123';
So this generated REST API application is using querymen for search query. I already tried www.domain.com/menus?q={list_id:"1"}, www.domain.com/menus?q={"list_id":"1"} but none of this works it only shows empty results.
Here's my the router part of the code.
/**
* #api {get} /menus Retrieve menus
* #apiName RetrieveMenus
* #apiGroup Menu
* #apiUse listParams
* #apiSuccess {Object[]} menus List of menus.
* #apiError {Object} 400 Some parameters may contain invalid values.
*/
router.get('/',
query({ limit: { max: 1000 } }),
index)
I'm answering my question just in case someone has the same problem. So I figured out that I just need to include a custom schema in the query parameter so instead of
router.get('/',
query({ limit: { max: 1000 } }),
index)
It is now like this.
query({
list_id: {
type: String,
paths: ['list_id']
},
limit: { max: 1000 }
}),index)
You can also change the String to Regexp if you want.
I have a button on the Purchase Order record that performs a saved search query on the current record and then uses the http module to send that data via a POST to a url. That url then sends the data posted back as part of the success confirmation. The idea with the saved search is to create a javascript object that contains all the data that I want from the purchase order (main record and items sublist with subrecords) and then to use JSON.stringify to create a JSON payload for the http POST. I can't do this with the currentRecord because if you inspect it it only contains the internal id. This would also prevent me from having to go to the great lengths of writing a lot of code to manually build up a JSON string from the currentRecord.
Unfortunately I don't really understand how to specify the column names in the dynamically created saved search. Sometimes it looks to me like the column names are those from the NetSuite Records Browser and other times the script gives an error (column not found) if I use a column name from the NetSuite Records Browser (for example currencysymbol).
I'm also not sure how to specify columns that appear in sublists or subrecords in sublists. I tried to use item.itemtype but this gave me a column not found error. Just item completes successfully but I'm not sure whether this was really successfull since it is difficult to decode the returned result after the JSON.stringify (it adds a lot of backslashes). Using console.log (for some reason I don't get anything back using the NetSuite log.audit) is also quite difficult, although it looks like it is returning an array with 5 rows. So using item might sort of be successful. I say sort of because I have 3 item lines and it is returning 5 array rows.
So basically I would like to know where one can find the names of the columns to use in NetSuite for a saved search; and also how to specify sublist column names and sublist subrecord column names in a saved search.
/**
* #NApiVersion 2.0
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/ui/dialog', 'N/currentRecord', 'N/record', 'N/url', 'N/http', 'N/search'], function (dialog, rec, record, url, http, s) {
function pageInit(context) {
// All client scripts need at least one dummy function.
} // pageInit
function onButtonClick() {
var currentRecord = rec.get();
// Create a saved search dynamically.
var rs = s.create({
type: s.Type.PURCHASE_ORDER,
filters: [
["mainline", s.Operator.IS, "F"], "and",
["internalid", s.Operator.IS, currentRecord.id]
],
columns: [
"internalid",
"currency",
{
name: "item",
sort: s.Sort.ASC // DESC
}
]
});
var myPostDataObj = rs.run().getRange(0, 1000);
console.log(myPostDataObj);
var headers = {
'Content-Type': 'application/json; charset=utf-8',
};
http.post.promise({
url: 'http://httpbin.org:80/post',
body: JSON.stringify(myPostDataObj),
headers: headers
})
.then(function(response){
console.log('SUCCESS: ' + JSON.stringify(response));
})
.catch(function onRejected(reason) {
console.log('ERROR: ' + JSON.stringify(reason));
})
}
return {
pageInit: pageInit,
onButtonClick: onButtonClick
};
}); // Define
There are two Chrome extensions I suggest you get;
NetSuite Field Explorer. This extension will show you the ids (and values) of all the fields in a NetSuite record.
NetSuite Search Export. This extension will convert/export a saved search to SuiteScript.
For what you're doing, I would create your saved search in the UI, and then export it using the Saved Search Export extension, paste that into your code (where s.create is), and work from there.
The first extension is nice to get to the sublist field ids. Saves a lookup in the record browser.
I am trying to call the Netsuite SuiteScript 2.0 N/record module's load function, but I am unsure as to what to pass for the parameters. Basically I would like a N/record with the same id (primary key) of the current record in the UI, that I can use to loop through the sublist items.
I'm not sure how to use the Records Browser in order to find the correct type and id. The Records Browser does not have the type, so I guessed at the name. There are also multiple fields that could be the primary key id. Is it tranid or externalid or some other field? I'm specifically interested in the Inventory Adjustment form. externalid is undefined and tranid is To Be Generated.
Is it possible to get a N/Record based on the currentRecord in this manner or will it also suffer from the same issues I have with currentRecord (I can't use selectLine to step through the sublist items, sublist items have not been saved yet and the last one is partially completed)?
/**
* #NApiVersion 2.0
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/search', 'N/record'], function (s, r) {
function fieldChanged(context) {
var currentRecord = context.currentRecord;
var sublistName = context.sublistId;
var sublistFieldName = context.fieldId;
var currentLine = context.line;
var recordId = currentRecord.getValue({fieldId: "externalid"});
var record = r.load({
type: r.Type.INVENTORY_ADJUSTMENT,
id: recordId,
isDynamic: true
});
Is it possible to get a N/Record based on the currentRecord
Yes, although N/record module is used to load/create records. So in order to use N/record module, you need to make sure that your record already exists or you are creating new.
InternalId specified at the top of the Records Browser page is the recordType that you need to pass as type to record module.
Also try using async version of record load. i.e record.load.promise in client script.