Nav
You are viewing an older version of this section. Click here to navigate to the latest version.

NetSuite Connector

Select

MuleSoft’s Anypoint™ Connector for NetSuite synchronizes data and automates business processes between NetSuite and third party applications, either on-premises or in the cloud.

Introduction

NetSuite is the world’s leading provider of cloud-based business management software. NetSuite helps companies manage core business processes with a single, fully integrated system covering ERP/financials, CRM, e-commerce, inventory, and more.

The NetSuite connector makes use of the SuiteTalk WSDL to provide SOAP-based integration and generate NetSuite business objects, make use of different authentication levels, and support error handling.

Prerequisites

This document assumes that you are familiar with Mule, Anypoint™ Connectors, and the Anypoint Studio interface. To increase your familiarity with Studio, consider completing one or more Anypoint Studio Tutorials. Further, this page assumes that you have a basic understanding of Mule flows and Mule Global Elements

To use this connector, you need a NetSuite account with Web Services Features enabled, and Anypoint Studio installed on your development machine.

Compatibility

The NetSuite connector v7.1.0 is compatible with:

Application/Service Version

Mule Runtime

3.5 and later

API

SuiteTalks 2015_2

Installing and Configuring

Installing

You can install a connector in Anypoint Studio using the instructions in Installing a Connector from Anypoint Exchange

However, to use the NetSuite connector in a production environment, you must have either:

  • An Enterprise Mule license.

  • CloudHub Starter, Professional, or Enterprise account.

Contact the MuleSoft Sales Team to obtain either of these. (Read more about Installing an Enterprise License.) 

Creating a New Project

To use the NetSuite connector in a Mule application project:

  1. In Studio, click File > New > Mule Project.

    filenew

  2. Enter a name for your new project and leave the remaining options with their default values.

    netsuite_new_mule_project

  3. If you plan to use Git, select Create a .gitignore file for the project with default ignores for Studio Projects, and click Next.

  4. Click Finish to create the project.

Configuring the NetSuite Connector Global Element

To use the NetSuite connector in your Mule application, you must configure a global NetSuite element that can be used by all the NetSuite connectors in the application (read more about global elements).

Not much has changed on this front, and as before (starting from v6.0.0) you are presented with a number of different Global Elements, each representing a different way of authenticating to NetSuite, but this release includes a new method of authentication: NetSuite: Request Level Token Based Authentication:

Configuration Description

Login Authentication

Makes use of the SuiteTalks login API call on the first request sent by the connector to establish a session with NetSuite.

Request Level Authentication

Using this strategy, you can send user credentials in the SOAP header of each request instead of authenticating to NetSuite by invoking login.

Single Sign-On Login Authentication

This is a token based authentication system that avoids the use of environment username and password. Here you supply a privateKey together with other information. The connector is then responsible for generating an authentication token and establishing a session with NetSuite via the ssoLogin API call on the first request.

Request Level Token Based Authentication

Similar to Single Sign-On Login Authentication, this is a token based authentication system. However, instead of using a privateKey generated via openssl, this uses a consumer and token key/secret pairs which are established within the NetSuite environment.

