This article is relevant if you are a SuiteScript developer working to program NetSuite against the purchase order record.
Background
Our firm has developed refined algorithms for processing purchase orders in our client environments. Since 2016, one of the most significant breakthroughs we produced as an Accelerator Template is the pattern to drive item-level gross margin on dropship transaction types. See my related article, Solved: NetSuite Drop Ship Purchase Accruals and Learn how to Reliably Measure NetSuite Gross Profit and Margin.
However, programmers may discover that when NetSuite automatically generates a linked Purchase Order from a Sales Order for either a drop ship or a special order, they are not getting the standard record user events for BeforeLoad or BeforeSubmit. This is one of the nuances of the NetSuite platform. The general phenomenon is that when one record event is executing, if during that execution, you create another NetSuite record, it will not fire user events on that new record.
Yet, in the case of the drop ship or special order, we can get an AfterSubmit event. Let’s review the pattern.
Dropship and Special Order Purchase Order NetSuite UserEvents
When working with NetSuite, dropship and special order purchase orders introduce nuances that can trip up developers relying on standard UserEvent Script triggers. A common frustration is that the beforeLoad
and beforeSubmit
functions do not execute when these purchase orders are automatically created from dependent transactions (e.g., Sales Orders). However, the afterSubmit
function does execute, providing a vital entry point for processing.
For SuiteScript developers, understanding the execution context and adapting to it is key. The challenge lies in accurately detecting the transaction type (dropship
or specialorder
) and ensuring proper handling within the script logic. The context
parameter is central to this, containing critical information like context.type
, which identifies the triggering event.
In SuiteScript 2.x, we leverage structured enums like context.UserEventType
to handle these scenarios, while SuiteScript 1.x relies on custom logic and direct field values to accomplish similar goals. Below, we discuss both approaches and how they can work to address the concern.
A this point, I would like to thank Sean G., and Boban D., on the team as they pointed out these considerations in previous client work.
SuiteScript 2.x: Embracing Enumerations and Modern Patterns
SuiteScript 2.x provides a structured, modular approach to coding. The key is to explicitly check for context.type
values that represent dropship
or specialorder
events alongside the typical create
event.
Here’s how we adapt to this scenario in SuiteScript 2.x:
define(['N/record'], function(record) {
function afterSubmit(context) {
if (context.type === context.UserEventType.CREATE ||
context.type === context.UserEventType.DROPSHIP ||
context.type === context.UserEventType.SPECIALORDER) {
var poRecord = context.newRecord;
log.debug('Triggered afterSubmit for a special purchase order', poRecord.id);
// Custom logic for handling dropship or special order POs
if (poRecord.getValue({ fieldId: 'specord' })) {
log.debug('Special order processing required.');
// Additional processing
}
}
}
return {
afterSubmit: afterSubmit
};
});
SuiteScript 1.x: Adapting Legacy Logic with Custom Checks
SuiteScript 1.x, while less structured, is still adequate for addressing the issue. It involves custom logic to check the type
parameter and relevant field values, such as specord
, to identify drop ship and special order events.
Here’s the equivalent logic in SuiteScript 1.x:
function afterSubmit(type, rec) {
var recordType = rec.getRecordType();
if ((recordType === 'purchaseorder' && type === 'specialorder') ||
(type === 'create' && rec.getFieldValue('specord'))) {
nlapiLogExecution('DEBUG', 'Triggered afterSubmit for special purchase order', rec.getId());
// Custom processing for special orders
if (rec.getFieldValue('specord')) {
nlapiLogExecution('DEBUG', 'Special order processing required.');
// Additional processing
}
}
}
This approach relies on manually comparing the type
parameter and inspecting field values to identify the transaction type. While less elegant than the 2.x method, it is equally effective for handling these scenarios in older scripts.
Getting NetSuite Under Your Control
When thinking about challenges in the NetSuite ERP system, it’s always important to remember that it is a software system, and we can overcome almost any limitation. Developing good judgment about the implications of any adaptation or enhancement is valuable. Just because we can do something does not mean we should. In this case, we may have thought, “It does not fire events.” and would have given up or perhaps created another less-than-ideal workaround. Yet, it is important to keep pushing our understanding so that we can give our business community what it demands.
If you found this article relevant, feel free to sign up for notifications to new articles as I post them. If you would like to work with a high-caliber team that focuses on merit, innovation, accomplishment and appreciation, let’s have a conversation.