Free Code – Wrapper for searches in NetSuite

About a year ago I wrote a SuiteScript 1.0 class as a wrapper around the search functionality in NetSuite. I have updated the code over time, and I want to share the latest version. Among the new features is support for formulas and search expressions. The class should be backwards compatible with the original version, but in addition you can also pass an object to most functions, instead of passing separate parameters. This makes it more flexible and allows me to add more functionality. Enjoy!   /** * Encapsulate NetSuite search functionality in an easy-to-use object for SuiteScript 1.0. * * Version Date Author Remarks * 1.0 11 Nov 2016 kmartinsson Initial version * 1.5 06 Jul 2017 kmartinsson Added record type to constructor * 2.0 23 Aug 2017 kmartinsson Added Search2 function, with support for objects and adding multiple columns/filters * 2.0.1 01 Sep 2017 kmartinsson Bug-fixes * 2.0.2 01 Sep 2017 kmartinsson Fixed issue with join not being null, added hasOwnProperty check * 3.0 20 Nov 2017 kmartinsson Removed v1.x code stream, renamed Search2 to Search * 3.0.1 06 Dec 2017 kmartinsson Added JSDoc style comments, updated comments to new JSDoc style * 3.0.2 28 Feb 2018 kmartinsson Fixed bug in sort key which prevented proper sorting. Added alternative keys. * 3.0.3 15 Jul 2018 kmartinsson Added filter expression support * 3.0.4 01 Oct 2018 kmartinsson Added method removeColumns() for use on (external) saved search * */ /** * Search object * @constructor * @param {string} recordtype - Optional NetSuite recordtype (internalid) */ function Search(recordtype) { this.recordType = null; this.columns = []; this.filters = []; this.filterExpressions = []; // Set internal id of saved search to null this.internalId = null; this.noSavedColumns = false; // If record type/ID is supplied, set it now, otherwise default to null if (recordtype != null && recordtype != "") { this.recordType = recordtype; } // Helper function to verify the value is empty or null function isNullOrEmpty(val) { if (val == null || val == '' || val ==[] || val == {}) { return true; } else { return false; } } /** * Remove all columns included in the search * @param none * */ this.removeColumns = function() { this.noSavedColumns = true; } /** * Add a column to include in the search * @param {object}|{string} column - Object specifying a column to return or string containing columnId * @param {string} join - Joined record (internalid) (optional) * @param {boolean}|{string} sorting - Sorting (optional) * Options: true = descending, false = ascending, empty/null = no sorting, "yes" (ascending), * "no", "ascending", "descending" (can be abbreviated "a" and "d" respectively). */ this.addColumn = function(column, join, sorting) { var nsSearchColumn = null; var paramColName = null; var paramJoin = null; var paramSummary = null; var paramSorted = null; // Check if first argument is string or object if (typeof column == "string") { paramColName = column; // Check if second argument is null (for no join) if (isNullOrEmpty(join)) { paramJoin = null; // Check…

0 Comments

Convert US state abbreviations in Javascript

I was working on a NetSuite project today, and I ran into a problem. I used DataTables to display sales orders. The data is retrieved through an Ajax call to a RESTlet on the server. One of the columns to display is the state of the shipping address. The table had a number of columns, so I was happy that the state coming over during the early testing were the abbreviated state. But today I noticed that after real data had been entered into the system, the state was the full name. And I had no space left in the table for that. So I did a quick search and found a snippet of code that converted between abbreviation and full name and vice versa. I made some minor modifications to the code, mainly to clean it up and also make the code easier to read. I introduced two constants to indicate which kind of conversion to use, and replaced the traditional loop through the array with a for...of iteration. You can find the code here: https://github.com/TexasSwede/stateAbbreviations And this is how you use it: var stateName = convertRegion("TX",TO_NAME); // Returns 'Texas" var stateAbbreviation = convertRegion("Florida",TO_ABBREVIATED): // Returns "FL" This code is of course not specific to NetSuite, it is plain Javascript. You can use it in a Domino web application or even in a Notes form. And naturally you can use it in pretty much any web application where you can use Javascript. Enjoy!

0 Comments

Load and Modify External File in NetSuite

When building a suitelet in NetSuite you can either inject HTML, CSS and Javascript in a field, or generate a full HTML page and render it into the suitelet. No matter which method you use, you normally have to write line after line of SuiteScript code where you build the HTML using string concatenation. This is not only difficult and tedious to write, making sure you match all the single and double quotes and semi colons, it also makes the code much harder to maintain. What if you could just create a regular HTML file, put it in the File Cabinet and then render it into a suitelet? And what if you could use one line of code to inject values from NetSuite in the correct place in the HTML? This could be search results from the use of my search function. That is what the function looks like: /** * Load file from NetSuite File Cabinet and replace placeholders with actual values * * Version Date Author Remarks * 1.00 07 Nov 2016 kmartinsson Created class/function * 1.01 08 Nov 2016 kmartinsson Consolidated setValue and setHTML into * one method and added noEscape parameter */ // ***** Read and process external file, replacing placeholders with proper values ***** function ExternalFile(filename) { //Get the file by path/name, can also be internal id var fileId = filename; // Load file content and store data var file = nlapiLoadFile(fileId); var data = file.getValue(); this.content = data; this.setValue = function(placeholder, value, noEscape) { // Check if noEscape is passed, if it is and if true then don't escape value. // This is needed when value contains HTML code. if (typeof noEscape == "undefined") { this.content = this.content.replace(new RegExp(placeholder, 'g'), nlapiEscapeXML(value)); } else { if (noEscape == true) { this.content = this.content.replace(new RegExp(placeholder, 'g'), value); } else { this.content = this.content.replace(new RegExp(placeholder, 'g'), nlapiEscapeXML(value)); } } } this.getContent = function() { return this.content; } } Reference this function in your Suitescript 1.0 code like this: // Load extrenal HTML file var html = new ExternalFile("SuiteScripts/BinTransfer.html"); // Insert NetSuite URL for CSS files var cssFileName = nlapiLoadFile("SuiteScripts/css/drop-shadow.css").getURL(); html.setValue("%cssDropShadow%", cssFileName, true); cssFileName = nlapiLoadFile("SuiteScripts/css/animate.css").getURL(); html.setValue("%cssAnimate%", cssFileName, true); // Insert array returned from a search html.setValue("%binarray%", JSON.stringify(binArray), true); // Replace placeholders with values html.setValue("%showAll%", "false"); html.setValue("%company%", companyName); The last (optional) argument "noEscape" decides if the value should be URL encoded (false/omitted) or not (true) using the function nlapiEscapeXML(). In most cases you don't need to specify this argument, but if you need to pass HTML or other code into the function you need to set it to true to avoid the code being modified. As you can see in my example above, I get the NetSuite URL for my CSS files as well. Instead of hard coding the NetSuite URL into the HTML page, I calculate it and insert it when the page is loaded. Not only does it make the page easier to read the code, it also makes it much easier to maintain. This is…

0 Comments

Easy NetSuite Search

In an attempt to expand my knowledge to other platforms than Notes and Domino, I have now been working with NetSuite for a number of months. I have mainly been working with the ERP part of the cloud based system. The language used is called SuiteScript, and it is Javascript with a NetSuite-specific API to work directly with the databases. Knowing Javascript makes it easy to get started, just like knowing Visual Basic makes it easy to learn Lotusscript. And just like with Lotusscript, you have to learn the NetSuite specific functions. Since I like my code clean and easy to read (which will make future maintenance easier), I have created a number of functions to encapsulate NetSuite functionality. The first one I created was to search the database. The search in NetSuite is done by defining the columns (i.e. fields) to return as an array of search column objects. Then an array of search filters is created, and finally the search function is called, specifying what record type to search and passing the two arrays to it as well. This is a lot of code, and with several searching in a script it can be very repetetive, not to mention hard to read. Here is an example of a traditional NetSuite search: var filters = []; filters.push(new nlobjSearchFilter('item', null, 'anyof', item)); filters.push(new nlobjSearchFilter('location', null, 'noneof', '@NONE@')); var columns = []; columns.push(new nlobjSearchColumn('internalid')); columns.push(new nlobjSearchColumn('trandate').setSort()); columns.push(new nlobjSearchColumn('location')); var search = nlapiSearchRecord('workorder', '', filters, columns); Using my function, the code wold be simplified to this: var search = new Search('workorder'); search.addFilter('item', null, 'anyof', item); search.addFilter('location', null, 'noneof', '@NONE@'); search.addColumn('internalid')); search.addColumn('trandate',true); // Sort on this column search.addColumn('location'); var search = search.getResults(); The function also support saved searches. Simply add the following line: search.useSavedSearch('custsearch123'); There is a limitation in SuiteScript so that a maximum of 1000 records can be returned by a normal search. There is a trick to bypass this, but it requires some extra coding. So I thought why not add this into the function as default? So I did. Below is the code for the search function. I usually put it in a separate file and reference it as a library in the scripts where I want to use it. This first version does not support more advanced functionality like formulas in the filters. But for most searches this function will be usable. /** * Module Description * * Version Date Author Remarks * 1.00 11 Nov 2016 kmartinsson * 1.05 27 May 2017 kmartinsson Added support for record type in constructor * */ //***** Encapsulate search functionality ***** function Search(recordtype) { this.columns = []; this.filters = []; // If record type/ID is passed, no need to set it later if (recordtype == null || recordtype == "") { this.recordType = null; } else { this.recordType = recordtype; } // Set internal id of saved search to null this.internalId = null; // *** Set array of column names to return this.setColumns = function(columnArray) { for (var i = 0; i…

1 Comment

End of content

No more pages to load