Showing posts with label tips. Show all posts
Showing posts with label tips. 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.

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);
}


Tuesday, August 2, 2011

Couple things NetSuite Documentation Doesn't Tell You

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

NetSuite most likely doesn't care what I complain to them about. I'm no body. I'm just a guy trying to make in this world.

However, I think these two items they may listen and PUT it on the documentation or make it more clearer.

Point 1: Check out customization URLs
There is ONLY ONE usable checkout URL in Sandbox Environment. That is https://checkout.sandbox.netsuite.com. All other selections are used ONLY for production.
I came across this issue while making our second webstore in Sandbox. When ever we refresh our Sandbox from Prod, this error occured. I initially thought it was just a flook. However, when second brand new Webstore I started on began to throw "Page Not Found" or "Internal Server Error" with other customizable check out URL, that's when it got me concerned.

Point 2: Domain IS required to be able to use Descriptive URLs
I'm sure some of you already knew this. I couldn't find anything on documentation about this specific statement. However, If you are having issues with Descriptive URL you set up for Items and Presentation Tabs, you need to set up your own domain.

CORRECTION:
Apparently, Point 2 is wrong on my part. You can find it under this Path of documentation:
Web Site : Searching & Search Engine Optimization : Search Engine Optimization (SEO) : Setting Up Descriptive URLs


It says:
To use descriptive URLs in NetSuite, first, set up a domain at Setup > Web Site > Set Up Domains. Next, turn on the Advanced Site Customization feature, and the Descriptive URLs feature at Setup > Company > Enable Features, on the Web Presence subtab. 

Wednesday, July 27, 2011

Steps to setting up your customized Invoice Template

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

This came as shock to me. I had issues finding different templates for setting up my custom invoice.
I broke my #1 rule of how to become NetSuite Guru. Did you click on the link? Well, #1 rule is to read the documentation and I did NOT on this particular case. =(

After doing some manly hunting work, I've figured out the mapping on custom invoice template. For us, we needed to include remittance slip on every invoice. Guess what, this is actually one of the feature you have to enable. (Again. READ YOUR DOCUMENTATION!!!)

If you are in the market to do such thing, here is how you enable remittance form with invoices:
Setup > Company > Printing, Fax & Email Preferences
- Check the box next to "Print Remittance Form with Invoices & Statements"

Here is how you set up your customized invoice. You kinda have to go backwards on this and here is why. When setting up your actual invoice, you supply templates for PDF layout, HTML layout and Remittance Slip.  Unless you plan to use Standard versions, you want to create custom versions of them.

Step 1-HTML Layout Template:
Go to Setup > Customization > Transaction Form HTML Layouts
- Select from different types of "Transaction" forms at your disposal to Customize.
- Provide custom HTML layout for your invoice under Templates Tab.
- You can customize HTML for specific NetSuite Tags under Elements tab.
- Save as "My Invoice HTML Layout" (This is a free country. You can name it what ever you want)

Step 2-PDF Layout Template:
Go to Setup > Customization > Transaction Form PDF Layouts
- Select from different types of "Transaction" forms at your disposal to Customize.
- Move things around, adjust the font size, text box etc.
** I found PDF layout customization somewhat difficult to work with. Just my $0.02
- Save as "My Invoice PDF Layout" (Again, name it what ever you want)

Setting up Remittance Form:
If you don't need to do this, you can skip this section but if you need to "customize" Remittance section, you may want to read on.

I don't know about you but for us, we needed to add text not available through NLATTRIBUTES. It had to be customized to look like our legacy invoice format. HTML version of Remittance form wasn't a problem because NetSuite provided highly flexible "TEXTAREA" to write our own HTML. However, PDF version... well, that was different story. Extremely customization UNFRIENDLY!!!!!

Step 3-HTML Remittance Form Template:
Go to Setup > Customization > Transaction Form HTML Layouts
- Select from different types of "Remittance Slip" forms at your disposal to Customize.
- Provide your custom HTML for remittance area of your invoice.
- Save as "My Invoice HTML Remittance Layout" (... Last time... Name it what ever you want)

Step 4-PDF Remittance Form Template:
Go to Setup > Customization > Transaction Form PDF Layouts
- Select your poison from "Remittance Slip" forms to Customize.
- Move things around, set up the way you want it to look in PDF.
** DO KEEP IN MIND, I found it Extremely difficult to customize this since only limited fields are at your disposal to display.
- Save as "My Invoice PDF Remittance Layout"

