Calculate Commission on Sales Orders
This customization calculates a custom commission amount when a sales order is saved. The calculated commission amount is displayed in a custom field on the sales order record. The commission is based on each item included in the sales order: MSRP, net distributor costs (MSRP * 0.5), and the price sold to the customer.
NetSuite has an Employee Commissions feature, but this customization calculates and sets a simple custom commission amount in a custom field without using the feature. For more information about the Employee Commissions feature, which can calculate commission for employees with different schedules and methods of calculation, see Commissions.
This project is available on the SuiteCloud Project Repository on Oracle Samples GitHub. It includes the complete project customization setup with custom objects, unit tests, package file configuration, and more.
Customization Details
The customization for this use case includes:
-
A custom field (MSRP) to store the MSRP for an item
-
A custom field (Custom Commission) to store the calculated commission
-
A user event script triggered on the afterSubmit entry point
Steps in this tutorial to complete this customization:
Before You Begin
The following table lists features, permissions, and other requirements necessary for performing this tutorial and implementing the solution:
Required Features |
The following features must be enabled in your account:
For more information, see Enabling Features. |
Required Permissions |
You need a role with access to the following:
For more information, see NetSuite Permissions Overview. |
Other Requirements |
None |
Step 1: Create the Custom Fields
This customization uses two custom fields. The Calculated Commission field stores the calculated commission when the sales order is saved. It is a transaction body field added to the sales order record. The MSRP field is displayed on the Items sublist of a sales order and stores the MSRP value for an item. It's a transaction line field added to the sales order record.
To create the custom Calculated Commission field:
-
Go to Customization > Lists, Records, Fields > Transaction Body Fields > New and enter the following values:
Field
Value
Label
Calculated Commission
ID
_commission_amount
Type
Currency
Store Value
Checked
Applies To
Sale
Display
Subtab: Main
-
Click Save.
To create the custom MSRP field:
-
Go to Customization > Lists, Records, Fields > Transaction Line Fields > New and enter the following values:
Field
Value
Label
MSRP
ID
_salesorder_msrp
Type
Currency
Store Value
Checked
Applies To
Sale Item
-
Click Save.
For more information about creating custom components, see the following help topics:
Step 2: Write the Script
This script calculates a custom commission amount when a sales order is saved. The calculated commission amount is displayed in a custom field on the sales order record. The commission is based on the sum of commission amounts for each item in the sales order: MSRP, the net distributor costs (MSRP * 0.5), and the price sold to the customer.
Script Summary
The following table summarizes the script:
Script: Calculate Commission |
|
---|---|
Script Type |
|
Modules Used |
|
Entry Points |
For more information about script types and entry points, see SuiteScript 2.x Script Types.
The Complete Script
This tutorial includes the complete script along with individual steps you can follow to build the script in logical sections. The complete script is provided below so that you can copy it, paste it into your text editor, and save it as a .js file (for example, ue_calculateCommission.js).
If you'd rather create your script step by step, follow the steps in Build the Script.
This tutorial script uses the define
function, which is required for an entry point script (a script you attach to a script record and deploy). If you want to copy the script into the SuiteScript Debugger and test it, you must use the require
function. For more information, see SuiteScript Debugger.
This sample uses SuiteScript 2.1. For more information, see SuiteScript 2.1.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
* @NModuleScope SameAccount
*/
define(['N/record', 'N/log'], (record, log) => {
function afterSubmit(scriptContext) {
const stMethodName = 'afterSubmit_calculateCommission';
try {
if (scriptContext.type !== scriptContext.UserEventType.CREATE && scriptContext.type !== scriptContext.UserEventType.EDIT) {
return;
}
let stItemType = null;
let flMSRPTotalAmt = 0.00;
let flMSRPAmt = 0.00;
let flNetDistributorCost = 0.00;
let flCommissionAmount = null;
let flQuantity = 0.00;
const recSalesOrder = scriptContext.newRecord;
let flSubtotal = parseFloat(recSalesOrder.getValue({
fieldId: 'subtotal'
}));
const numItems = recSalesOrder.getLineCount({
sublistId: 'item'
});
for (let intLinenum = 0; intLinenum < numItems; intLinenum++) {
flMSRPAmt = parseFloat(recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'custcol_salesorder_msrp',
line: intLinenum
}));
flQuantity = parseFloat(recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'quantity',
line: intLinenum
}));
stItemType = recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'itemtype',
line: intLinenum
});
if (stItemType !== 'Discount' && stItemType !== 'Subtotal' && stItemType !== 'Markup') {
flMSRPTotalAmt = flMSRPTotalAmt + (flMSRPAmt * flQuantity);
}
}
flNetDistributorCost = flMSRPTotalAmt * 0.5;
if (flSubtotal === flNetDistributorCost) {
flCommissionAmount = flSubtotal * 0.10;
} else if ((flSubtotal > flNetDistributorCost) && (flSubtotal <= flMSRPTotalAmt)) {
flCommissionAmount = flNetDistributorCost * 0.10 + (flSubtotal - flNetDistributorCost) * 0.75;
} else {
if (flSubtotal > flMSRPTotalAmt) {
flCommissionAmount = flNetDistributorCost * 0.10 + (flMSRPTotalAmt - flNetDistributorCost) * 0.75 + (flSubtotal - flMSRPTotalAmt) * 0.5;
}
}
const thisSalesOrderID = recSalesOrder.id;
const updateSalesOrder = record.load({
type: record.Type.SALES_ORDER,
id: thisSalesOrderID
});
updateSalesOrder.setValue({
fieldId: 'custbody_commission_amount',
value: flCommissionAmount
});
const updateSalesOrderID = updateSalesOrder.save();
} catch(e) {
log.debug({
title: stMethodName,
details: ' - Exit (Catch)- '
});
if (e.getDetails !== undefined) {
log.error({
title: 'Process Error',
details: JSON.stringify(e)
});
throw e;
} else {
log.error({
title: 'Unexpected Error',
details: JSON.stringify(e)
});
throw error.create({
name: 'Unexpected Error',
message: JSON.stringify(e)
});
}
}
}
return {
afterSubmit: afterSubmit
};
});
Build the Script
You can write the script using a step-by-step approach that includes the following:
The code snippets included below don't include indentation. Refer to The Complete Script for suggested formatting.
Start with required opening lines
You need JSDoc comments and a define
function at the top of the script file. The JSDoc comments in this script indicate that it's a SuiteScript 2.x (2.0 or 2.1) user event script. The script uses two SuiteScript modules specified in the define
statement:
-
N/record
– provides access to the sales order record -
N/log
– lets you log execution details
Start a new script file using any text editor and add the following JSDoc comments and define
function at the top of the file:
This tutorial script uses the define
function, which is required for an entry point script (a script you attach to a script record and deploy). If you want to copy the script into the SuiteScript Debugger and test it, you must use the require
function. For more information, see SuiteScript Debugger.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
* @NModuleScope SameAccount
*/
define(['N/record', 'N/log'], (record, log) => {
});
Create the entry point function
This script is triggered on the afterSubmit
entry point when a sales order is saved. A try-catch block logs any errors that might occur during script execution. Most of the script code is placed in the try block.
Add the following function definition and initial try-catch block statements at the top of the define
function:
function afterSubmit(scriptContext) {
const stMethodName = 'afterSubmit_calculateCommission';
try {
} catch(e) {
log.debug({
title: stMethodName,
details: ' - Exit (Catch)- '
});
if (e.getDetails !== undefined) {
log.error({
title: 'Process Error',
details: JSON.stringify(e)
});
throw e;
} else {
log.error({
title: 'Unexpected Error',
details: JSON.stringify(e)
});
throw error.create({
name: 'Unexpected Error',
message: JSON.stringify(e)
});
}
}
}
Check the scriptContext
You want this script to run only when the user creates or edits a sales order.
Add the following code at the top of the try block:
if (scriptContext.type !== scriptContext.UserEventType.CREATE && scriptContext.type !== scriptContext.UserEventType.EDIT) {
return;
}
Initialize variables
This script uses several variables to store the type, quantity, MSRP, net distributor cost for each item, the sum of all MSRP amounts, and the calculated commission amount. You need to initialize these variables.
Add the following code into the try block:
let stItemType = null;
let flMSRPTotalAmt = 0.00;
let flMSRPAmt = 0.00;
let flNetDistributorCost = 0.00;
let flCommissionAmount = null;
let flQuantity = 0.00;
Get the subtotal from the sales order record
You want to get the subtotal from the record to calculate the commission.
Add the following code into the try block:
const recSalesOrder = scriptContext.newRecord;
let flSubtotal = parseFloat(recSalesOrder.getValue({
fieldId: 'subtotal'
}));
Process items on the sales order
You need to process each item on the sales order needs by getting the MSRP, quantity, and type for the item. Then, you make sure the it's not a discount, markup, or subtotal item since those types of items aren't used to calculate the commission. To process the items, add code for the following:
To begin, add the following code into the try block:
const numItems = recSalesOrder.getLineCount({
sublistId: 'item'
});
for (let intLinenum = 0; intLinenum < numItems; intLinenum++) {
}
Get the item MSRPs
Now, you get the MSRP for each item.
Add the following code as the first statement inside the for
block:
flMSRPAmt = parseFloat(recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'custcol_salesorder_msrp',
line: intLinenum
}));
Get the item quantity and type
And you get the item quantity and the item type.
Add the following code into the for
block:
flQuantity = parseFloat(recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'quantity',
line: intLinenum
}));
stItemType = recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: 'itemtype',
line: intLinenum
});
Calculate the MSRP for all items that are not discount, markup, or subtotal items
This script sums all item MSRPs to calculate the total MSRP, but doesn't include discount, markup, and subtotal items.
Add the following code into the for
block:
if (stItemType !== 'Discount' && stItemType !== 'Subtotal' && stItemType !== 'Markup') {
flMSRPTotalAmt = flMSRPTotalAmt + (flMSRPAmt * flQuantity);
}
Calculate the net distributor cost
Now, calculate the net distributor cost. You'll use this to calculate the commission.
Add the following code after the end of the for
block, inside the try block:
flNetDistributorCost = flMSRPTotalAmt * 0.5;
Calculate the commission amount
You need to calculate the commission amount for the entire sales order. The commission is based on the sum of commission amounts for each item: MSRP, net distributor costs (MSRP * 0.1), and the price sold to the customer.
Add the following code into the try block:
if (flSubtotal === flNetDistributorCost) {
flCommissionAmount = flSubtotal * 0.10;
} else if ((flSubtotal > flNetDistributorCost) && (flSubtotal <= flMSRPTotalAmt)) {
flCommissionAmount = flNetDistributorCost * 0.10 + (flSubtotal - flNetDistributorCost) * 0.75;
} else {
if (flSubtotal > flMSRPTotalAmt) {
flCommissionAmount = flNetDistributorCost * 0.10 + (flMSRPTotalAmt - flNetDistributorCost) * 0.75 + (flSubtotal - flMSRPTotalAmt) * 0.5;
}
}
Set the commission amount on the sales order
Finally, set the final commission amount in the custom Commission Amount field on the header of the sales order record.
Add the following code into the try block:
const thisSalesOrderID = recSalesOrder.id;
const updateSalesOrder = record.load({
type: record.Type.SALES_ORDER,
id: thisSalesOrderID
});
updateSalesOrder.setValue({
fieldId: 'custbody_commission_amount',
value: flCommissionAmount
});
Save the sales order
After you set the commission amount, you want to save the sales order.
Add the following code into the try block:
const updateSalesOrderID = updateSalesOrder.save();
Create the return statement
This script associates the afterSubmit
function with the afterSubmit
user event script entry point.
Add the following code immediately above the closing });
in your script:
return {
afterSubmit: afterSubmit
};
Save your script file
You need to save your script file so you can load it to the NetSuite File Cabinet. Before you save your script file, you may want to adjust the indentation to improve the readability of the script. Refer to The Complete Script for suggested formatting.
When you are happy with your script, save it as a .js file (for example, ue_calculateCommission.js).
Step 3: Create the Script Record
Now that you’ve completed the script, you can upload it to the File Cabinet and create a script record for it.
For more information about creating script records, see Creating a Script Record.
To create the script record:
-
Upload your script to the NetSuite File Cabinet.
-
Go to Customization > Scripting > Scripts > New.
-
Select your script from the Script File list and click Create Script Record. The Script page is displayed.
-
On the Script page, enter the following values:
Field
Value
Name
Calculate Commission
ID
_ue_calculate_commission
NetSuite prefixes the ID with customscript.
Description
This script calculates a custom commission based on each item in a sales order.
-
Set any other fields on the script record as required.
-
Click Save and Deploy. The Script Deployment page appears. Continue with Step 4: Deploy the Script.
Step 4: Deploy the Script
After you create the script record, you can create a script deployment record for it. A script deployment record determines how, when, and for whom the script runs.
For more information about script deployment records, see Script Deployment.
To deploy the script:
-
Complete the steps in Step 3: Create the Script Record.
-
On the Script Deployment page, enter the following values:
Field
Value
Applies To
Sales Order
ID
_ue_calculate_commission
NetSuite prefixes the ID with custdeploy.
Status
Testing
The Testing status lets the script owner test the script without affecting other users in the account.
Log Level
Debug
The Debug level writes all
log.debug
statements and errors to the Execution Log tab of the script deployment record.Audience > Roles
Check Select All
-
Click Save.
Step 5: Test the Solution
After you create the script record and deploy your script, you can test it by creating a new sales order with several items.
To test the solution:
-
Go to Transaction > Sales > Enter Sales Orders to create a new sales order.
-
In the Custom Form field, select the Standard Sales Order form. The custom fields appear on all standard and custom sales order forms, but for this tutorial you can use the standard form.
-
Add multiple items to the sales order and set a value in the MSRP field for each item.
-
Fill out all other required fields.
-
Save the sales order.
-
Review the sales order and verify the calculated commission in the Calculated Commission field.
Related Topics
- SuiteCloud Customization Tutorials
- Add Custom Button to Execute a Suitelet
- Copy a Value to the Item Column
- Disable Tax Fields
- Hide a Column in a Sublist
- Populate Item Substitution
- Set a Default Posting Period in a Custom Field
- Set Purchase Order Exchange Rate
- Set the Item Amount to Zero for Marketing Orders
- Set Default Values in a Sublist
- Track Customer Deposit Balances
- Validate Order on Entry