Follow these steps to configure NetSuite connector global element in a Mule application:

  1. Click the Global Elements tab at the base of the canvas.

  2. On the Global Mule Configuration Elements screen, click Create.

  3. In the "Choose Global Type" wizard, expand  Connector Configuration, and then select  NetSuite: Login Authentication, NetSuite: Request Level Authentication, NetSuite: SSO Login Authentication, or NetSuite: Request Level Token Based Authentication depending on your NetSuite authentication.

    netsuite_global_configuration

  4. Click Ok.

  5. Enter global element properties.

    1. For NetSuite: Login Authentication and NetSuite: Request Level Authentication:

      Parameter Description

      Name

      Enter a name for the configuration with which to reference it later.

      Email

      Enter the login email of the NetSuite UI.

      Password

      Enter the corresponding password to log into NetSuite UI.

      Account

      Enter the account ID of the SuiteTalk NetSuite web services. This is usually found within NetSuite sandbox UI under Setup > Integration > Web Service Preferences.

      Role Id

      Enter the role ID for the user in SuiteTalk, which determines the Processor privileges.

      Application Id

      Enter the application ID corresponding to the Integration record to be used (New in NetSuite Connector version 7.0.0).

      Connection Timeout

      Enter the amount of time, in milliseconds, that the client must attempt to establish a connection before timing out.

      Receive Timeout

      Enter the amount of time, in milliseconds, that the client must wait for a response before timing out.

      Enable DataSense

      If you select this option, DataSense extracts metadata for NetSuite standard objects to automatically determine the data type and format that your application must deliver to, or can expect from, NetSuite. By enabling this functionality, Mule does the heavy lifting of discovering the type of data you must send to, or be prepared to receive from NetSuite. For more information, see DataSense.

      Endpoint

      Enter the URL of the service endpoint.

      Make sure that the endpoint uses the version of NetSuite that the connector supports.

      Separator

      Enter the separator used to support the keys that are required to provide a better support for custom fields.

    2. For NetSuite: SSO Login Authentication:
      To use the SSO Login Authentication, enable this feature in your sandbox environment by NetSuite’s Support. NetSuite provides an SSO Kit and information on how to proceed with setting up private and public keys for use in generating authentication tokens. They also provide you with a Partner ID. After this setup is established, a mapping has to be created between the standard NetSuite credentials, the partner ID, company ID, and user ID. A developer or administrator should perform this mapping. It is not handled by the connector and it is only done once for each user ID that is allowed to authenticate using SSO within your company.

      For this mapping, start by generating a token using the SSO Kit provided by NetSuite. To establish the mapping, invoke the SuiteTalks Web Service API call mapSso using an external Java application or any other method of your choice. A sample SOAP request of the mapSso API call looks as follows:

      
                
                        
                     
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:messages_2015_1.platform.webservices.netsuite.com" xmlns:urn1="urn:core_2015_1.platform.webservices.netsuite.com">
         <soapenv:Header></soapenv:Header>
         <soapenv:Body>
            <urn:mapSso>
               <urn:ssoCredentials>
                  <urn1:email>Your NetSuite email</urn1:email>
                  <urn1:password>Your NetSuite password</urn1:password>
                  <urn1:account>Your NetSuite account Id</urn1:account>
                  <urn1:role internalId="The account role Id"></urn1:role>
                  <urn1:authenticationToken>The token string generated using the SSO kit</urn1:authenticationToken>
                  <urn1:partnerId>Your NetSuite partner Id</urn1:partnerId>
               </urn:ssoCredentials>
            </urn:mapSso>
         </soapenv:Body>
      </soapenv:Envelope>
      Parameter Description

      Name

      Enter a name for the configuration so it can be referenced later.

      Partner Id

      Enter the partner ID used in the mapping process.

      Partner Account

      Enter the account ID of the SuiteTalk NetSuite web services.

      Company ID

      Enter the company ID used in the mapping process for the connector to generate a token.

      User ID

      Enter the user ID used in the mapping process for the connector to generate a token.

      Key File

      Enter the privateKey file name to pick up from the project. This file should be the .der file generated as per NetSuite’s specifications. This is used to encrypt the company ID and user ID into a token for ssoLogin.

      Application Id

      Enter the application ID corresponding to the Integration record to be used (New in NetSuite Connector version 7.0.0).

      Connection Timeout

      Enter the amount of time, in milliseconds, that the client must attempt to establish a connection before timing out.

      Receive Timeout

      Enter the amount of time, in milliseconds, that the client must wait for a response before timing out.

      Enable DataSense

      If you select this option, DataSense extracts metadata for NetSuite standard objects to automatically determine the data type and format that your application must deliver to, or can expect from, NetSuite. By enabling this functionality, Mule does the heavy lifting of discovering the type of data you must send to, or be prepared to receive from NetSuite. For more information, see DataSense.

      Endpoint

      Enter the URL of the service endpoint.

      Separator

      Enter the separator used to support the keys that are required to provide a better support for custom fields.

      Required Libraries

      Click Add File to add the SSO jar that you acquire via NetSuite support.

    3. For NetSuite: Request Level Token Based Authentication:
      To use this authentication mechanism you will need to set up an Integration Record within NetSuite and enable Token Based Authentication. This will automatically generate a consumer key and secret for you.

      Furthermore you must set up an access token from within your NetSuite environment that combines the Integration Record with a User. This could be done assuming that your NetSuite account has the required permissions enabled in order to generate such tokens and login using them.

      Please refer to NetSuite’s Help Center or SuiteAnswers for detailed information on how to navigate NetSuite and set this up.

      Parameter Description

      Consumer Key

      Enter the consumer key value for the token based authentication enabled integration record being used.

      Consumer Secret

      Enter the consumer secret value for the token based authentication enabled integration record being used.

      Token Id

      Enter the token id representing the unique combination of a user and integration generated within the NetSuite environment.

      Token Secret

      Enter the respective token secret for the user/integration pair.

      Account

      Enter the account ID of the SuiteTalk NetSuite web services. This is usually found within NetSuite sandbox UI under Setup > Integration > Web Service Preferences.

      Connection Timeout

      Enter the amount of time, in milliseconds, that the client must attempt to establish a connection before timing out.

      Receive Timeout

      Enter the amount of time, in milliseconds, that the client must wait for a response before timing out.

      Enable DataSense

      If you select this option, DataSense extracts metadata for NetSuite standard objects to automatically determine the data type and format that your application must deliver to, or can expect from, NetSuite. By enabling this functionality, Mule does the heavy lifting of discovering the type of data you must send to, or be prepared to receive from NetSuite. For more information, see DataSense.

      Endpoint

      Enter the URL of the service endpoint.

      Make sure that the endpoint uses the version of NetSuite that the connector supports.

      Separator

      Enter the separator used to support the keys that are required to provide a better support for custom fields.

  6. Access the Pooling Profile tab to configure any settings relevant to managing multiple connections via a connection pool.

  7. Access the Reconnection tab to configure any settings relevant to reconnection strategies that Mule should execute if it loses its connection to NetSuite.

  8. Click OK to save the global connector configurations.

  9. Return to the Message Flow tab in Studio.

  1. Ensure that you include the NetSuite namespaces in your configuration file.

    
           
                   
                
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    <mule xmlns="http://www.mulesoft.org/schema/mule/core"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:netsuite="http://www.mulesoft.org/schema/mule/netsuite"
          xsi:schemaLocation="
                   http://www.mulesoft.org/schema/mule/core
                   http://www.mulesoft.org/schema/mule/core/current/mule.xsd
                   http://www.mulesoft.org/schema/mule/netsuite
                   http://www.mulesoft.org/schema/mule/netsuite/current/mule-netsuite.xsd">
     
    </mule>
  2. Create a global NetSuite configuration outside and above your flows, using one of the following global configuration codes:

    
           
                   
                
    1
    
    <netsuite:config-login-authentication name="NetSuite" email="${email}" password="${password}" account="${account}" roleId="${roleId}" applicationId="${applicationId}"/>
    
           
                   
                
    1
    
    <netsuite:config-request-level-authentication name="NetSuite" email="${email}" password="${password}" account="${account}" roleId="${roleId}" applicationId="${applicationId}"/>
    
           
                   
                
    1
    
    <netsuite:config-sso-login-authentication name="NetSuite" email="${email}" password="${password}" account="${account}" roleId="${roleId}" applicationId="${applicationId}"/>
    
           
                   
                
    1
    
    <netsuite:config-request-level-token-based-authentication name="NetSuite" consumerKey="${consumerKey}" consumerSecret="${consumerSecret}" tokenId="${tokenId}" tokenSecret="${tokenSecret}" account="${account}" />