Step 5-Remittance Template Wrapper:
Go to Setup > Customization > Transaction Forms
- Select from different types of "Remittance Slip" forms to Customize.
- For PDF Layout, select "My Invoice PDF Remittance Layout" or what ever you named it on Step 4.
- For HTML Layout, select "My Invoice HTML Remittance Layout" or what ever you named it on Step 3.
** Quick Note: **
If you write ANYTHING on Disclaimer textbox, you can get to it by using the tag <DISCLAIMER>. However,... as I noted above, PDF is VERY VERY limited when it comes to providing free text. I actually used Disclaimer box to enter in my free text. I'm sure it's not recommended but this was the only way I found to enter in Free-Text.  IF you are doing what I did, be sure to do following:

  • Never use <DISCLAIMER> tag on your HTML template. Since HTML template is more flexible when it comes to free text, you can write it out.
  • Move things around on your PDF layout so that disclaimer box appears in different way.
  • IMPORTANT: Disclaimer and Address textarea are NOT HTML enabled. If you type HTML, it'll get parsed as regular text 

- Finally save this as "My Remittance Template Wrapper"

OK! You are now ready to create your own Invoice Template!

Step 6-Create Custom Invoice Template:
Go to Setup > Customization > Transaction Forms
- Select from different types of "Invoice" froms to Customize.
- For PDF Layout, select "My Invoice PDF Layout" or what ever you named it from Step 2.
- For HTML Layout, select "My Invoice HTML Layout" or what ever you named it from Step 1.
- For Remittance Slip, select "My Remittance Template Wrapper" or what ever you named it from Step 5.
- Save as "My Custom Invoice Template"

Now you see what I mean by going backwards?

Once you've set this up, you can choose your custom invoice from Sales Order templates to be used.

Here are some things that I found Important:

  • You need to set up EVERYTHING before you can TRUELY customize the look and feel. From the most parent level, you can provide different fields to be shown which can in turn be accessed by child forms.
  • From Customer Center, one you choose as default will be used for PDF layout. (If anyone from NetSuite can correct me on this, PLEASE DO!)
  • You CAN override Print in PDF by going to Home > Set Preferences > Transactions Tab and Setting "Print Using HTML" check box. However, THIS seems to be user based rather than Global setting.
Hope this helps... 

Tuesday, June 7, 2011

How to become a NetSuite Guru

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

This is just my opinion but I think I'm starting to see a pattern on how to to become true NetSuite Guru. I'm sure I have a right to say this since I have such knowledge and experience on working with NetSuite. (I'm being really sarcastic here. I don't have long years of experience and I am not a NetSuite Guru. It's my way of making a joke).

  1.  Read NetSuite documentation.
    I admit, I haven't read topic in NetSuite documentation. I get lost reading accounting and financing topics. I should have paid more attention in College. It really helps to know where to go for help. I see lot of people jumping the gun and asking people but if you  read the documentation answers are there. It also allows you the ability to find what you are looking for quickly.
  2. Expand your knowledge of relational database.
    You may disagree with me on this but I feel that it really helps if you have understanding in this area. Custom records is nothing but database tables. Creating and defining relationships between custom records and native records allows you to build better forms and business processes.
  3. Become an expert on HTML, CSS and JavaScript
    If you are doing any kind of customization, you need to know these three technologies. Form customizations, business process customizations and webstore customizations all depends on these three technologies and it will make your life easier as a developer.
  4. Know what is available out of the box as well as online public bundles.
    I think this goes with point #1. There are times when you get lost in joy and high of customizing NetSuite. However, beware of over customization. There are things that are readily available for you out of the box. You don't have to build something from ground up. There are also free bundles you can download and customize to your need.
  5. Understand the business needs.
    With NetSuite, I think it's very important that you understand organizational goal as well as each departments needs. NetSuite is just a tool.
  6. Atleast have an understanding of NetSuite process.
    You don't have to be an expert in project management or accounting or finance. As long as you understand how NetSuite processes them, you can build or configure based on expertise provided by your organizations' department experts.
  7. Study, Practice and Participate
    I've been hearing alot of negative feedback on NetSuite lately. and I have one thing to say to all Nay Sayers. No matter what cloud platforms you go with, if you don't take time to learn the product you are a lost cause. Always study up on features and unknown features of NetSuite, always practice different methodologies and always participate in user forums.