Showing posts with label SuiteScript. Show all posts
Showing posts with label SuiteScript. Show all posts

Wednesday, August 31, 2011

NetSuite Fact 1: nlapiSubmitField() doesn't work on ALL fields

We've MOVED!!!! www.codeboxllc.com/ksc


Five days ago, I was inspired by the growing list of cases currently assigned to me. Did I say inspired? I meant to say annoyed. There was one case in particular that was marked urgent and needed to be done by the end of the month. (That was five days ago)

It was a simple task yet so important. Update Department and Class field on Transaction records; specifically Sales Order, Cash Sales and Invoices.

Obvious weapon of choice was Scheduled Job and this was the task that helped me realize the power of Script Parameter. My choice for SuiteScript API function to update these two fields was nlapiSubmitField(). Why? It costs less (About 20 Governance to load and submit vs 10 to update fields).

I finished my coding in approximately 45 mins. Felt proud and clever so I gave myself a pad on the back. I began testing my code and something odd occurred. Even after nlapiSubmitField was called, my fields weren't updated!

I thought it was a defect so I tried using the function against other fields such as custom fields and native fields. It worked just fine. It JUST didn't work for Department and Class fields on Transaction record types.

This was my code:
var flds=['department','class'];
var vals=[19,51]; //internal ID of department and class
var rectype='salesorder';
var recid=555; //internal ID of sales order record
nlapiSubmitField(rectype, recid, flds,vals);
After testing out the function against other native records such as Customer record type, I called NetSuite Support and asked about it.  The support rep. told me that there is an existing defect out there for nlapiSubmitField API call in v2011.2. The problem was, I WASN'T!

I get a response from Support Rep the next day saying this:
Upon further investigation, it appears that the Department and Class fields in the Sales order record are both "non-direct list editable", the nlapiSubmitField in this case behaves as designed. The nlapiSubmitField function will only work for fields which can be Direct List Edited. You can see this on the help guide. Here is the path: SuiteFlex (Customization, Scripting, and WebServices) > SuiteScript > Scripting Records, Fields, Forms, and Sublists > Direct List Editing and SuiteScript > Direct List Editing Using nlapiSubmitField
My problem with this response from the support rep. is that no where on that Help section does it say that Department and Class fields are categorized as None-Direct list editable.

However, if you go to SuiteFlex (Customization, Scripting, and Web Services) : SuiteScript : Scripting Records, Fields, Forms, and Sublists : Direct List Editing and SuiteScript : Direct List Editing and SuiteScript Overview it DOES state this:
In SuiteScript, you cannot direct list edit select fields. In other words, you cannot call nlapiSubmitField on a select field.
If you look at Department and Class field in SuiteScript Recrods Browser both are indeed labeled as select fields.  What's MORE interesting is that I have used nlapiSubmitField function to set select fields!!!!!!!!!

If you are having this problem, you are not the only one. If you want to set Department and Class fields on a transaction record such as Sales Order, you will need to do it the old fashion way:
var soid='123';
var deptid='19';
var clsid='51';
var so=nlapiLoadRecord(rectype, trid);
so.setFieldValue('department',deptid);
so.setFieldValue('class',clsid);
nlapiSubmitRecord(so);
My thought is NetSuite should update their documentation to provide Non-Direct editable fields list.

Saturday, August 27, 2011

Script Parameters: Where have you been all my life??

We've MOVED!!!! www.codeboxllc.com/ksc

Ok. perhaps script parameters been around for a while. I just failed to see the usefulness of it. You can read all about script parameters by going to NetSuite Help > SuiteFlex > SuiteScript > Creating Script Parameters (Custom Fields)

While back, I had one of NetSuite Custom Script guy review my codes. I asked him, "Please, imagine you are paying me to do your work and you are doing a code review of my work. Just rip it part and be very critical".
And he did just that. One of the suggestion he gave me was to utilize Script Parameters to turn my scripts into "Configurable" script.

What does configuration give you? Re-usability. As you see your script library grow, re-usability plays very important role in keeping your NetSuite account clean and organized.

