suitescript 2.0 fail to evaluate - suitescript2.0

I am a novice suitescript writer and cannot figure out what I am doing wrong. I am trying to load a very simple suitescript 2.0 script to calculate values in a custom table. I can upload the script file just fine but when I create the script record, I get the following error: Fail to evaluate script: {"type":"error.SuiteScriptModuleLoaderError","name":"UNEXPECTED_ERROR","message":"missing : after property id (SS_SCRIPT_FOR_METADATA#22)","stack":[]}
Here is the code
/**
*#NApiVersion 2.x
*#NScriptType ClientScript
*/
define(['N/currentRecord'],
function fieldChanged(context) {
var fieldName=context.currentRecord.fieldID;
//return if not one of these fields
if (fieldName!=='custrecord_am_ehir_emp_prem_percent' &&
fieldName!=='custrecord_am_ehir_dep_prem_percent' &&
fieldName!=='custrecord_am_ehir_total_month_prem')
return false;
else
//get premium and percent values
var totalPremium=currentRecord.getValue(
{fieldID:'custrecord_am_ehir_total_month_prem'
});
var employeeOnlyPremium=currentRecord.getValue(
{fieldID:'custrecord_am_ehir_emp_only_prem'
});
var employeePercent=currentRecord.getValue(
{fieldID:'custrecord_am_ehir_emp_prem_percent'
});
var dependentPercent=currentRecord.getValue(
{fieldID:'custrecord_am_ehir_dep_prem_percent'
});
var employeePremium=totalPremium*employeePercent;
var dependentPremium=(to1talPremium-employeeOnlyPremium)*dependentPercent;
var companyPremium=totalPremium-employeePremium-dependentPremium;
//set field values
currentRecord.setValue(
{fieldID:'custrecord_am_ehir_emp_month_prem',employeePremium
});
currentRecord.setValue(
{fieldID:'custrecord_am_ehir_dep_month_prem',dependentPremium
});
currentRecord.setValue(
{fieldID:'custrecord_am_ehir_co_month_prem',companyPremium
});
return {fieldChanged:fieldChanged};
}
);

Robert,
The property name is "fieldId" instead of "fieldID". I think that is causing the error.
Regards,
Luiz Morais

I saw some code error in your script
Just like Luiz mention, change "fieldID" to "fieldId"
there is a typo in line 30, "to1talPremium" I believe is "totalPremium"
currentRecord.setValue function should follow with 2 argument {fieldId: '', value: ''}
currentRecord.setValue(
{
fieldId: 'custrecord_am_ehir_emp_month_prem', employeePremium
});
This code will not work if you using SuiteScript 2.0
try this
currentRecord.setValue({
fieldId: 'custrecord_am_ehir_emp_month_prem',
value: employeePremium
});
Let me know if you have more question.

I think code should ↓
/**
*#NApiVersion 2.x
*#NScriptType ClientScript
*/
define(['N/currentRecord'],
function(currentRecord){
function fieldChanged(context) {}
return {fieldChanged:fieldChanged}
})

Your code had a few issues but the important one that caused Module Loader Error was
You need to have curly-braces for multi-line scripts as follows
else {
//get premium and percent values
var totalPremium = currentRecord.getValue({
fieldID: 'custrecord_am_ehir_total_month_prem'
});
var employeeOnlyPremium = currentRecord.getValue({
fieldID: 'custrecord_am_ehir_emp_only_prem'
});
var employeePercent = currentRecord.getValue({
fieldID: 'custrecord_am_ehir_emp_prem_percent'
});
var dependentPercent = currentRecord.getValue({
fieldID: 'custrecord_am_ehir_dep_prem_percent'
});
var employeePremium = totalPremium * employeePercent;
var dependentPremium = (to1talPremium - employeeOnlyPremium) * dependentPercent;
var companyPremium = totalPremium - employeePremium - dependentPremium;
//set field values
currentRecord.setValue({
fieldID: 'custrecord_am_ehir_emp_month_prem', employeePremium
});
currentRecord.setValue({
fieldID: 'custrecord_am_ehir_dep_month_prem', dependentPremium
});
currentRecord.setValue({
fieldID: 'custrecord_am_ehir_co_month_prem', companyPremium
});
}
It is fieldId and not fieldID or fieldid.
eg.
var totalPremium = currentRecord.getValue({
fieldId: 'custrecord_am_ehir_total_month_prem'
});
To set a value using SS2.0 you need to pass object containing 2 properties fieldId and value.
So, to set a value you need to do the following.
currentRecord.setValue({
fieldId:'custrecord_am_ehir_emp_month_prem',
value: employeePremium
});
For further readings, you can refer to Record Module in NetSuite Help