Using the Connector

NetSuite connector is an operation-based connector, which means that when you add the connector to your flow, you need to configure a specific web service operation for the connector to perform. NetSuite connector v7.1.0 supports 50 operations.

Adding to a Flow

  1. Create a new Mule project in Anypoint Studio.

  2. Add a suitable Mule inbound endpoint, such as the HTTP listener or File endpoint, to begin the flow.

  3. Drag the NetSuite connector onto the canvas, then select it to open the properties editor.

  4. Configure the connector’s parameters as follows:

    Field Description

    Display Name

    Enter a unique label for the connector in your application.

    Config Reference

    Connect to a global element linked to this connector. Global elements encapsulate reusable data about the connection to the target resource or service. Select the global NetSuite connector element you create.

    Operation

    Select the action this component must perform.

Custom Field DataSense

In NetSuite one can add different types of custom fields and have these customizations apply to different record types. With DataSense enabled, the NetSuite connector retrieves and shows these fields. Note however that we do not fully support all the customization types that NetSuite users are able to define. The following lists outline what fields we do and do not handle, and where they currently appear in relation to the record type’s attributes. For the most part you can see that customizations are usually present within a list field called customFieldList, but in some cases these might reside elsewhere.

Entity Fields

Record Type Custom Field Placement

CONTACT

Contact > customFieldList > customField

CUSTOMER

Customer > customFieldList > customField

EMPLOYEE

Employee > customFieldList > customField

ENTITY_GROUP

EntityGroup > customFieldList > customField

PARTNER

Partner > customFieldList > customField

PROJECT_TASK

ProjectTask > customFieldList > customField

VENDOR

Vendor > customFieldList > customField

Item Fields

Record Type Custom Field Placement

ASSEMBLY_ITEM

AssemblyItem > customFieldList > customField

ENTITY_GROUP

EntityGroup > customFieldList > customField

INVENTORY_ITEM

InventoryItem > customFieldList > customField

KIT_ITEM

KitItem > customFieldList > customField

NON_INVENTORY_PURCHASE_ITEM

NonInventoryPurchaseItem > customFieldList > customField

NON_INVENTORY_RESALE_ITEM

NonInventoryResaleItem > customFieldList > customField

NON_INVENTORY_SALE_ITEM

NonInventorySaleItem > customFieldList > customField

OTHER_CHARGE_PURCHASE_ITEM

OtherChargePurchaseItem > customFieldList > customField

OTHER_CHARGE_RESALE_ITEM

OtherChargeResaleItem > customFieldList > customField

OTHER_CHARGE_SALE_ITEM

OtherChargeSaleItem > customFieldList > customField

SERVICE_PURCHASE_ITEM

ServicePurchaseItem > customFieldList > customField

SERVICE_RESALE_ITEM

ServiceResaleItem > customFieldList > customField

SERVICE_SALE_ITEM

ServiceSaleItem > customFieldList > customField

CRM Fields

Record Type Custom Field Placement

CALENDAR_EVENT

CalendarEvent > customFieldList > customField

CAMPAIGN

Campaign > customFieldList > customField

ISSUE

Issue > customFieldList > customField

MANUFACTURING_OPERATION_TASK

ManufacturingOperationTask > customFieldList > customField

PHONE_CALL

PhoneCall > customFieldList > customField

PROJECT_TASK

ProjectTask > customFieldList > customField

SOLUTION

Solution > customFieldList > customField

SUPPORT_CASE

SupportCase > customFieldList > customField

TASK

Task > customFieldList > customField

Transaction Body Fields

Record Type Custom Field Placement

ASSEMBLY_BUILD

AssemblyBuild > customFieldList > customField

CASH_SALE

CashSale > customFieldList > customField

CUSTOMER_PAYMENT

CustomerPayment > customFieldList > customField

DEPOSIT

Deposit > customFieldList > customField

ESTIMATE

Estimate > customFieldList > customField

EXPENSE_REPORT

ExpenseReport > customFieldList > customField

INVENTORY_ADJUSTMENT

InventoryAdjustment > customFieldList > customField

INVOICE

Invoice > customFieldList > customField

ITEM_FULFILLMENT

ItemFulfillment > customFieldList > customField

ITEM_RECEIPT

ItemReceipt > customFieldList > customField

JOURNAL_ENTRY

JournalEntry > customFieldList > customField

OPPORTUNITY

Opportunity > customFieldList > customField

PURCHASE_ORDER

PurchaseOrder > customFieldList > customField

PURCHASE_REQUISITION

PurchaseRequisition > customFieldList > customField