Think of following situations where you can use power of configuration
1. Script that applies to multiple entity record types that sets same fields depending on the situation:
- You could hard code multiple entity  record types in to the script but that's not scalable. If you end up wanting to add new record, you need update the script and deploy.

- An alternative would be to create one script that takes record types as a parameter and DEPLOY it multiple times. It can easily be extended out to other entity record types by creating another deployment of the script with value of parameter as records internal id.

2. Script that takes different saved searches but ultimately does same thing for each records:
- You could hard code different types of saved searches but again, how scalable is that?

- An alternative would be to create one script that takes internal id of a saved search and DEPLOY it multiple times.

I think you are starting to see the trend here. Whats really cool about script parameter is that it can be text field, drop down list or a check box. Why is this cool? It's easy to set the parameters. Typing in internal ID might not be too user friendly but what if you want to set list of items, departments, or custom record as your parameter? Instead of looking up the internal ID of those records, you simply set it. EASY RIGHT!!!!

Keep in mind, if you want to set custom parameter specific for your script, you leave the Preference as blank.
You have two other options for this preference; Company and User. You can see full details by going to NetSuite Help > SuiteFlex > SuiteScript > Setting Script Parameter Preferences


You create your parameter(s) during your script creation stage. You set values for those parameters when you deploy your script. 

ID of your custom parameter starts with custscript prefix. Once you know what your ID is going to be, you can gain access to it with following code:
nlapiGetContext().getSetting('SCRIPT','YOUR CUSTOM FIELD ID');
On my screen shot above, I named my parameter _testparam. Full sample code will look like this:

 nlapiGetContext().getSetting('SCRIPT','custscript_testparam');
I can't wait to go back and rewrite all my scripts. Happy coding everyone!




Monday, August 8, 2011

Scriptable Cart - Full Sample By Jason K

We've MOVED!!!! www.codeboxllc.com/ksc

Hey Guys. I've been meaning to post this up but lost track of time due to extermination work I've been doing.
Couple months ago, I've worked with Jason K from NetSuite to trouble shoot remove/add issues I was having with my particular scriptable cart process. What this code is SUPPOSED to do:
When an item is added with certain country, it pro grammatically adds country specific surcharge item to the cart. In increments existing surcharge item in the cart if it already exists, it adds new country item if it doesn't exists. Removing parent item will also either increments or decrements the surcharge item.
I have not tried out his code personally but he assures me that it worked for him when he was fully testing out the process in his environment.

I'm hoping this will help in your effort to implement Webstore Scriptable Cart/Checkout form:


/*
Summary:  A custom item option is attached to a certificate which allows the shopper to choose a country.
When the shopper does this, a surcharge will be added to the cart based on the country chosen.  The shopper
can also add another certificate to the cart with a different country and there will be a separate line item
for each surcharge for each country.


This script also syncs up quantities for each cert-country combination.  For example, if the shopper increments,
decrements, or adds another Canada certificate to the cart, the quantity of the canadian surcharge will follow
that quantity.  This will NOT affect the quantity of other surcharges that are not the same country.


Finally, when a certificate is removed from the cart, the associated surcharge is also removed.


There are two customizations that were done to the sales order to support this script:


1) a new custom body field "custbody_processing", a text field, was added to ensure that no infinite looping
is seen.


2) a new custom body field "custbody_deletedcountry", a text field, is added and used by the validateDelete
event. The problem with recalc during a deletion is that we don't know what was deleted.  But, in our
custom validateDelete, if a cert was deleted, we save the cert's country in this custom field.  Then, during
recalc, we can just look up what surcharge needs to be removed and remove it.


There are also a couple of utility functions included below, including safeSelectNewLineItem and safeSelectLineItem.
In some cases, I've noticed that selectNewLineItem and selectLineItem throws an error if the script left the current
item row in an uncommitted state.  Using these functions will ensure that a commit will be done if need be before
a new row is selected.  The other functions should be self-explanatory.


*/
var certId = "74"; // ID of the general certificate, will including an item option custcol_certcountry
var certCountry = "custcol_certcountry"; // name of the custom column