Related

SuiteScript Workflow Action-how to add error handling

I have a workflow action script that is supposed to search for a string in an email message body (the string being for the document number--this is stored in a field with the id 'custevent_case_creation') and return the transaction record id.
The script:
/**
*#NApiVersion 2.x
*#NScriptType WorkflowActionScript
* #param {Object} context
*/
define(["N/search", "N/record"], function (search, record) {
function onAction(context) {
var recordObj = context.newRecord;
var oc_number = recordObj.getValue({ fieldId: "custevent_case_creation" });
var s = search
.create({
type: "salesorder",
filters: [
search.createFilter({
name: "tranid",
operator: search.Operator.IS,
values: [oc_number],
}),
],
columns: ["internalid"],
})
.run()
.getRange({
start: 0,
end: 1,
});
log.debug("result set", s[0].id);
return s[0].id;
}
return {
onAction: onAction,
};
});
This works as expected when there is a valid document number used in the email message.
However, there are two scenarios where that won't be the case:
there is no document number referenced in the original email (and therefore, the field "custevent_case_creation" will be blank)
the document number referenced is incorrect and there is no transaction with that document number in the system
I am trying to add some form of error handling to deal with these two scenarios though I can't find anything that works. Where should the error handling be in this script?
Should it be an if/else statement?
So far I have tried:
adding if{s.length>0);
adding a condition in the workflow itself so that the custom action from the workflow action script doesn't occur if the field for custevent_case_creation is blank
-
The error message I am getting is:
org.mozilla.javascript.EcmaError: TypeError: Cannot read property "id" from undefined (/SuiteScripts/sdf_ignore/Workflow Action Lookup SO.js#41)
EDIT:
The working code
/**
*#NApiVersion 2.x
*#NScriptType WorkflowActionScript
* #param {Object} context
*/
define(["N/search", "N/record"], function (search, record) {
function onAction(context) {
try {
var recordObj = context.newRecord;
var oc_number = recordObj.getValue({
fieldId: "custevent_case_creation",
});
var s = search
.create({
type: "salesorder",
filters: [
search.createFilter({
name: "tranid",
operator: search.Operator.IS,
values: [oc_number],
}),
],
columns: ["internalid"],
})
.run()
.getRange({
start: 0,
end: 1,
});
log.debug("result set", s[0].id);
return s[0].id;
} catch (error) {
log.debug(
error.name,
"recordObjId: " +
recordObj.id +
", oc_number:" +
oc_number +
", message: " +
error.message
);
}
}
return {
onAction: onAction,
};
});
Try wrapping the contents of you onAction function with try/catch. More info on try/catch can be found here on W3Schools.
try {
//your working code for onAction function
var recordObj = context.newRecord;
var oc_number = recordObj.getValue({ fieldId: "custevent_case_creation" });
var s = search.create({
type: "salesorder",
filters: [
search.createFilter({
name: "tranid",
operator: search.Operator.IS,
values: [oc_number]
})
],
columns: ["internalid"]
})run().getRange({
start: 0,
end: 1,
});
log.debug("result set", s[0].id);
return s[0].id;
} catch(e){
log.debug(e.name,'recordObjId: '+ recordObj.id +', oc_number:'+ oc_number +', message: ' + e.message); //if e.name is empty try e.title
//you can add additional steps here if desired, i.e. send an email, display an alert, etc.
}

Why is datatables concatenating data?

I have the following code:
var {$js_key} = this.api().columns($i);
var {$js_key}_select = $('<select><option value="">$please</option></select>')
.appendTo($appendTo)
.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
{$js_key}.search( val ? '^'+val+'$' : '', true, false ).draw();
});
{$js_key}.data().each(function(d,j){
alert(d);
})
d should clearly be each instance of the data. Instead I'm getting:
Yes,No,No,No,No,No,No,No. What have I done wrong? I should be able to output each option and fyi this is the whole value of the Select box so is not just an issue with alert/outputting.
I'm using v 1.10.12 and its jquery.datatables.
Ok so after further investigations - this was because I was using the columns() function and should have used column()!!
https://datatables.net/reference/api/column()
Hope that helps anyone else.

How to omit fields when serializing Mongoose models in MEAN [duplicate]