SALES_ORDER

SalesOrder > customFieldList > customField

TRANSFER_ORDER

TransferOrder > customFieldList > customField

VENDOR_BILL

VendorBill > customFieldList > customField

VENDOR_CREDIT

VendorCredit > customFieldList > customField

VENDOR_PAYMENT

VendorPayment > customFieldList > customField

VENDOR_RETURN_AUTHORIZATION

VendorReturnAuthorization > customFieldList > customField

WORK_ORDER

WorkOrder > customFieldList > customField

Transaction Column Fields

Record Type Custom Field Placement

CASH_SALE

CashSale > itemList > item > customFieldList > customField

ESTIMATE

Estimate > itemList > item > customFieldList > customField

EXPENSE_REPORT

ExpenseReport > expenseList > expense > customFieldList > customField

INVOICE

Invoice > itemList > item > customFieldList > customField

ITEM_FULFILLMENT

ItemFulfillment > itemList > item > customFieldList > customField

ITEM_RECEIPT

ItemReceipt > itemList > item > customFieldList > customField

JOURNAL_ENTRY

JournalEntry > lineList > line > customFieldList > customField

OPPORTUNITY

Opportunity > itemList > item > customFieldList > customField

PURCHASE_ORDER

PurchaseOrder > itemList > item > customFieldList > customField

PURCHASE_REQUISITION

PurchaseRequisition > itemList > item > customFieldList > customField

SALES_ORDER

SalesOrder > itemList > item > customFieldList > customField

TIME_BILL

TimeBill > customFieldList > customField

TRANSFER_ORDER

TransferOrder > itemList > item > customFieldList > customField

VENDOR_BILL

VendorBill > itemList > item > customFieldList > customField

VENDOR_CREDIT

VendorCredit > itemList > item > customFieldList > customField

VENDOR_PAYMENT

VendorPayment > itemList > item > customFieldList > customField

VENDOR_RETURN_AUTHORIZATION

VendorReturnAuthorization > itemList > item > customFieldList > customField

WORK_ORDER

WorkOrder > itemList > item > customFieldList > customField

Transaction Item Options

Currently DataSense cannot detect NetSuite’s Transaction Item Options.

Item Number Fields

Currently DataSense cannot detect NetSuite’s Item Number Fields.

Other Custom Fields

Record Type Custom Field Placement

ACCOUNT

Account > customFieldList > customField

BIN

Bin > customFieldList > customField

CLASSIFICATION

Classification > customFieldList > customField

EXPENSE_CATEGORY

ExpenseCategory > customFieldList > customField

ITEM_DEMAND_PLAN

ItemDemandPlan > customFieldList > customField

ITEM_SUPPLY_PLAN

ItemSupplyPlan > customFieldList > customField

LOCATION

Location > customFieldList > customField

MANUFACTURING_COST_TEMPLATE

ManufacturingCostTemplate > customFieldList > customField

MANUFACTURING_ROUTING

ManufacturingRouting > customFieldList > customField

NOTE

Note > customFieldList > customField

PROMOTION_CODE

PromotionCode > customFieldList > customField

SUBSIDIARY

Subsidiary > customFieldList > customField

Example Use Case

Add a new Employee record in NetSuite using a Mule application; use Login Authentication.

NetSuiteDemoFlow

  1. Drag an HTTP connector into a new flow, and configure it as follows:

    netsuite_http

    Field Value

    Display Name

    HTTP (or any other name you prefer)

    config-ref

    Configure a global element with the desired host and port, we use 0.0.0.0 and 8081 respectively

    path

    /addEmployee

  2. Drag the NetSuite connector onto the canvas, then select it to open the properties editor console.

  3. Click the + sign next to the Connector Configuration field to add a new NetSuite global element.

    netsuite_demonetsuite1

  4. Configure the global element as follows:

    Field Value

    Name

    NetSuite (or any other name you prefer)

    Email

    <Your NetSuite Email>

    Password

    <Your NetSuite password>

    Account

    <Your NetSuite account>

    Role Id

    Enter the ID of the role you use to login in SuiteTalk, which determines the Processor privileges.

    Application Id

    Enter the application ID corresponding to the Integration record to be used (New in NetSuite Connector version 7.0.0).

  5. In the properties editor of the NetSuite connector, configure the remaining parameters:

    netsuite_addrecord

    Field Value

    Display Name

    NetSuite (or any other name you prefer)

    Config Reference

    NetSuite (name of the global element you have created)

    Operation

    Add record

    Record Type

    Employee

  6. Drag a Transform Message transformer before the NetSuite connector, then click the component to open its properties editor.

  7. Once metadata has been retrieved, select the respective fields to populate for the Employee.

  8. The DataWeave script in your Transform Message component should look similar to the following:

%dw 1.0
%output application/java
---
{
	email: inboundProperties."http.query.params".email,
	externalId:  inboundProperties."http.query.params".externalId,
	firstName:  inboundProperties."http.query.params".name,
	lastName:  inboundProperties."http.query.params".lastname,
	subsidiary: {
		internalId: 3
	}
}
  1. Add an Object to JSON transformer into the flow to capture the response from the NetSuite connector and display it as a HTTP response. 

  2. Run the project as a Mule Application (right-click the project name in the explorer, then select Run As > Mule Application ). 

  3. From a browser, enter the employee’s e-mail address, externalId, lastname, and name in the form of the following query parameters:  http://localhost:8081/addEmployee? email=<employee’s email address> &externalId=<employee’s externalId> &lastname= <employee’s last name>&name=<employee’s firstname> 

  4. Mule conducts the query, and adds the Employee record to NetSuite.

  1. Add a netsuite:config element to your project, then configure its attributes according to the  table below.

    
           
                   
                
    1
    2
    3
    
    &lt;netsuite:config-login-authentication name="NetSuite" email="email@youremail.com"
        password="netsuite_password" account="netsuite_account" roleId="netsuite_role"
        applicationId="netsuite_applicationId" doc:name="Netsuite"/&gt;
    Attribute Value

    name

    NetSuite

    email

    <Your NetSuite Email>

    password

    <Your NetSuite password>

    account

    <Your NetSuite account>

    roleId

    Enter the ID of the role you use to login in SuiteTalk, which determines the Processor privileges.

    Application Id

    Enter the application ID corresponding to the Integration record to be used (New in NetSuite Connector version 7.0.0).

    doc:name

    NetSuite

  2. Create a Mule flow with an HTTP endpoint, configuring the endpoint as follows:  

    
           
                   
                
    1
    
    &lt;http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="accountWithCustomFields" doc:name="HTTP"/&gt;
    Attribute Value

    exchange-pattern

    request-response

    host

    localhost

    port

    8081

    path

    accountWithCustomFields

    doc:name

    HTTP

  3. Add a Transform Message transformer to pass the message payload to NetSuite.

    
           
                   
                
    1
    
    &lt;dw:transform-message doc:name="Transform Message"/&gt;
  4. Add a netsuite:add-record element to your flow as follows:

    
           
                   
                
    1
    
    &lt;netsuite:add-record config-ref="Netsuite" doc:name="Netsuite Add Record" recordType="EMPLOYEE"/&gt;
  5. Configure the Transform Message through the Visual Editor. Switch the view to Message Flow view, then click the Transform Message transformer to set its properties.

  6. Once metadata is retrieved, select the respective fields to populate for the Employee.

  7. The script should look similar to the following:

%dw 1.0
%output application/java
---
{
	email: inboundProperties."http.query.params".email,
	externalId:  inboundProperties."http.query.params".externalId,
	firstName:  inboundProperties."http.query.params".name,
	lastName:  inboundProperties."http.query.params".lastname,
	subsidiary: {
		internalId: 3
	}
}
  1. Add a json:object-to-json-transformer element to the flow to capture the response from the NetSuite connector and display it as an HTTP response.

    
           
                   
                
    1
    
    &lt;json:object-to-json-transformer doc:name="Object to JSON"/&gt;
  2. Run the project as a Mule Application (right-click project name, then select Run As > Mule Application). 

  3. From a browser, enter the employee’s e-mail address, externalId, lastname, and name in the form of the following query parameters: http://localhost:8081/accountWithCustomFields ?email =<employee’s email address> &externalId=<employee’s externalId> &lname= <employee’s last name>&name=<employee’s firstname>

  4. Mule conducts the query, and adds the Employee record to NetSuite.

Example Use Case Code

Note that for this example code to work, you must manually configure the following values of the global element for your NetSuite connector to match your instance of NetSuite:

  • Email

  • Password

  • Account

  • Role ID

  • Application ID


         
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw" xmlns:netsuite="http://www.mulesoft.org/schema/mule/netsuite"
        xmlns:json="http://www.mulesoft.org/schema/mule/json"
        xmlns:http="http://www.mulesoft.org/schema/mule/http"
        xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
        xmlns:spring="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.mulesoft.org/schema/mule/netsuite http://www.mulesoft.org/schema/mule/netsuite/current/mule-netsuite.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/dw http://www.mulesoft.org/schema/mule/ee/dw/current/dw.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
        <netsuite:config-login-authentication name="NetSuite" email="suchi.deshpande@mulesoft.com" password="Mules0ft1!" account="TSTDRV1372796" roleId="3" applicationId="250FA966-3A66-4512-87C6-4AF27B929F49" doc:name="NetSuite: Login Authentication"/>
        <http:listener-config name="HTTP_Listener_Configuration" host="localhost" port="8081" doc:name="HTTP Listener Configuration"/>
        <flow name="netsuite-demoFlow" >
        <http:listener config-ref="HTTP_Listener_Configuration" path="/addEmployee" doc:name="HTTP"/>
                <dw:transform-message doc:name="Transform Message">
                        <dw:input-payload />
                        <dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
{
        email: inboundProperties."http.query.params".email,
        externalId:  inboundProperties."http.query.params".externalId,
        firstName:  inboundProperties."http.query.params".name,
        lastName:  inboundProperties."http.query.params".lastname,
        subsidiary: {
                internalId: 3
        }
}]]></dw:set-payload>
                </dw:transform-message>
                <netsuite:add-record config-ref="NetSuite" recordType="EMPLOYEE" doc:name="Netsuite Add Record"/><json:object-to-json-transformer doc:name="Object to JSON"/>
        </flow>
</mule>

Other Code Examples

Working with Asynchronous Operations

This code example demonstrates how to use async-add-list together with the check-async-statusget-async-result, and delete operations, using a custom record type.

Note that for this example code to work, you must use a custom record type of your own (or just a regular type), and manually configure the following values of the global NetSuite config to match your instance of NetSuite:

  • email

  • password

  • account

  • roleId

  • applicationId