// Map to define what surcharge item ID belongs to which country.
// In this case, I've only set up two countries along with two non inventory items.
var surchargeMap = {"US":"76", "CA":"75"};


// In order to make things easier for us, we will track the type of cert
// that is deleted via a validateDelete.  Will get the country
function validateDelete(type)
{
if (type == 'item')
{
var itemId = nlapiGetCurrentLineItemValue('item','item');
if (itemId == certId)
{
// if we get here, we know a certificate is being deleted.  Store the country in our
// custom body field for use in recalc.
var country = nlapiGetCurrentLineItemValue('item', certCountry);
log('Item ID '+itemId+' being deleted for country '+country+' - storing this in custom field');
nlapiSetFieldValue('custbody_deletedcountry', country);
}
}


return true; // Always return either true or false during validation
}


function onRecalc(type, action)
{
if (type != 'item') { return; }


try
{
var processing = nlapiGetFieldValue('custbody_processing');
if (processing != null && processing == 'T')
{
// We are in a secondary recalc, so exit
return;
}


// If we've passed the previous check, we are in the first
// level of recalc, so set processing flag
nlapiSetFieldValue('custbody_processing', 'T');


if (action=='commit')
{
doCommit();
}


if (action=='remove')
{
doRemove();
}
}
catch (err)
{
log("General Error: "+err.message);
}
finally
{
// Now, even with an error, we want to reset the processing flag
// so use a finally-clause to ensure this happens no matter what
nlapiSetFieldValue('custbody_processing', 'F');
}
}




// Called when a commit is done for recalc
function doCommit()
{
var thisItem = nlapiGetCurrentLineItemValue('item','item');


// Ignore any add-to-carts that are not certifications
if (thisItem != certId) { return; }


var thisQty = nlapiGetCurrentLineItemValue('item','quantity');
log("Current qty of cert = "+thisQty);


var thisCountry = nlapiGetCurrentLineItemValue('item', certCountry);
log("Current country of cert: "+thisCountry);


var surchargeId = surchargeMap[thisCountry];


if (isEmpty(surchargeId))
{
log("No surcharge ID found for country "+thisCountry+" - skipping processing");
return;
}


var surchargeLine = findItem(surchargeId);


if (surchargeLine == -1)
{
// We need to add a surcharge here
log("surcharge not found - adding surcharge");
addItem(surchargeId, thisQty);
}
else
{
surchargeQty = nlapiGetLineItemValue('item', 'quantity', surchargeLine);
log("Surcharge found - current Surcharge qty "+surchargeQty);


if (surchargeQty != thisQty)
{
log("updating quantity of surcharge");
safeSelectLineItem(surchargeLine);
nlapiSetCurrentLineItemValue('item', 'quantity', thisQty);
nlapiCommitLineItem('item');
}
}
}


// Called when a remove is done for recalc.  We have tracked the country that was
// deleted in the custom field, so this should be straightforward.  If there's no
// value in the custom field, don't do anything.
function doRemove()
{
// First, we get the deleted country from custbody_deleteditem
var deletedCountry= nlapiGetFieldValue('custbody_deletedcountry');


// If it's empty, this means that the item that was deleted was not a cert, so ignore.
if (isEmpty(deletedCountry))
{
return;
}


// Start a try-block here so after the remove we are sure that custbody_deletedcountry
// is cleared out even during an error
try
{
log('Country '+deletedCountry+' has been deleted, finding related surcharge');


var surchargeId = surchargeMap[deletedCountry];
var surchargeLine = findItem(surchargeId);


// only delete if appropriate surcharge is found
if (surchargeLine > 0)
{
log('Surcharge item for country '+deletedCountry+' found on line '+surchargeLine+' - removing');
safeSelectLineItem(surchargeLine);
nlapiRemoveLineItem('item', surchargeLine);
}
}
finally
{
nlapiSetFieldValue('custbody_deletedcountry', '');
}
}


