SuiteScript auto-populate line item fields from header fields - suitescript

I am trying to have the class field for each line item on a Sales Order be automatically populated to match the class field set on the header level of that Sales Order. I tried following the article "SuiteScript Auto Populate Department Line Item Fields" and making some adjustments, but it does not populate the class field for each line item. I am using a User Event script and trying to populate Before Submit. Here is the code I am using:
function onBeforeSubmit(type) {
if (type == 'create' || type =='edit'){
var itemClass = nlapiGetFieldValue('class');
var itemCount = nlapiGetLineItemCount('item');
for (var i = 1; i <= itemCount; i++) {
nlapiSetLineItemValue('item', 'class', itemClass);
}
}
}

nlapiSetLineItemValue('item', 'class', itemClass)
is missing a parameter for the line number. This should be the correct API call
nlapiSetLineItemValue('item', 'class',i, itemClass)

This worked as user event script.
function onBeforeSubmit(type) {
if (type == 'create' || type =='edit'){
var itemClass = nlapiGetFieldValue('class');
var itemCount = nlapiGetLineItemCount('item');
for (var i = 1; i <= itemCount; i++) {
nlapiSetLineItemValue('item', 'class', i, itemClass);
}
}

Related

How to browse to the next page in a datasource that is loaded into table in Google AppMaker

I'm working on a requirement where I have a datasource named 'emailSearchResults' where I search for email messages metadata and load the results in the datasource.
The fields in the datasource are not relevant, however I set the datasource to have 50 records per page as per the below screenshot:
The script I used to load the datasource is shown in the query field, that call the following script:
function getMessageDetails(userId, msgID)
{
var messageDetails = [];
var messageData;
var msgID_,subject_,from_,date_;
messageData=Gmail.Users.Messages.get(userId,msgID,{format:"metadata", metadataHeaders:["Message-ID", "Subject", "From", "Date"]});
console.log(messageData.payload.headers);
//console.log(msgID);
//console.log(messageData.payload.headers[3].value);
date_="<na>";
from_="<na>";
subject_="<na>";
msgID_="<na>";
for (var counter =0;counter<4;counter++)
{
if (messageData.payload.headers[counter].name=="Message-ID")
{
msgID_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="Subject")
{
subject_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="From")
{
from_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="Date")
{
date_=messageData.payload.headers[counter].value;
}
}
messageDetails.push(date_);
messageDetails.push(from_);
messageDetails.push(subject_);
messageDetails.push(msgID_);
return messageDetails;
}
function searchMessages(userId,condition)
{
//
// first we build the conditions
// we can make it fixed
// or we can make it dynamic
var searchResult;
var deleteResult;
var currentMessage;
var results = [];
var pageToken;
var params = {};
var _stat;
var options = {
includeSpamTrash: "true",
pageToken: pageToken
};
var msgRecord = [];
do
{
searchResult=Gmail.Users.Messages.list(userId,options);
for (var i = 0; i < searchResult.messages.length; i++)
{
var record=app.models.emailSearchResults.newRecord();
msgRecord=getMessageDetails(userId,searchResult.messages[i].id);
record.msgMainID=searchResult.messages[i].id;
record.msgID=msgRecord[3];
record.subject=msgRecord[2];
record.senderAddress=msgRecord[1];
record.msgDate=msgRecord[0];
/*console.log(searchResult.messages[i].id);
console.log(msgRecord[3]);
console.log(msgRecord[2]);
console.log(msgRecord[1]);
console.log(msgRecord[0]);
return;*/
results.push(record);
msgRecord=null;
}
if (searchResult.nextPageToken) {
options.pageToken = searchResult.nextPageToken;
}
} while (searchResult.pageToken);
searchResult=null;
return results;
}
On the main page I put a table and linked it to the datasource, and I enabled pagination on the table, so I get the pager buttons at the bottom of the table as below:
When I execute the app and the datasource is filled, I see the first page results in a correct way, however when I want to move to the next page, I click the next page button and once the loading is complete I find out that I still see the same results from the first page on the table.
I am not familiar with how to make the table show the results of the second page then the third page, and I am going in circles on this...
Hope the explanation is clear and addresses the issue..
I would really appreciate any help on this!
Regards
Currently pagination isn't working as expected with calculated datasources. You can, however, build your own. There are several changes you'll need to make to accomplish this. First you'll want to refactor your searchMessages function to something like this:
function searchMessages(userId, pageToken){
var results = [];
var options = {
includeSpamTrash: "true",
pageToken: pageToken,
maxResults: 50
};
var searchResult = Gmail.Users.Messages.list(userId, options);
for (var i = 0; i < searchResult.messages.length; i++){
var record = app.models.emailSearchResults.newRecord();
var msgRecord = getMessageDetails(userId,searchResult.messages[i].id);
record.msgMainID = searchResult.messages[i].id;
record.msgID = msgRecord[3];
record.subject = msgRecord[2];
record.senderAddress = msgRecord[1];
record.msgDate = msgRecord[0];
results.push(record);
}
return {records: results, nextPageToken: searchResult.nextPageToken};
}
Then you'll want to change your datasource query. You'll need to add a number parameter called page.
var cache = CacheService.getUserCache();
var page = query.parameters.page || 1;
var pageToken;
if(page > 1){
pageToken = cache.get('pageToken' + page.toString());
}
var results = searchMessages('me', pageToken);
var nextPage = (page + 1).toString();
cache.put('pageToken' + nextPage, results.nextPageToken);
return results.records;
You'll need to modify the pagination widget's various attributes. Here are the previous/next click functions:
Previous:
widget.datasource.query.pageIndex--;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();
Next:
widget.datasource.query.pageIndex++;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();
You should be able to take it from there.

places api Unable to get property 'address_components' of undefined or null reference

working with the google places api and cannot figure why autocomplete is returning undefined here on call to get places.
what developer tools shows is.
address_components is what should be returned on a call to autocomplete.getPlace
Unable to get property 'address_components' of undefined or null reference
function initAutoCompleteDynamic() {
var slideID = 99;
var idx = 99 - slideID;
var propcount = 5;
for (var i = 0; i < propcount; i++) {
var propaddress = "prop1address" + i;
var autocomplete = autocomplete + i;
autocomplete = new google.maps.places.Autocomplete(
document.getElementById(propaddress)),
{ types: ['geocode'] };
autocomplete.addListener('place_changed', fillinAddressDynamic);
}
}
and in fillinAddressDynamic
var place=autocomplete.getPlace():
for (var i = 0; i < place.address_components.length; i++) {
alert("i am in the loop");
var addressType = place.address_components[i].types[0];
var field = addressType;
var completeaddress1 = '';
var propaddress = 'prop1address' + i;
var strnum = 'streetnumber' + i;
CR(i);//calling component resolver.
if (componentFormProduction[addressType]) {
var val = place.address_components[i][componentFormProduction[addressType]];
document.getElementById(CR[addressType]).value = val;
if (field == "street_number") {
var streetnum = document.getElementById(strnum).value = val;
}
if (field == "route") {
if (streetnum) {
completeaddress1 = streetnum + ' ' + val;
}
else {
completeaddress1 = val;
}
document.getElementById('prop1address0').value = completeaddress1;
}
}
}
This would happen if the user (or you) hits Enter without clicking on a suggestion.
Typically the sequence of event is like this:
user enters input
JavaScript queries Autocomplete for suggestions
user clicks on a suggestion
JavaScript queries Details, replaces user input with Details responses' fields (incl. address_components) and fires the places_changed event
handler for places_changed will obtain the Place object from Details response by calling getPlace()
However, it may also be like this:
user enters input
JavaScript queries Autocomplete for suggestions
user disregards suggestions and hits Enter without clicking on one
JavaScript fires the places_changed event without querying Details or modifying user input
handler for places_changed calls getPlace() and gets a nearly empty Place object, with only the name field containing the raw user input.
It is for you to decide what to do with raw user input, here are some examples:
This tool uses the JavaScript Geocoding service to search for that input:
https://google-developers.appspot.com/maps/documentation/utils/geocoder/
This example (address form) does nothing with it:
https://google-developers.appspot.com/maps/documentation/javascript/examples/places-autocomplete-addressform
This (very basic) example will show an error message reporting no details:
https://google-developers.appspot.com/maps/documentation/javascript/examples/full/places-autocomplete

Meteor collection insert from input element

This code is trying to insert the data from input elements on the page into a Meteor Collection Task1
I am getting "App is crashing error" because of the Tasks1.insert line. Why and how can I fix it?
I need to get the element name and value as the key:value pair for the Document being inserted. Thanks
Template.footer.events({
'click button': function () {
if ( this.text === "SUBMIT" ) {
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
Tasks1.insert({inputs[i].name: inputs[i].value});
}
}
}
});
inputs[i].name cannot be used as a key of an object literal, because it's a variable and we can only use strings for defining properties in an object literal.
Like this it should work (it's the most common workaround):
for (var i = 0; i < inputs.length; i++) {
// First define a variable
var params = {};
// Then you can use a variable (or a function) to set the key
params[inputs[i].name] = inputs[i].value;
Tasks1.insert(params);
}

How can you force an ASP.Net GridView to display an EmptyDataTemplate given there's only a single data record with all blanks?

My stored procedure, instead of returning zero rows, returns one with most of the columns NULL. When my .Net code sees such data, I wish to force it to display the EmptyDataTemplate. How?
Thanks Win,
In the LinqDataSource Selecting event handler I check if the data source has a size of one and has a null value for one of the key fields and then I pass in this to the LinqDataSourceSelectEventArgs' Result:
using (var dataContext = new WebDataContext())
{
var report = from row in dataContext.GetReport()
select new Report()
{
AccountCode = row.AccountCode //,
//...
}
}
if (report.Count() == 1 && report.ToList()[0].AccountCode == null)
{
var emptyReport = report.ToList();
report.Clear();
e.Result = emptyReport;
}
else
{
//...
e.Result = matrixReport;
//...
}

write condition statements in a sharepoint SPListItemCollection before binding the method to asp.net repeater

My situation is like this:
I have a function that returns a value as SPListItemCollection and I bind this function to a repeater.
My problem is how can I do some conditional formatting before the return value?
SPListItemCollection GetListItems()
{
SPWeb curWeb = SPContext.Current.Site.RootWeb;
string siteUrl = SPContext.Current.Web.Url;
SPListItemCollection curItems = GetDep(ListName, department);
// write condition here so that it checks if the item count is higher or
//lower than a specified number.
return curItems;
}
thank you for your help.
Im not 100% sure what you want to do before the return. If you only want to check if the resultItem.Count is bigger then 100 for example, you can do this:
SPListItemCollection GetListItems()
{
SPWeb curWeb = SPContext.Current.Site.RootWeb;
string siteUrl = SPContext.Current.Web.Url;
SPListItemCollection curItems = GetDep(ListName, department);
if (curItems.Count > 100)
{
// change the items or do whatever you want. after that, return:
foreach(SPListItem item in curItems)
{
//format/change
}
return curItems;
}
// return, without any changes
return curItems;
}
Try smth like
SPListItemCollection GetListItems()
{
SPWeb curWeb = SPContext.Current.Site.RootWeb;
string siteUrl = SPContext.Current.Web.Url;
SPListItemCollection curItems = GetDep(ListName, department);
var itemsForDepartment = curItems.GetDataTable().Rows.Where(r => r["Department"] == department); // you can try to do this is caml too
if(itemsForDepartment.Count > itemCount) {
// insert the "show me more" link
}
var itemsForDepartment = itemsForDepartment.Take(itemCount);
// bind itemsForDepartment to a Repeater
return curItems;
}
I have not compiled this code so you will have to correct some syntax mistakes ;)

Resources