netsuite_async1


          
       
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking"
        xmlns:dw="http://www.mulesoft.org/schema/mule/ee/dw" xmlns:netsuite="http://www.mulesoft.org/schema/mule/netsuite"
        xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:http="http://www.mulesoft.org/schema/mule/http"
        xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
        xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.mulesoft.org/schema/mule/netsuite http://www.mulesoft.org/schema/mule/netsuite/current/mule-netsuite.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
        <http:listener-config name="HTTP_Listener_Configuration"
                host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration" />
         
        <netsuite:config-login-authentication
                name="NetSuite__Login_Authentication" email="${netsuite.email}"
                password="${netsuite.password}" account="${netsuite.account}" roleId="${netsuite.roleId}"
                applicationId="${netsuite.applicationId}" doc:name="NetSuite: Login Authentication" />

         
        <flow name="asyncAddList" >
                    
                <http:listener config-ref="HTTP_Listener_Configuration"
                        path="/asyncAddList" doc:name="HTTP" />
                    
                <logger message="Process Started ..." level="INFO" doc:name="Logger" />
                    
                <netsuite:async-add-list config-ref="NetSuite__Login_Authentication"
                        recordType="__customRecordType__customrecordcustomaccount__22"
                        doc:name="Async Add List">
                                
                        <netsuite:records-attributes>
                                            
                                <netsuite:records-attribute>
                                                        
                                        <netsuite:inner-records-attribute
                                                key="externalId">addListExt1</netsuite:inner-records-attribute>
                                                        
                                        <netsuite:inner-records-attribute
                                                key="name">addListName1</netsuite:inner-records-attribute>
                                                    
                                </netsuite:records-attribute>
                                            
                                <netsuite:records-attribute>
                                                        
                                        <netsuite:inner-records-attribute
                                                key="externalId">addListExt2</netsuite:inner-records-attribute>
                                                        
                                        <netsuite:inner-records-attribute
                                                key="name">addListName2</netsuite:inner-records-attribute>
                                                    
                                </netsuite:records-attribute>
                                        
                        </netsuite:records-attributes>
                            
                </netsuite:async-add-list>
                    
                <set-variable variableName="jobId" value="#[payload.getJobId()]"
                        doc:name="Set Variable: jobId" />
                    
                <flow-ref name="check_async_status" doc:name="Check Async Status" />
        </flow>
         
        <sub-flow name="check_async_status" >
                    
                <logger message="===== Checking status for jobId: #[flowVars.jobId] ====="
                        level="INFO" doc:name="Logger" />
                    
                <until-successful maxRetries="180"
                        failureExpression="#[payload.getStatus() == com.netsuite.webservices.platform.core.types.AsyncStatusType.PENDING || payload.getStatus() == com.netsuite.webservices.platform.core.types.AsyncStatusType.PROCESSING]"
                        synchronous="true" doc:name="Until Successful" millisBetweenRetries="10000">

                                
                        <processor-chain doc:name="Processor Chain">
                                            
                                <netsuite:check-async-status config-ref="NetSuite__Login_Authentication"
                                        jobId="#[flowVars.jobId]" doc:name="Check Async Status" />
                                            
                                <logger message="Status is: #[payload.getStatus()]" level="INFO"
                                        doc:name="Status" />
                                        
                        </processor-chain>
                            
                </until-successful>
                    
                <choice doc:name="Choice">
                                
                        <when
                                expression="#[payload.getStatus() == com.netsuite.webservices.platform.core.types.AsyncStatusType.FINISHED]">
                                            
                                <logger message="Records have been added successfully."
                                        level="INFO" doc:name="FINISHED" />

                                        
                        </when>
                                
                        <otherwise>
                                            
                                <logger
                                        message="An error has been encountered for jobId: #[flowVars.jobId] Navigate to Setup &gt; Integration &gt; Web Services Process Status on your sandbox for more information."
                                        level="ERROR" doc:name="FAILED / FINISHED_WITH_ERRORS" />

                                        
                        </otherwise>
                            
                </choice>
        </sub-flow>
         
        <sub-flow name="get_async_result" >
                    
                <http:listener config-ref="HTTP_Listener_Configuration"
                        path="/getAsyncResult" doc:name="HTTP" />
                    
                <set-variable variableName="jobId"
                        value="#[message.inboundProperties.'http.query.params'.jobId]"
                        doc:name="Set Variable: jobId" />
                    
                <logger message="===== Results for jobId: #[flowVars.jobId] ====="
                        level="INFO" doc:name="Logger" />
                    
                <netsuite:get-async-result config-ref="NetSuite__Login_Authentication"
                        jobId="#[flowVars.jobId]" doc:name="Get Async Result" />
                    
                <set-payload value="#[payload.getWriteResponseList().getWriteResponse()]"
                        doc:name="Get Response List" />
                    
                <foreach doc:name="For Each">
                                
                        <logger
                                message="Custom record with externalId: #[payload.getBaseRef().getExternalId()] and typeId: #[payload.getBaseRef().getTypeId()] ... Deleting it!"
                                level="INFO" doc:name="Result Info" />
                                
                        <netsuite:delete config-ref="Netsuite" doc:name="Delete">
                                            
                                <netsuite:base-ref type="CUSTOM_RECORD_REF" externalId="#[payload.getBaseRef().getExternalId()]">
                                                        
                                        <netsuite:specific-fields>
                                                                    
                                                <netsuite:specific-field key="typeId">#[payload.getBaseRef().getTypeId()]</netsuite:specific-field>
                                                                
                                        </netsuite:specific-fields>
                                                    
                                </netsuite:base-ref>
                                        
                        </netsuite:delete>
                            
                </foreach>
                    
                <logger message="Process Complete" level="INFO" doc:name="Logger" />
        </sub-flow>