// This function adds the given item to the order
function addItem(itemID, qty)
{
safeSelectNewLineItem();
nlapiSetCurrentLineItemValue('item', 'item', itemID);
nlapiSetCurrentLineItemValue('item', 'quantity', qty);
nlapiCommitLineItem('item');
}




// Sometimes, a selectNewLineItem results in an error if there's uncommitted
// values in the item list.  This makes sure this does not happen.
function safeSelectNewLineItem()
{
if (notEmpty(nlapiGetCurrentLineItemValue('item','item')))
{
nlapiCommitLineItem('item');
}


nlapiSelectNewLineItem('item');
}


// Sometimes, a selectLineItem results in an error if there's uncommitted
// values in the item list.  This makes sure this does not happen.
function safeSelectLineItem(itemLine)
{
if (notEmpty(nlapiGetCurrentLineItemValue('item','item')))
{
nlapiCommitLineItem('item');
}


nlapiSelectLineItem('item', itemLine);
}


// General find function for the item list
function findItem(itemID)
{
var cnt = nlapiGetLineItemCount('item');
for (var i=1; i <= cnt; i++)
{
if (nlapiGetLineItemValue('item','item',i) == itemID)
{
return i;
}
}


return -1; // -1 means not found
}




function isEmpty(tmp)
{
return tmp == null || tmp == '';
}


function notEmpty(tmp)
{
return !isEmpty(tmp);
}




function log(msg)
{
alert(msg);
}


Wednesday, May 25, 2011

Getting Started with Pardot API in NetSuite

We've MOVED!!!! www.codeboxllc.com/ksc

Who is using Pardot for Email Marketing Automation? I don't directly work with Marketing Department to know ins and outs of Pardot but I do know it's pretty awesome email marketing automation tool. I've seen my Marketing department create very effective unmanned drip marketing campaign through Pardot's automation workflow. Like every online software though, it's not perfect. However for what it's used for, I think it's pretty great software.

They have API available so that other cloud based or home grown software can connect and integrate.

As a developer, what does Pardot API mean? It means more work ;) No, no, it actually means you can take your website to new level of integration. Automated drip campaign based on activity your website visitors are doing? Access prospects information such as past activities, scores and display different sales related result pages? Well, I'm sure your marketing department can come up with pretty fancy way of using it.

Let's start with the basics. Pardot's API is URL based. I found it pretty easy to use when integrating NetSuite and Pardot together. You can check out Pardots' API documentation.

I wrote about NetSuite - Pardot Integration before

Step 1: You need to be able to get Authenticated into Pardot.
Pardot API on Authentcation
Pardot URL: https://pi.pardot.com/api/login/version/3
Required Parameters: Email Address, Password, User Key
Request sent to Pardot using GET or POST method will return API Key if login was successful.
In NetSuite, you can use nlapiRequestURL() method to make a server call out to external webservices.
var loginUrl='https://pi.pardot.com/api/login/version/3?email=[pardotEmail]&password=[pardotPass]&user_key=[pardotKey]';
var authorizeResponse = nlapiRequestURL(loginUrl,null,null);
var xml=nlapiStringToXML(authorizeResponse.getBody());
Javascript variable xml will contain result xml from Pardot. If successful, it will contain API Key. If unsuccessful, it will contain error code.

Step 2: Use the API Key to perform actions against Pardot.
Once you have the API Key, you can perform actions against Pardot. User Key and API Key are fundamentally required parameters. Most of my actions were against Pardot prospects so below are my most widely used API URLs:
  • Prospect Search:
    https://pi.pardot.com/api/prospect/version/3/do/read/output/full&user_key=[x]&api_key=[x]...
  • Prospect Add:
    https://pi.pardot.com/api/prospect/version/3/do/create/output/full&user_key=[x]&api_key=[x]...
  • Prospect Update:
    https://pi.pardot.com/api/prospect/version/3/do/update/output/full&user_key=[x]&api_key=[x]...

You can get pretty creative once you know the basics of how to use Pardot API. As I mentioned before, if your company is using NetSuite along with Pardot, it'll be extremely useful to create Pardot related library script.