I have the following simple shema:
var userSchema = new Schema({
name : String,
age: Number,
_creator: Schema.ObjectId
});
var User = mongoose.model('User',userSchema);
What I want to do is create the new document and return to client, but I want to exclude the 'creator' field from one:
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
res.json(200, {user: user}); // how to exclude the _creator field?
});
});
At the end I want to send the new created user without _creator field:
{
name: 'John',
age: 45
}
Is it possible to make without extra find request to mongoose?
P.S:It's preferable to make it by
Another way to handle this on the schema level is to override toJSON for the model.
UserSchema.methods.toJSON = function() {
var obj = this.toObject()
delete obj.passwordHash
return obj
}
I came across this question looking for a way to exclude password hash from the json i served to the client, and select: false broke my verifyPassword function because it didn't retrieve the value from the database at all.
The documented way is
UserSchema.set('toJSON', {
transform: function(doc, ret, options) {
delete ret.password;
return ret;
}
});
UPDATE - You might want to use a white list:
UserSchema.set('toJSON', {
transform: function(doc, ret, options) {
var retJson = {
email: ret.email,
registered: ret.registered,
modified: ret.modified
};
return retJson;
}
});
Come across your question when I was trying to find a similar answer with pymongo. It turns out that in mongo shell, with the find() function call, you can pass a second parameter which specifies how the result document looks like. When you pass a dictionary with attribute's value being 0, you are excluding this field in all the document that come out of this query.
In your case, for example, the query will be like:
db.user.find({an_attr: a_value}, {_creator: 0});
It will exclude _creator parameter for you.
In pymongo, the find() function is pretty much the same. Not sure how it translate to mongoose though. I think it's a better solution compare to manually delete the fields afterwards.
Hope it helps.
I would use the lodash utilities .pick() or .omit()
var _ = require('lodash');
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
// Only get name and age properties
var userFiltered = _.pick(user.toObject(), ['name', 'age']);
res.json(200, {user: user});
});
});
The other example would be:
var _ = require('lodash');
app.post('/example.json', function (req, res) {
var user = new User({name: 'John', age: 45, _creator: 'some ObjectId'});
user.save(function (err) {
if (err) throw err;
// Remove _creator property
var userFiltered = _.omit(user.toObject(), ['_creator']);
res.json(200, {user: user});
});
});
You can call toObject() on the document to convert it to a plain JS object that you can freely modify:
user = user.toObject();
delete user._creator;
res.json(200, {user: user});
By following the MongoDB documentation, you can exclude fields by passing a second parameter to your query like:
User.find({_id: req.user.id}, {password: 0})
.then(users => {
res.status(STATUS_OK).json(users);
})
.catch(error => res.status(STATUS_NOT_FOUND).json({error: error}));
In this case, password will be excluded from the query.
font: https://docs.mongodb.com/v2.8/tutorial/project-fields-from-query-results/#return-all-but-the-excluded-field
I am using Mongoosemask and am very happy with it.
It does support hiding and exposing properties with other names based on your need
https://github.com/mccormicka/mongoosemask
var maskedModel = mongomask.mask(model, ['name', 'age']); //And you are done.
You can do this on the schema file itself.
// user.js
var userSchema = new Schema({
name : String,
age: Number,
_creator: Schema.ObjectId
});
userSchema.statics.toClientObject = function (user) {
const userObject = user?.toObject();
// Include fields that you want to send
const clientObject = {
name: userObject.name,
age: userObject.age,
};
return clientObject;
};
var User = mongoose.model('User',userSchema);
Now, in the controller method where you are responding back to the client, do the following
return res.json({
user: User.toClientObject(YOUR_ENTIRE_USER_DOC),
});

dojo xmlstore and data grid item count

