NetSuite Restlet Sample Program Exploits New Power

NetSuite’s new Restlet API is promising for developing external software applications that interact with NetSuite’s rich data and business functionality.  For example, imagine a large professional services organization that needs to track timesheets in the NetSuite Advanced Projects module.  Most professionals are highly mobile.  Instead of logging into NetSuite to do your timesheet via a web browser, imagine a small iPhone or Android app that allows you to quickly enter data.  Restlet is the key to make this happen without making a big investment.

This article illustrates how to connect up and create timesheet entries from a Linux Perl program.  This example should help bridge the key concepts to hook up to NetSuite through the new Restlet API.  The article assumes you have a good understanding of how to create and deploy scripts in the NetSuite environment.  The example consists of three files:

  1. restlet.js: NetSuite program to receive an insert time entry request.  It validates data and produces information in the execution log.
  2. timebill.pl: Perl program that reads timesheet entry data from timebill.csv file.  This file has hard coded NetSuite credential information.
  3. timebill.csv: tab delimited file in the following format: Date <tab> Client: Project <tab> Task <tab> Time in Decimal format <tab> Memo <newline – for new record>

Step 1: Deploy restlet.js

After enabling the NetSuite Restlet API create a new NetSuite Script as type Restlet.  Set it up with the following parameters:

  • Post Function: “CreateTimebills”
  • Deploy the function with a Log Level of “Debug”
  • Get the External URL.  In our case, it was “https://rest.netsuite.com/app/site/hosting/restlet.nl?script=73&deploy=1 “

Here is the restlet.js code:

function CreateTimebills(datain) {
    var output = '';
    nlapiLogExecution('DEBUG','createRecord',(typeof datain.timebill));
    var msg = validateTimeBills(datain);
    if (msg) {
        var err = new Object();
        err.status = "failed";
        err.message = msg;
        return err;
    }
    var timebills = datain.timebill;
    for (var timebillobject in timebills) {
        var timebill = timebills[timebillobject];
        var trandate = timebill.trandate;
        var customer = timebill.customer;
        var casetaskevent = timebill.casetaskevent;
        var hours = timebill.hours;
        var memo = timebill.memo;
        var timebill = nlapiCreateRecord('timebill');
        timebill.setFieldValue('trandate', trandate);
        timebill.setFieldText('customer', customer);
        timebill.setFieldText('casetaskevent', casetaskevent);
        timebill.setFieldValue('memo', memo);
        timebill.setFieldValue('hours', hours);
        var timebillid = nlapiSubmitRecord(timebill);
        nlapiLogExecution('DEBUG', 'Timebill ' + timebillid + ' successfully created', timebillid);
    }
    return;
}

function validateTimeBills(datain) {
    var timebills = datain.timebill;
    var returnMessage = "";
    for (var timebillobject in timebills) {
        var timebill = timebills[timebillobject];
        var trandate = timebill.trandate;
        var customer = timebill.customer;
        var casetaskevent = timebill.casetaskevent;
        var hours = timebill.hours;
        var memo = timebill.memo;
        if (isNaN(nlapiStringToDate(trandate))) {
            returnMessage += "Invalid date: '" + trandate + "'\n";
        }
        if (customer == '') {
            returnMessage += "Customer entry cannot be blank.'\n";
        }
        if (casetaskevent == '') {
            returnMessage += "Case Task Event entry cannot be blank.'\n";
        }
        if (hours == '') {
            returnMessage += "Hours cannot be blank.'\n";
        }
        if (memo == '') {
            returnMessage += "Memo cannot be blank.'\n";
        }
    }
    if (returnMessage) {
        nlapiLogExecution('DEBUG', 'Validation Error', returnMessage);
        return returnMessage;
    }
}

Step 2: Edit timebill.pl

Edit timebill.pl with your specific NetSuite account ID, username, password, and role.  Here is the code:

#!/usr/bin/perl