As I mentioned before, you can use Xpath to gain access to response XML from Pardot. With Pardot API, you can;
  • Create or Update Prospects
  • Search for existing Prospects
  • Add/Remove Prospects from Marketing Segmentations
  • Add/Remove Prospects from Marketing Campaigns
  • Access native and/or custom Pardot fields
I have one last thought. Both NetSuite and Pardot used together can be very powerful tool for your organization. If you lack in technical resources or you need to get something off the ground fast, do consider using external resources. One company in particular who's been great help is Audaxium. They specialize in MS Dynamics, Pardot and NetSuite integration. Understanding the integration points between the two system and know what it can and can not do is critical to your business.

Saturday, May 21, 2011

Helpful JavaScript functions you may want to include in your Library Script

We've MOVED!!!! www.codeboxllc.com/ksc

We all need help sometimes. For me, I am not ashamed to look for help on the NetSuite Forum. Through out my experience with NetSuite deployment and customizations, I've found following JavaScript functions to be extremely helpful and I hope it provides you with some help as well.

Contains function: I found this script from CSS-Tricks website.
It is most useful when you have array of objects, strings, numbers and you wish to check for existence of a value you pass it.
Array.prototype.contains = function(arg) {
  for (i in this) {
    if (this[i]==arg) return true;
  }
  return false;
};
Here is how you use it.
var myArray = new Array("123","555","888","999"); //internal id of items
var itm = nlapiGetCurrentLineItemValue('item','item'); //get item id of current line item
if (myArray.contains(itm)) {
  alert('This Item exists in the Array!');
}
It makes your code lot simpler and easy to read.

Empty filter value checker: While writing custom search, I came across some odd errors here and there. Turns out, when search filter value is null or empty, it throws an error. After reading documentation, it turns out that you have to use @NONE@ in place of empty or null value.
function emptyFilterCheck(_val) {
  if (_val) {
    return _val;
  } else {
    return '@NONE@';
  }
}
 Send Email Function: I'm sure most of you have this function separated out. This is my version of the send email. It takes 6 parameters. From ID, To ID, Subject, Message, Attach to Record ID, Record Type.
Script will attach email to a record if the value is passed in.
function sendNotificationEmails(fromId, toId, strSbj, strMsg, attachToRecId, recType) {
  //check for sandbox
  if (env == 'SANDBOX') {
    strSbj='[SANDBOX] - '+strSbj;
  }


  try {
    //attach this email to record if defined
    if (attachToRecId != null) {
      var rec = new Object();
      if (recType==null) {
        rec['entity']=attachToRecId;
      } else if (recType=='transaction' || recType=='activity') {
        rec[recType]=attachToRecId;
      } else {
        //This is custom record
        nlapiLogExecution('DEBUG','msg','This is custom record:');
        rec['recordtype']=recType;
        rec['record']=attachToRecId;
      }
      nlapiSendEmail(fromId, toId, strSbj, strMsg, null, null, rec);
    } else {
      nlapiSendEmail(fromId, toId, strSbj, strMsg);
    }
    return true;
  } catch(e) {
    if (e instanceof nlobjError) {
      //Do your error handling here for e.getCode()and e.getDetails()
    } else {
      //Do your error handling for JavaScript issue: e.toString()
    }
  }
}
There are few others I'm trying to put it. Just to give you an idea, here are list of potential helper functions I am creating:

  • Search function which takes array of filter fields, values, and records' internal ID.
    I found myself writing these codes over and over again.
  • Specialized Pardot API library sets.
    If you use Pardot along with NetSuite, it's a good idea to create common function calls to Pardot. For example, LookupProspect(email), AddOrUpdProspect(email, JSONfldValObj), UpdProspectList(email, newList), UpdProspectCamp(email, newCampaign), GetActivities(email) just to name a few.
    I plan to write some sample Pardot API calls from NetSuite that I've written later.
  • Sublist related functions. 
What are some of your helper functions you are using?

Thursday, May 19, 2011

Working with Scriptable Cart in NetSuite Webstore - Lessons Learned