</mule>

Code Description

  1. netsuite:config-login-authentication is the NetSuite global configuration.

  2. The first flow, labeled "asyncAddList" is triggered via an HTTP request.

  3. netsuite:async-add-list provides the configuration for the async-add-list operation showing externalIds and names we defined for the custom record.

  4. Store the jobId returned from the async-add-list operation in a flow variable called "jobId". See set-variable.

  5. Calls a sub-flow named "check_async_status" that monitors the status of the async process.

  6. The until-successful block queries NetSuite using the check-async-result operation to see whether the async job is finished or pending/processing. This loops for a number of defined retries and resumes control of the flow after the condition is satisfied.

  7. A choice router directs the message based on whether the async operation finished successfully or not.

  8. Displays a message in the console notifying that the async process is successful.

  9. Displays a message in the console if it has failed.

  10. The second flow is also triggered via an HTTP request, passing the jobId as a query parameter.

  11. Uses the get-async-result operation to obtain the result for the async process using the jobId that is saved.

  12. Extracts the response list from the AsyncResult object.

  13. For each result list item, logs some details and delete the record we added.

  14. Removes the custom records that are just added from the NetSuite sandbox using their externalId.

Using the Search Operation

In NetSuite, the search operation can be used to execute a Basic Search, Joined Search or an Advanced Search. To this end, you need to instantiate one of these three search types for the record type you want to query:

<Record>SearchBasic

Used to execute a search on a record type based on search filter fields that are specific to that type.

<Record>Search

Used to execute a search on a record type based on search filter fields specific to that type and others that are associated with a related record type.

<Record>SearchAdvanced

Used to execute a search on a record type in which you specify search filter fields and/or search return columns or joined search columns. Using advanced search, you can also return an existing saved search.

This also applies for the asynchronous equivalent of search, the asyncSearch operation.

Search Pagination Support

Support for pagination was added to search for NetSuite connector version 7.0.0.

The connector’s search capability is now unified under one operation. Other search-related processors have been removed. Thus, search will always retrieve the whole set of results. Therefore users will not need to work with searchNext or searchMore in order to get the rest of the records from subsequent pages. The return type is also different; the processor will output a List of Maps representing each and every record obtained by your search criteria.

An important aspect to note is that pagination could not be applied to the asynchronous equivalent of search (asyncSearch). This is due to the fact that the actual pagination would have to be applied to the getAsyncResult operation. This would mean that only the first page would end up being retrieved asynchronously. Furthermore, getAsyncResult is common to all async operations. Hence we cannot even apply pagination here since the return type of this operation depends on what async operation was invoked.

Regarding the new search configuration, the connector is the same apart from a new attribute called fetchSize:


           
        
1
<netsuite:paged-search config-ref="NetSuite__Login_Authentication" searchRecord="CUSTOMER_BASIC" fetchSize="5" doc:name="Customer Basic Search"/>

ItemSearchAdvanced and returnSearchColumns

When using search, the connector outputs a list of maps representing the Record objects returned by your search operation. If using an advanced search and the returnSearchColumns flag is set to true, NetSuite returns a SearchRowList containing the search results.

However, in the case of ItemSearchAdvanced the connector does not do this mapping and simply provides the user with the SearchRows. This is the case due to the fact that ITEMs in NetSuite can be of various types and we cannot assume the item type from an ItemSearchRow. This issue would also occur with any other record type that behaves similar to ITEM, but we are currently not aware of others.

For this example, we set up a basic search operation for Customers (CustomerSearchBasic) with the criteria below:

  • companyName starts with "A".

  • The customer is not an individual.

  • The customer has a priority of 50, which is handled by a customField.

Below is the Studio flow and the corresponding code:

netsuite_basic_search


           
        
1
2
3
4
5
6
7
8
9
10
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
 
<netsuite:config-login-authentication name="NetSuite__Login_Authentication" email="${netsuite.email}" password="${netsuite.password}" account="${netsuite.account}" roleId="${netsuite.roleId}" applicationId="${netsuite.applicationId}" doc:name="NetSuite: Login Authentication"/>
 
<flow name="customer-basic-search">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/basicSearch" doc:name="HTTP"/>
    <component class="CustomerBasicSearchComponent" doc:name="Create Customer Search Basic criteria"/>
    <netsuite:search config-ref="NetSuite__Login_Authentication" searchRecord="CUSTOMER_BASIC" fetchSize="5" doc:name="Customer Basic Search"/>
    <json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>

Java Component Code


           
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class CustomerBasicSearchComponent implements Callable {
 
    @Override
    public Object onCall(MuleEventContext eventContext) throws Exception {
        CustomerSearchBasic searchCriteria = new CustomerSearchBasic();
 
        SearchStringField companyNameFilter = new SearchStringField();
        companyNameFilter.setOperator(SearchStringFieldOperator.STARTS_WITH);
        companyNameFilter.setSearchValue("A");
        searchCriteria.setCompanyName(companyNameFilter);
 
        SearchBooleanField isPersonFilter = new SearchBooleanField();
        isPersonFilter.setSearchValue(false);
        searchCriteria.setIsPerson(isPersonFilter);
 
        SearchCustomFieldList customFieldListFilter = new SearchCustomFieldList();
        List<SearchCustomField> customFieldList = new ArrayList<SearchCustomField>();
        SearchLongCustomField priority = new SearchLongCustomField();
        priority.setScriptId("custentity_cust_priority");
        priority.setOperator(SearchLongFieldOperator.EQUAL_TO);
        priority.setSearchValue(50l);
        customFieldList.add(priority);
        customFieldListFilter.setCustomField(customFieldList);
        searchCriteria.setCustomFieldList(customFieldListFilter);
 
        return searchCriteria;
    }
 
}

