NetSuite SuiteScript 2.0 How to specify field, sublist field or subrecord field in N/search create API - netsuite

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.

Related

Netsuite email template - how to get child values from custentity field?

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.

SuiteScript Updating Search Result Fields

I have a search in SuiteScript 2.0 that's working fine. But for each record the search brings back, I want to update a particular field (I use it elsewhere to determine that the record has been examined). It's potentially a very large result set, so I have to page it. Here's my code:
var sResult = mySearch.runPaged({pageSize: 10});
for (var pageIndex = 0; pageIndex < sResult.pageRanges.length; pageIndex++)
{
var searchPage = sResult.fetch({ index: pageRange.index });
searchPage.data.forEach(function (result)
{
var name = result.getValue({ name: "altname"})
result.setValue({
name: 'tracker',
value: new Date()
})
});
}
You can see where I have a call to result.setValue(), which is a non-existent function. But it shows where I want to update the 'tracker' field and what data I want to use.
Am I barking up the wrong tree entirely here? How do I update the field for each result returned?
As Simon says you can't directly update a search result, but you can use submitFields method.
This example is from NetSuite documentation:
var otherId = record.submitFields({
type: 'customrecord_book', //record Type
id: '4', // record Id
values: {
'custrecord_rating': '2'
}
});
This approach will save more governance than load and save the record.
AFAIK You can't directly update a search result and write the value back to the record, the record needs to be loaded first. The snippet doesn't say what the type of record it is you're searching for or want to load, but the general idea is (in place of your result.setValue line):
var loadedRecord = Record.load({type:'myrecordtype', id:result.id});
loadedRecord.setValue( {fieldId:'tracker', value: new Date() });
loadedRecord.save();
Keep in mind SuiteScript governance and the number of records your modifying. Load & Save too many and your script will terminate earlier than you expect.
Bad design: instead of using result.setValue inside the iteration, push those to an "update" array then after the data.forEach have another function that loops thru the update array and processes them there with record.submitFields()
Be careful of governance....

Firestore: Increment some numeric field by a variable number using an AJAX post. NodeJs

I have 11 different numeric fields for every user in my application. I want to build an api to increment one of those fields by a certain amount.
The request would be of this form:
{
"uid":"Qewqhfui7232289",
"field":"someName",
"value":13.4
}
The api would then retrieve the document with id "uid" and increment the field someName by 13.4
Most of the examples I see are incrementing a specific field by a constant.
Something like this (but that actually works):
var router = express.Router();
router.post('/increment', function (req, res, next) {
var ref = db.collection('UserInfo').doc(req.body.uid);
var field=req.body.field;
var value=req.body.value;
var transaction = db.runTransaction(function(t) {
return t.get(ref)
.then(function(doc) {
var updated= doc.data().field + value;
t.update(ref, {field: updated);
});
}).then(function(result) {
console.log('Transaction success!');
}).catch(function(err) {
console.log('Transaction failure:', err);
});
res.send("response");
});
Do I need to create an api for every single field?
And does firestore support variable incrementation (ie not a hard-coded number)?
EDIT: Some clarifications::
1)I am just planning on editing single documents, not several.
2)I want to create an api that is able to increment any field according to request body input (instead of creating an api for each field). But that's not essential as I can just create several api's.
3)My TOP PRIORITY is to know how to increment using a variable that is set using req.body.value rather than a fixed number that's hard-coded into the api.
EDIT2: I settled for creating an API for each field.
A single call to Document.update() can update multiple fields in a document. But it can only update a single document.
Do I need to create an api for every single field?
If the fields are in a single document, you can update them all with one call like:
var data= doc.data();
t.update(ref, {field: data.field + value, field2: data.field2 + value, field3: data.field3 + value);
And does firestore support variable incrementation (ie not a hard-coded number)?
There is currently no API to tell the database server to "increment this field", but that is being considered and work has even been done on it. As usually though there are no guarantees when (or even if) this feature will make it into a release.

Podio Filter item method response missing files details

In nodejs I am trying to filter podio data by using FilterItems its working fine but its not giving files attributes. I can get the files count but I need uploaded files details. Here is my sample code
var Podio = require('podio-js').api;
var podio = new Podio({
authType: 'server',
clientId: 'XXXXX',
clientSecret:'*****************'
});
podio.authenticateWithApp('XXXXX', 'YYYYYYYYYYYYYY', function(err) {
podio.request('POST', '/item/app/XXXXX/filter', {
"filters": { "email":'sample#gmail.com'}
}).then(function(responseData) {
console.log(responseData);
}).catch(function(e) {
console.log(e);
});
});
To solve this problem am doing one more call Get Item by using Item-id (Which I have received from filter call).
Here my question is why filter method is not giving files details whether its bug in podio filter call or is there any specific reason. Please suggest better way too.
Note: In my scenario I should use only filter functionality;
You can get additional fields (including files) by bundling responses using fields parameter. It's described here: https://developers.podio.com/index/api
Sample:
// Include files when getting filtered items
/item/app/{app_id}/filter/?fields=items.fields(files)

Pagination for search indexes on cloudant

I have a cloudant db which contains documents for access logs of users. Example:
{
"name": "John Doe",
"url": "somepage.html",
"dateaccessed": "2016-08-23T21:20:25.502Z"
}
I created a search index with a function:
function (doc) {
if(doc.dateaccessed) {
var d = new Date(doc.dateaccessed);
index("dateaccessed", d.getTime(), {store: true});
}
}
Now this setup is working as expected with just a normal query. Example
{
q: 'dateaccessed:[1420041600000 TO 1471987625266]',
include_docs: true,
sort: '-dateaccessed<number>',
}
However, I wish to limit the results - let's say 5 at a time (which can be done with the "limit: 5" argument), and I want to somehow make a pagination - be able to move to the next 5 results or the previous 5 results.
I checked the cloudant documentation and there's an argument there called "bookmark" (https://cloudant.com/for-developers/search/) but I'm not sure how to use it.
May I request for any insights on this?
The Cloudant documentation shows examples on how to use bookmarks, but the gist is that you get a bookmark from the server in your search response, when requesting the next page, you use the bookmark received in your request with the bookmark parameter in either your JSON object for POST, or in the query params for GET.

Resources