We've MOVED!!!! www.codeboxllc.com/ksc

It's been a while since my last post. I have a good reason. I've been struggling with Scriptable Cart feature in NetSuite advanced Webstore. After close to 9 days of none stop work, I think I've finally have it working.

This is new feature NetSuite released and it's still in an infant stage yet very powerful when coded correctly.
First thing I struggled with the most was not being able to see scripts' behavior when executed from the Webstore. You can read about on "How to debug NetSuite Webstore Scriptable Cart".

This gave me some major insight as to how NetSuite Webstore processes each addition/subtraction of items in the cart.

I want to give shout out to Jason K. for providing massive assistance in getting my cart script to work properly!

Here are some things I've found out that could help you:
  1. You can get execution environment variable using nlapiGetContext().getEnvironment() call. I didn't think this was possible but using this in your cart script actually returns SANDBOX, BETA or PRODUCTION from webstore.
     This will be very handy if you have to switch item ID depending on the environments.

  2. nlapiCommitLineItem('item') Is a MUST Call if you want your recalc to correctly recalculate totals. I tried taking the easy way out by not calling commit. What a newb mistake that was.

  3. nlapiLookupField() call can not be used. Obviously right? Well, I made this mistake as well. You may have an instance where you need to create item list table to add pro grammatically. I highly recommend using JSON object to create your item look up table.

  4. User selected items will ALWAYS be at line number 1 of the cart. The order of items may change after you've been to check out summary page but when it's added to the cart by the user; not script, it'll always be on the first line of item list.

  5. Jason K's trick 1: nlapiSelectLineItem results in an error if there's uncommitted values in the item list. He recommended to commit all items before adding new.
    I especially had issues with this. My work around was to use nlapiInsertLineItem with nlapiSetCurrentLinetItemValue method.

  6. Not sure if this will apply to everyone but IF you end up getting NetSuite Script Notice page during your execution of cart script or you end up getting Webstore maint. screen, it usually means there is an error in your script. For me, it was infinite loop issue. If you see your form re-initializing, it usually indicates error.

  7. Jason K's trick 2: Using global variable in the cart script sometimes fails. The workaround is to create custom body field on your form and use that as temporary global field that you set and get using nlapiGetFieldValue() call.
  8. Jason K's trick 3: When doing extra commit, always check for valid item in the current row. 
Some quick sample code from Jason K on safeSelectLine and safeSelectNewLine

** notEmpty is a custom function which simply checks to see if passed in value is null or empty string

safeSelectNewLine function:
function safeSelectNewLineItem() {
  if (notEmpty(nlapiGetCurrentLineItemValue('item','item'))) {
    nlapiCommitLineItem('item');
  }
  nlapiSelectNewLineItem('item');
}
safeSelectLine function:
function safeSelectLineItem(itemLine) {
  if (notEmpty(nlapiGetCurrentLineItemValue('item','item'))) {
    nlapiCommitLineItem('item');
  }
  nlapiSelectLineItem('item', itemLine);
}
Most important lesson I've learned is that cart script behaves differently in webstore. Do test your code on the external form but be extra careful not to fully trust the result. When testing on webstore, keep close eye on your log execution files. If you ever see page init more than once, you know you have an error somewhere.

As I mentioned before on my previous post, turning on logging on webstore will slow down your cart since it's calling to your external suitelet so keep that in mind as well. 

Hope this helps you. Let me know if you get stuck. I'll try my best to help you out.

Saturday, May 14, 2011

How to debug Netsuite Webstore Scriptable Cart

We've MOVED!!!! www.codeboxllc.com/ksc


Notice:
Blogspot had issues with their server and post I originally wrote got deleted. I do apologize for missing link:

Important Update on this Post: 5/17/2011:
nlapiRequestURL() eats up API Governance meter by 10 points. Testing on External Form, if you have this turned on, you only have 1000 limit. On Webstore, you seem to have 2147483647. Don't ask me where that number came from.