This example here searches for all inventory items with a pricing join (ItemSearch) where the price rate is of 10.00.
The search criteria is set within a custom Java component.

netsuite_joined_search


           
        
1
2
3
4
5
6
<flow name="item-search-pricing-join">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/joinedSearch" doc:name="HTTP"/>
    <component class="ItemSearchPricingJoinComponent" doc:name="Create Item Search Pricing Join criteria"/>
    <netsuite:search config-ref="NetSuite__Login_Authentication" searchRecord="ITEM" doc:name="Item Search Pricing Join"/>
    <json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>

Java Component Code


           
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ItemSearchPricingJoinComponent implements Callable {
 
    @Override
    public Object onCall(MuleEventContext eventContext) throws Exception {
        ItemSearch searchCriteria = new ItemSearch();
 
        ItemSearchBasic basicCriteria = new ItemSearchBasic();
        SearchEnumMultiSelectField typeFilter = new SearchEnumMultiSelectField();
        List<String> typeList = new ArrayList<String>();
        typeList.add("_inventoryItem");
        typeFilter.setOperator(SearchEnumMultiSelectFieldOperator.ANY_OF);
        typeFilter.setSearchValue(typeList);
        basicCriteria.setType(typeFilter);
        searchCriteria.setBasic(basicCriteria);
 
        PricingSearchBasic pricingJoinCriteria = new PricingSearchBasic();
        SearchDoubleField rateFilter = new SearchDoubleField();
        rateFilter.setOperator(SearchDoubleFieldOperator.EQUAL_TO);
        rateFilter.setSearchValue(10.00d);
        pricingJoinCriteria.setRate(rateFilter);
        searchCriteria.setPricingJoin(pricingJoinCriteria);
 
        return searchCriteria;
    }
 
}

The example constructs a simple Java component that creates a criteria to get the result of an Employee saved search in our NetSuite environment (EmployeeSearchAdvanced). Each saved search in NetSuite has a particular id. Here, we use the scriptId customsearch130.

netsuite_code_example_search_advanced


           
        
1
2
3
4
5
6
<flow name="employee-search-advanced-saved-search">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/advancedSearch" doc:name="HTTP"/>
    <component class="EmployeeSearchAdvancedSavedComponent" doc:name="Create Employee Search Advanced Saved Search criteria"/>
    <netsuite:search config-ref="NetSuite__Login_Authentication" searchRecord="EMPLOYEE_ADVANCED" doc:name="NetSuite"/>
    <json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>

Java Component Code


           
        
1
2
3
4
5
6
7
8
9
10
11
12
public class EmployeeSearchAdvancedSavedComponent implements Callable {
 
    @Override
    public Object onCall(MuleEventContext eventContext) throws Exception {
        EmployeeSearchAdvanced searchCriteria = new EmployeeSearchAdvanced();
 
        searchCriteria.setSavedSearchScriptId("customsearch130");
 
        return searchCriteria;
    }
 
}

NetSuite and DataWeave

The NetSuite connector’s DataSense capability coupled with that of DataWeave via the Transform Message component makes integrating with your NetSuite environment straightforward. For the following two examples, we use a JSON input string and extract the necessary data from it to form our NetSuite request.

  1. This example code adds a Journal Entry to NetSuite from the following JSON input:

    
                 
              
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    
    {
       "tranId":"SampleJournal123",
       "subsidiary":{
          "internalId":"1"
       },
       "customFieldList":{
          "customField":[
             {
                "StringCustomFieldRef__custbodytestbodyfield":"Sample Transaction Body Custom Field"
             }
          ]
       },
       "lineList":{
          "line":[
             {
                "account":{
                   "internalId":"1"
                },
                "debit":100.0,
                "customFieldList":{
                   "customField":[
                      {
                         "SelectCustomFieldRef__custcol_far_trn_relatedasset":{
                             "internalId":"1"
                         }
                      },
                      {
                         "StringCustomFieldRef__custcoltestcolumnfield": "Sample Transaction Column Custom Field 1"
                      }
                   ]
                }
             },
             {
                "account":{
                   "internalId":"1"
                },
                "credit":100.0,
                "customFieldList":{
                   "customField":[
                      {
                         "SelectCustomFieldRef__custcol_far_trn_relatedasset":{
                             "internalId":"2"
                         }
                      },
                      {
                         "StringCustomFieldRef__custcoltestcolumnfield": "Sample Transaction Column Custom Field 2"
                      }
                   ]
                }
             }
          ]
       }
    }

    The "add" operation for the connector expects a Map as input. The DataWeave script looks as follows:

    netsuite_dataweave1

  2. In this example, we use the same scenario for basic search as described in the previous section. However, instead of constructing the criteria in a java component, we transform a JSON string:

    
                 
              
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    {
       "companyName": {
          "operator": "STARTS_WITH",
          "searchValue": "A"
       },
       "isPerson": false,
       "priority": {
          "operator": "EQUAL_TO",
          "searchValue": 50
       }
    }

    netsuite_code_example_dataweave02

See Also