use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Headers;
my $inputfilelocation = "timebill.csv";
my $scriptdeployment = "https://rest.netsuite.com/app/site/hosting/restlet.nl?script=73&deploy=1";
my $account = "TSTDRV365788";
my $email = "developer\@prolecto.com";
my $password = "";
my $role = "15";
my $jsonString = & getJSONStringFromFile($inputfilelocation);
my $result = & submitRestlet($account, $email, $password, $role, "POST", $scriptdeployment, $jsonString);
print $result;
exit;
sub submitRestlet() {
    (my $account, my $email, my $password, my $role, my $method, my $deploymentURL, my $request) = @_;#
    define the HTTP header
    my $objHeader = HTTP::Headers - > new;
    $objHeader - > push_header('Authorization' => "NLAuth nlauth_account=$account, nlauth_email=$email, nlauth_signature=$password, nlauth_role=$role");
    $objHeader - > push_header('Content-Type' => 'application/json');#
    make the call
    my $objRequest = HTTP::Request - > new(
        $method,
        $deploymentURL,
        $objHeader,
        $request
    );
    my $content = "";#
    deal with the response
    my $objUserAgent = LWP::UserAgent - > new;
    my $objResponse = $objUserAgent - > request($objRequest);
    if (!$objResponse - > is_error) {
        return $objResponse - > content;
    } else {
        return $objResponse - > error_as_HTML;
    }
}
sub getJSONStringFromFile() {
    (my $inputfilelocation) = @_;
    open(FILE, $inputfilelocation);
    my $output = "";
    $output = qq {
        "timebill": [
        };
        while ( < FILE > ) {
            chomp;
            (my $trandate, my $customer, my $casetaskevent, my $hours, my $memo) = split("\t");
            $output. = "{";
            $output. = qq {
                "trandate": "$trandate",
                "customer": "$customer",
                "casetaskevent": "$casetaskevent",
                "hours": "$hours",
                "memo": "$memo"
            };
            $output. = "},";
        }
        close(FILE);
        chop($output);
        $output. = qq {]
    };
    $output = "{$output}";
    return $output;
}

Step 3: Create Timesheet Entry Data

In timebill.csv, create some data as input to insert as NetSuite timesheet entries.  Here are a couple sample entries.  Note the clients: projects, and tasks must match what is in already in NetSuite to work:

12/05/2011        SmartTech : Test Project 005      Test Task 005 (Task)     .75        Meeting on Specifications
12/05/2011        SmartTech : Test Project 005      Test Task 005 (Task)     1          Meeting with Management

The timebill.csv file should be placed in the same local directory as timebill.pl.

Step 4: Execute timebill.pl

Now you can run timebill.pl to see the program work.  If all goes right, it will take a few moments and return a code.  Go to the NetSuite script deployment log and see if the timesheet entries were created.  If so, check the timesheet system to find the new entries.

This article should help you kickstart your restlet system into a working prototype.  Stay tuned as we will be writing another article on how we are using restlets to create an Android / iOS app.

Be Sociable, Share!

Marty Zigman

Holding all three official certifications, Marty is Southern California's NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. He is a former Deloitte & Touche CPA and has held CTO roles. For over 25 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus - YouTube

| Tags: , , , , , , , , , , , , , , , , | Category: NetSuite, Technical | 30 Comments