So, Here I go again. How DO you debug scriptable cart executing on webstore? The script itself is attached to the External Sales Order form you create which implies is client level script. You can't use Firebug to step through it either.So how do you debug when your script is not returning the results you want?

I began using this workaround and it has helped me alot.
Workaround: Create Suitelet (Available without Login) to track printing of debug messages and call it using nlapiRequestURL() from your scriptable cart script.

Write Suitelet Script: Save as "sl_writelog.js" and push out to Netsuite 
** Please note, for simplicity, I've written my script to use GET event.
function slExecLog(request, response){
  if (request.getMethod() == 'GET') {
    var log = filterUserInput(request.getParameter('log'));
    var title=filterUserInput(request.getParameter('title'));
    writeLog('DEBUG',title,log);
    response.write('called back');
  }
}
Deploy your script:
  1. Login to Netsuite and go to Setup > Customization > Scripts > Click New
  2. Select Suitelet as script type
  3. Provide Name and ID for this script.
  4. Under Scripts tab, select "sl_writelog.js" for Script File and "slExecLog" as Function
  5. Select "Save and Deploy" option.
  6. Provide Name and ID for this script deployment
  7. Check "Available Without Login" 
  8. Select GET Request as Event Type.
    If you choose to use Post, you should change your script to check for POST and also select POST Request as Event Type
  9. Under Audience tab, select "All Roles"
  10. Save
Once you've deployed your script, copy the External URL for this deployment. According to NetSuite documentation, nlapiRequestURL() does NOT send User Session information. 

Link to your Suitelet from Scriptable cart script:
Open your scriptable cart script and create a function which will call your suitelet. This is how I did it:
Please note that anything enclosed in [ and ] is to be replaced by your code including the brackets.
function wslog(_txt) {
  if (!_txt) {
    return;
  }
  var loginUrl = '[External URL for your Suitelet]&title=[Value of title]&log='+_txt;
  if (wsdebug) {
    nlapiRequestURL(loginUrl, null, null);
    return;
  }else{
    alert(_txt);
  }
}
You will notice above that I check for wsdebug value. This is global boolean value I created so that I can turn on/off calling of my debug suitelet.
When I'm testing on the form, I set this value to false so that I can see the alert messages. Testing/deployment on webstore, I set this value to true.
Check your debug messages:
Once everything is doen, go to your Webstore and add items to your cart so that your scriptable cart script will fire.
To check the log messages, open your Suitelet script record and click on Execution Log.


Friday, April 29, 2011

NetSuite - Scripting/Debugging Tips I've learned so far

We've MOVED!!!! www.codeboxllc.com/ksc

NetSuites' SuiteScript is JavaScript based language which allows developers to really get down and dirty with truly customize NetSuite.

Like finger prints, not all businesses are alike. NetSuite tries pretty hard to meet the requirements of each and every businesses that are out there but it's an impossible task. That's why they have SuiteScript to build out your own, business specific customizations.

Here are some tips on scripting/customizing/debugging that I've picked up so far:
  1. Download and install Chrome or FireFox. JavaScript Debugger, Firebug is a must have tool. It allows you to set break points so that you can successfully debug your custom scripts.
  2. Take advantage of NetSuite Debugger. This is really good for unit testing your code. Write snippets of your code and execute it on NetSuite Debugger and verify your script behaves properly.
  3. Abstract out common functions and create utility script. I'm sure everyone is already doing this. I mean who really wants to write out nlapiLogExecution or nlapiSendEmail?!?!?!!?! Way too long!
  4. Unless you HAVE to... avoid using nlapiLoadRecord. If you are doing simple field value search or field updates, nlapiLookupField and nlapiSubmitField will do just fine. Only time I found myself using nlapiLoadRecord is when I had to drill down to sublists. I'm really hoping NetSuite will come up with function to do just this
  5. For Webstore customization, get to know what IS customizable. I recently had to customize login pages text and links on our Webstore. It turns out, all the text and links are customizable through Setup > Website > Customize Text
    If you are going to use Webstore, it really REALLY helps to purchase Advanced Web Module. 
Ok.. That's what I have so far...