I ahve an xml store that calls an url and fetch data from database. It has to be displayed in the data grid when there is data returned from the database. When there is no data, it has to show appropriate error message.
I have the following js file.
require(["dojo/date/locale","dojox/grid/DataGrid","dojox/data/XmlStore","dijit/registry", "dojo/fx","dijit/form/ValidationTextBox", "dojo/dom-form", "dojo/dom", "dojo/on", "dojo/request","dojox/xml/parser", "dojo/ready","dojo/domReady!"],
function(locale,DataGrid,XmlStore,registry,coreFx,dijit, domForm, dom, on, request, parser, ready){
var format;
var siteId;
var phoneNum;
var grid;
var dataGrid=new DataGrid({
autoWidth:true,
autoHeight:true,
clientSort:true,
structure: [
{name:"Order ID", field:"orderId"},
{name:"Sender", field:"senderName"},
{name:"Recipient", field:"recipientName"},
{name:"Phone Number", field:"phone"},
{name:"Gift Amount", field:"amount"}
]
},"showGrid");
dataGrid.startup();
on(dom.byId("submitButton"), "click", function(){
ready(function()
{
submitValue();
});
});
on(dom.byId("printGiftcard"), "click", function(){
ready(function()
{
window.print();
});
});
function submitValue(){
grid=registry.byId("showGrid");
grid.set("store", null);
grid.filter();
document.getElementById("outcomeMessage").innerHTML="";
var orderNumber= document.getElementById("orderNumber");
var num=orderNumber.value;
if(num==""){
document.getElementById("outcomeMessage").innerHTML="Please enter Order number";
return;
}
var myStore= new XmlStore({
url:"/hello/"+num,
urlPreventCache : false,
query:{},
queryOptions:{},
onComplete:sizeCount
});
var sizeCount = function(items,request){
console.log(items.length);
if(items.length == 0){
document.getElementById("outcomeMessage").innerHTML="data not found";
}
}
var request = myStore.fetch({query:{},queryOptions:{},onComplete:sizeCount});
grid=registry.byId("showGrid");
grid.set("store", myStore);
//grid.filter();
}
});
The problem is it is calling database twice now in order to check the number of items returned.Once to set the store for the grid and other to check if the data returned is null.Can someone give me a simplified solution for this.
Thanks
I finally resolved my issue.
dojo.connect(dataGrid,"_onFetchComplete",function(items){
console.log(datagrid.rowCount);
}
})
Thanks!

Is it possible to filter data in a dgrid like you can in a datagrid? If so, how?

I'm relatively new to dojo and have seen how datagrid offers a dynamic filtering capability that reduces the visible rows based on what you type into a filter text input. I have not found any examples of how to do it with the dgrid. If it can be done, please provide an example or point me to a resource that offers a tutorial or example. Thanks!
Yes, it is possible. Use dgrid/OnDemandGrid and define query function that will return true or false based on your logic for each row in dojo/store powering the grid.
I prepared an example to play with at jsFiddle: http://jsfiddle.net/phusick/7gnFd/, so I do not have to explain too much:
The Query Function:
var filterQuery = function(item, index, items) {
var filterString = filter ? filter.get("value") + "" : "";
// early exists
if (filterString.length < 2) return true;
if (!item.Name) return false;
// compare
var name = (item.Name + "").toLowerCase();
if (~name.indexOf(filterString.toLowerCase())) { return true;}
return false;
};
The Grid:
var grid = new Grid({
store: store,
query: filterQuery, // <== the query function for filtering
columns: {
Name: "Name",
Year: "Year",
Artist: "Artist",
Album: "Album",
Genre: "Genre"
}
}, "grid");
I know this isn't the answer to the question asked, and the answer provided is masterful and we use it quite a bit.
However, this functionality doesn't seem to work well at all if you're using a TreeGrid (columns with the "dgrid/tree" plugin). I've written some code to simulate the same behavior as the accepted answer with a tree grid. It's basically just looping through the items in the store and hiding any row elements that don't match whatever condition you set forth. Thought I would share it in case it helps anybody. It's rather ugly and I'm sure it can be improved upon, but it works.
It basically uses the same concept as phusick's answer. You need to watch a value on a TextBox, but instead of refreshing the grid you have it call a function:
textBox.watch("value", lang.hitch(this, function() {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
};
timeoutId = setTimeout(lang.hitch(this, function() {
this.filterGridByName(textBox.get('value'), myGrid);
}, 300));
}));
And here's the function:
filterGridByName: function(name, grid){
try {
for (var j in grid.store.data){
var dataItem = grid.store.data[j];
var childrenLength = dataItem.children.length;
var childrenHiddenCount = 0;
var parentRow = grid.row(dataItem.id);
for (var k in dataItem.children){
var row = grid.row(dataItem.children[k].id);
var found = false;
if (dataItem.children[k].name.toLowerCase().indexOf(name.toLowerCase()) != -1){
found = true;
}
if (found){
if (row.element){
domStyle.set(row.element, "display", "block");
}
if (parentRow.element){
domStyle.set(parentRow.element, "display", "block");
}
} else {
childrenHiddenCount++;
// programmatically uncheck any hidden item so hidden items
for (var m in grid.dirty){
if (m === dataItem.children[k].id && grid.dirty[m].selected){
grid.dirty[m].selected = false;
}
}
if (row.element){
domStyle.set(row.element, "display", "none");
}
}
}
// if all of the children were hidden, hide the parent too
if (childrenLength === childrenHiddenCount){
domStyle.set(parentRow.element, "display", "none");
}
}
} catch (err){
console.info("error: ", err);
}
}