29 Comments

  1. Posted January 9, 2012 at 8:32 pm | Permalink

    This is Awesome! I’ve been looking for examples on Restlets.

    Thank you!

  2. Posted June 24, 2013 at 9:57 am | Permalink

    Perl code…I think I’m in love.

    Seriously though. Great example code. Thank you!

  3. Posted June 24, 2013 at 9:59 am | Permalink

    Yes, we perform Perl legacy application development for some long-term clients. The great thing is that it all works and illustrates the model.

    Marty

  4. Posted June 24, 2013 at 10:03 am | Permalink

    Indeed. Perl is wonderful. Just rarely see it any more, especially in blog posts. I rather miss working with it.

    On a semi-related note, have you created file cabinet hosted applications that interface with RESTlets? For example, a static HTML page which utilizes jQuery or Javascript to format the POST data and sends it off? I’m debating between an externally vs. internally hosted page for some sales order interaction.

  5. Posted June 24, 2013 at 10:17 am | Permalink

    No, we haven not worked that use case. Yet, this kinds of questions come up when we think about optimizing the license model. Sometimes, we have to go with SuiteLets to produce the equivalent of ResetLets due to limitations with the security model.

    Marty

  6. Posted November 27, 2013 at 4:57 am | Permalink

    1)How to store and retrieve data(ArrayList of JavaObject) in/from NetSuite from Java web application?
    2)If possible, how to create a new NetSuite database table and to store and retrieve data?
    P.S: timothy@ghhcommerce.com is our customer login email address

  7. Posted December 2, 2013 at 5:57 am | Permalink

    Hello,

    First, I believe you are going to want to format your data as JSON between your Java Application and NetSuite.

    Second, you can easily create tables in NetSuite via Setup, Customization, Record Types. Then, you can use the Restlet capacities to expose this data. It’s pretty well documented in the NetSuite help guide.

    Marty

  8. Avinash
    Posted April 16, 2014 at 2:41 am | Permalink

    Hi,

    Can you please give me example of how to create restlet using get method
    and how to call the same restlet.

  9. Posted April 16, 2014 at 12:03 pm | Permalink

    Avinash,

    Have a look at this article. The code pattern is very similar as it handles both GETS and POSTS. T

    http://blog.prolecto.com/2013/08/04/how-to-code-pattern-for-netsuite-driven-jsonp-cross-domain-javascript/

    Marty

  10. Andrew Arrow
    Posted April 28, 2014 at 2:08 pm | Permalink

    Hi, I’m trying to write a RESTlet that will create a new employee. So far I have:

    var employeeRec = nlapiCreateRecord(’employee’);
    employeeRec.setFieldValue(‘lastname’, ‘Test’);
    employeeRec.setFieldValue(‘firstname’, ‘Frank’);
    employeeRec.setFieldValue(’email’, ‘test9475@frank.org’);
    employeeRec.setFieldValue(‘subsidiary’, 3);
    var id = nlapiSubmitRecord(employeeRec);
    nlapiLogExecution(‘DEBUG’,’bitium: ‘ + id + ‘ employee’,id);

    and it works great! But when I try and add:

    employeeRec.setFieldValue(‘giveAccess’, true);
    employeeRec.setFieldValue(‘password’, ‘somePassword1!’);
    employeeRec.setFieldValue(‘password2’, ‘somePassword1!’);

    it doesn’t have any effect. How do I make the employee have access to login and set their password after I create the employee? From netsuite web interface I select the “Access” tab.

  11. Posted May 1, 2014 at 8:50 pm | Permalink

    Hi Andrew,

    I suspect what is missing is the related role. Here is a code snippet from some recent work that allows the password to be set:

    //snippet
    NS_record.setFieldValue('accessrole', role_id);
    NS_record.setFieldValue('pass'+'word', password);
    NS_record.setFieldValue('pass'+'word2', password);
    NS_record.setFieldValue('giveaccess', 'T');
    NS_record.setFieldValue('sendemail', 'F')

    // watch the optional subsequent parameters
    new_id = nlapiSubmitRecord(NS_record, false, true)

    Marty

  12. IAN
    Posted October 22, 2014 at 7:44 pm | Permalink

    Hi,

    Im trying to submit the record inside PUT method in restlet, but it gives me an error?
    Here is the code:

    function putRESTlet(dataIn) {

    nlapiSubmitField(‘invoice’, dataIn.id, ‘custbody202’, ‘T’, true);
    }

    what seems to be the problem?

    Another question, does Restlet issue a submit behind the scene causing my code to fail?

    Note: my get request in success. It’s just this put request is giving me hard time.

    Thank you in advance.

  13. Posted October 26, 2014 at 12:06 pm | Permalink

    I recommend you first ensure that the data that is being posted is what you expect. Have you decomposed and inspected the ‘datain’ parameter to make sure that it indeed as the data you expect? Is there an ‘id’ property?

    On your second question, no, there is implicate submit behind the scenes with the Restlet. Think of a Restlet as a SuiteLet with an HTTP vocabulary (GET, POST, PUT, DELETE). All that is happening is that the data is being passed to you but you must perform all the logic to make it interact with the NetSuite platform.

  14. Sandy
    Posted November 17, 2014 at 2:45 am | Permalink

    Hi,

    How to write the Restlet POST Function in NetSuite to set the lineitem values for records like sales order and customer and what would be the JSON request for those ?

    Thanks.

  15. Posted November 17, 2014 at 6:29 am | Permalink

    Hello Sandy,

    The key to work with this is to understand that the Restlet is simply a JSON way to pass information back. That JSON can look like anything you want. Hence, you will need to define a JSON structure for expressing line item values. You could load a Sales Order record with nlapiLoadRecord and then JSON.stringify that object to have one interpretation. But you are free to invent.

    Once you get your values for your Sales Order and its respective lines, you will need to parse it and then effectively use the SubLists API to manipulate the line values. Calls to nlapiGetCurrentLineItemValues and nlapiSetCurrentLineItemValue are used. These calls are fundamental SuiteScirpt calls and have no relationship to the RestLet itself. The NetSuite Help document has many examples.

    Marty

  16. Avinash
    Posted February 21, 2015 at 6:19 am | Permalink

    Hi Marty,

    I found your blog very helpful.
    Thanks for sharing your knowledge with us.

    Having query:
    Scenario is i am using scheduled script to call a url.
    This url is used to fetch currency details.

    But problem is Netsuie automatically converts HTML entities into punctuations.
    Please refer code below…
    Problem scenario is as :

    var date1 = new Date();
    nlapiLogExecution(‘DEBUG’, ‘Daily Exchange rate’,’date1 is ‘+date1 );

    date1 = nlapiDateToString(date1);
    nlapiLogExecution(‘DEBUG’, ‘Daily Exchange rate’,’after nlapiDateToString date1 is ‘+date1 );

    var url = “https://www.testname.com/rates/api/v1/rates/USD.csv?”

    // ************* we required url in following format
    // https://www.testname.com/rates/api/v1/rates/USD.csv?quote=EUR&quote=USD&quote=CAN&quote=IND&date=2015/02/20

    var toCurrency = ”;

    // ******* arr_toCurrencies contains values like EUR,CAN,IND,USD. *************************
    for( var i=0; i < arr_toCurrencies.length ; i++)
    {
    toCurrency = arr_toCurrencies[i];
    nlapiLogExecution('DEBUG', 'Daily Exchange rate','toCurrency is '+toCurrency );

    if(i == 0)
    {
    url +="quote="+toCurrency;
    }
    else
    {
    url += "&quote="+toCurrency;

    nlapiLogExecution('DEBUG', 'Daily Exchange rate','url is '+url );
    }
    //nlapiLogExecution('DEBUG', 'Daily Exchange rate','herererererer url is '+url );

    }

    nlapiLogExecution('DEBUG', 'Daily Exchange rate','currency url is vname'+url );

    url += '&date='+date1+'&api_key='+oandaApiKey

    nlapiLogExecution('DEBUG', 'Daily Exchange rate','final url is '+url );

    // By above code we are able to get the url, but Netsuite automatically converts &quot into " and we are not getting required url.
    // URL which gets generated is :
    // https://www.testname.com/rates/api/v1/rates/USD.csv?quote=EUR"e=USD"e=CAN"e=IND&date=2015/02/20

  17. Posted February 21, 2015 at 10:51 am | Permalink

    Avinish,

    Have you tried to fetch the contents and then save it to the file system? Once there, you can open the file and process it. As per the documentation: “nlapiRequestURL automatically encodes binary content using base64 representation, since JavaScript is a character-based language with no support for binary types. This means you can take the contents returned and save them in the NetSuite file cabinet as a file or stream them directly to a response.”

    By the way, if you seeking to get Bitcoin currency rates into NetSuite, it is available free of charge at http://www.btc4erp.com

    Marty

  18. Avinash
    Posted February 23, 2015 at 11:04 am | Permalink

    Hi Marty,

    Thanks for your valuable response…
    I tried following solution.
    Rather than using &quote to create a url. i used %26quote and then while calling url thorugh nlapiRequestURL i replaced %26 with &.
    It works…

    Thanks…

  19. Saul
    Posted May 20, 2015 at 9:03 am | Permalink

    Hello Marty, thanks for your code, I’ve been looking for how to update a record with restlet, your help can be useful, thanks

  20. Posted May 20, 2015 at 10:24 am | Permalink

    Hi Saul,

    The way to update a record is like any other SuiteScript method to update records. Think of the RESTlet as a hookpoint function to gather inputs. The only difference is that there are four hookpoints corresponding with standard HTTP methods: GET, POST, PUT, and DELETE

    Here is a code pattern that shows how to update records. In this case, creating a NetSuite journal entry:

    http://blog.prolecto.com/2013/05/01/how-to-script-to-automate-netsuite-journal-entries/

  21. Posted June 1, 2015 at 3:54 am | Permalink

    Hi Marty,

    thank you for your great tutorial here. Helps a lot. Especially that you are using perl code for your example is nice since we are using perl for our systems, too.

    Hope for more!
    Paul

  22. Posted June 1, 2015 at 4:07 am | Permalink

    Thanks Paul. As a systems integrator, we need to be able to to use different languages. Certainly, Perl is one of our older languages. Plenty more coming.

    Marty

  23. RUPINDER
    Posted September 14, 2015 at 9:40 am | Permalink

    While trying to run this example, its giving error in perl script in accepting the password as:– it should require explicit package.plz resolve the same.

  24. Mohd Shoyeb
    Posted December 23, 2016 at 1:23 am | Permalink

    Hello Sir,

    I want to know, how can I get data from reslet from external url.

  25. Posted December 30, 2016 at 4:32 pm | Permalink

    The Restlet is an inbound to NetSuite technology. So your questions is sort of directionally confusing. However, you can call http services from NetSuite servers using the nlapiRequestURL (ver 1.0) call or use the N/http (ver 2.0) module.

  26. Gabukun
    Posted January 13, 2017 at 12:08 pm | Permalink

    This is great stuff. Can you share the JSON format for your code?

    Does it look like this?
    [
    {
    “trandate”: “12/01/2017”,
    “customer”: “NetSuite IMP Project”,
    “casetaskevent”: “SIT”,
    “hours”: “5:00”,
    “memo”: “Timesheet approval routing”,
    }
    ]

  27. Posted January 16, 2017 at 5:00 pm | Permalink

    This code example definitely could provide better instrumentation. If it succeeds, it does not return any business data.

  28. harish
    Posted March 5, 2018 at 4:34 am | Permalink

    I am trying the pull the data for a estimate record by hardcoding the value in restlet through restful web services,but i want to pass that hard code value in java.

    How to pass the value in Java,can you please help me

  29. Posted March 10, 2018 at 10:34 am | Permalink

    Hi Harish,

    The endpoint you create is up to your imagination. You can shape the data anyway you need to.

    Marty

One Trackback

  1. […] NetSuite Restlet Sample Program Exploits New Power Posted in Automation, NetSuite SHARE THIS Twitter Facebook Delicious StumbleUpon E-mail Similar posts […]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>