Skip to Content

It’s been a while since the Service Layer has been enhanced with a new feature called Script Engine, released together with the SAP Business One, version for SAP HANA 9.2 PL04. I’m sure you have already read the relevant blog posts talking about it from Trinidad here and Andy Bai here, as well as the SAP Note 2343691 – Service Layer supports script engine.

As you’ve learned in those posts, there are many benefits of using script engine such as better performance, as it reduces the calls from your application to the Service Layer; re-use of server-side customizations; and the implementation of global transaction for several operations.

Now that you are already familiar with the feature, let me guide you through two very simple examples on how to implement it:

Example A – Creating a Sales Order

So, here is the scenario: before creating a Sales Order, you want to validate whether the customer already exists in the system. If it doesn’t exist, then create it before the sales order, if it already does, just create the sales order. In a world without Script Engine (before 9.2 PL04), your application would have to do at least two requests to the Service Layer (GET BusinessPartners(id), and POST Orders). Since 9.2 PL04, you can do a single request to your own custom script (at the script engine level) in the Service Layer and it will threat other calls internally.

In this example I’m interested in demonstrate the use of global transactions and how to call a Service Layer entity from a custom script, using the script engine feature.

Here is all you’ll need: one javascript and one xml, packed together in a zip file.

The steps required to accomplish this development is described below:

  1. Create a javaScript file which will threat a POST request and perform two calls: one GET request to validate the business partner and a POST request to add the sales order to the given business partner;
  2. Create an xml file with the ARD extension, where you’ll basically reference your javaScript file as part of the Service Layer, as well as some other data such as partner name and namespace so that Business One can install it in the right place during the deployment of your script;
  3. Create a zip file containing both ARD and JS files above;
  4. Run the deployment of this script by importing the zip file using the Extension Manager; and
  5. Test the new script calling it from a REST client.

Let’s now run it step-by-step.

1. Create a javaScript file, name it as you wish using the js extension, in this case it will be SalesOrders.js. Just open your favorite IDE and write the code below, note that it is fully commented:

// required to handle http calls
var http = require('HttpModule.js'); 

// required to call SL entities/actions
var ServiceLayerContext = require('ServiceLayerContext.js'); 

function POST() {    
    var ret = {};

    // Instantiates SL context
    var slContext = new ServiceLayerContext(); 

    // Gets the body of the request
    var salesOrderData = http.request.getJsonObj(); 
    
    // Starting point for the Global Transaction
    slContext.startTransaction(); 
 
    //Gets Business Partner data
    var res = slContext.BusinessPartners.get(salesOrderData.CardCode);
    
    //If it doesn't exist then create it
    if (res.status != 200){
        var res = slContext.BusinessPartners.add(
                    {   
                        "CardCode": salesOrderData.CardCode, 
                        "CardName": "BP created using SL Script Engine", 
                        "CardType": "C"
                    }
                );
        
        // If there's any problem creating Business Partner, 
        // roll back and throw the exception
        if (!res.isOK()) {
            slContext.rollbackTransaction();
            throw http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST, 
                                        res.getErrMsg());
        }
    }
    
    // This is to store and send back business partner details
    ret.BusinessPartnerDetail = res;

    //Create Sales Order
    var res = slContext.Orders.add(salesOrderData);

    // If there's any problem creating the Sales Order, 
    // roll back and throw the exception
    if (!res.isOK()) {
        slContext.rollbackTransaction();
        throw http.ScriptException(http.HttpStatus.HTTP_BAD_REQUEST, 
                                    res.getErrMsg());
    }

    // This is to store and send back sales order details
    ret.SalesOrderDetail = res;
    
    //Everything went smooth then commit!
    slContext.commitTransaction();

    /* SET HTTP RESPONSE */
    http.response.setContentType(http.ContentType.APPLICATION_JSON);
    http.response.setStatus(http.HttpStatus.HTTP_OK);
    http.response.setContent(ret);
    http.response.send();
}

2. Now create an XML file, give it the same name as the previous javascript just changing the extension to ard, in this case SalesOrders.ard. Fill in the Partner Namespace, Partner Name, Script name and File Name, as you can see below:

<?xml version="1.0" encoding="utf-8"?>
<AddOnRegData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              SlientInstallation="" 
              SlientUpgrade="" 
              Partnernmsp="saponenmsp" 
              SchemaVersion="3.0"
              Type="ServiceLayerScript" 
              OnDemand="" 
              OnPremise="" 
              ExtName=""
              ExtVersion="1.00" 
              Contdata="" 
              Partner="sapone" 
              DBType="HANA" 
              ClientType="S">
    <ServiceLayerScripts>
        <Script Name="SalesOrders" FileName="SalesOrders.js"></Script>
    </ServiceLayerScripts>
    <XApps>
        <XApp Name="" Path="" FileName="" />
    </XApps>
</AddOnRegData>

Note that this will define the URL you will call in your application, it is https://<hanaserver>:50000/b1s/v1/script/<Partner>/<Script Name>.

In this case, it will be a POST to the URL https://<hanaserver>:50000/b1s/v1/script/sapone/SalesOrders

3. Now generate a standard zip file containing both xml and js file above.

4. Open the Extension Manager at https://<hanaserver>:40000/ExtensionManager, select “Extensions” > “Import” > “Browse” > select the zip file and finish the wizard. Then assign the extension to a specific company: select “Company Assignment” > “Assign” > select the extension and finish the wizard.

5. Open your favorite REST client and test it by running a POST to the Login entity:

And a POST to the URL https://<hanaserver>:50000/b1s/v1/script/<Partner>/<Name> using the body such as the one below:

You should get a json object containing the business partner details and the sales order details.

Side note: there’s no mechanism in place at this moment to debug this kind of script in the server-side, but you can use the console.log command to keep track of the variables or steps you want to watch. The log files are recorded in the server side, under the path /<SAPBusinessOne Installation folder>/ServiceLayer/logs/script/, in this case /usr/sap/SAPBusinessOne/ServiceLayer/logs/script:

Example B – Identifying the current user logged in

It might be very useful to identify the current session properties such as the logged in user and company, mainly when there are many requests to the same script and you want to identify and log each call, for any reason.
While there is no standard Service Layer entity to do that so far, you can use the following script, but please note that this is a provisory solution – a new interface might be available in a future patch level.

var http = require('HttpModule.js');

function GET() {    
    
    var ret = {};
        
    /* GET CURRENT SESSION PROPERTIES */
    ret.user = session.getProperty('user');
    ret.company = session.getProperty('company');
    ret.version = session.getProperty('version');
    ret.maxOperationsPerTransaction = session.getProperty('maxOperationsPerTransaction');
    ret.server = session.getProperty('server');
    ret.timeout = session.getProperty('timeout');
    
    /* SET RESPONSE */
    http.response.setContentType(http.ContentType.APPLICATION_JSON);
    http.response.setStatus(http.HttpStatus.HTTP_OK);
    http.response.setContent(ret);
    http.response.send();
}

This is the call to the above script and the json returned:

Thanks to @Andy Bai for providing the information on how to get current session properties, and stay tuned to this blog where we will provide more details when available.

Hope you can enhance your apps by using all the power of the service layer. Enjoy!

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply