| Layer | Status | Summary |
|---|---|---|
| User Event scripts (form open / save) | MEDIUM | 6 active UEs run beforeLoad on every open; 4 of 6 have hidden source (bundle-protected) and could not be code-reviewed. |
| Client scripts (open / per-line) | CRITICAL | 7 active client scripts; Packship CS runs uncached N/query round-trips on pageInit and fieldChanged. |
| Workflows | GOOD | Zero active workflows initiate on Sales Order create/view/update. |
| Custom field surface | MEDIUM | 56 custom fields visible on SO (31 body, 25 line-level; 15 sourced line fields interact with client-script events). |
| Execution-log heat | LIMITED | No scriptnote entries exist for the 13 SO scripts — log evidence unavailable (levels above DEBUG or purged). |
| Bundle footprint | MEDIUM | 4 bundles contribute 9 of 13 deployments; several are shipping/fulfillment features running on the sales-entry hot path. |
This audit followed the Sonar Transaction Entry Performance Audit protocol, six phases, all read-only:
scriptdeployment ⋈ script for recordtype='SALESORDER'.customfield rows whose visibleontransactions includes SalesOrd.scriptnote volumes for the Phase-1 script ids.script.frombundle + API version per script.Every claim is tagged: MEASURED backed by account data · OBSERVED seen in actual source code · HYPOTHESIS plausible, unconfirmed, with the confirming step stated.
| Item | Value |
|---|---|
| Account / environment | TD3016323 — PRODUCTION |
| OneWorld | Yes (multi-subsidiary; multi-currency OFF) |
| Relevant features | Inventory, Multi-Location Inventory, Matrix Items, Work Orders, Advanced Printing, CRM, Estimates |
| Auditing role | Role id 3 (broad read access; some bundle files inaccessible — see Concerns) |
13 active deployments (status RELEASED, isdeployed=T) on Sales Order. All 13 are deployed to all roles (allroles=T). Two further deployments exist but are switched off (ATB_UE_SalesOrder, Packship Non-Adv-Inventory UE) — correctly excluded from cost.
| Script | scriptid | Type | API | Bundle | Cost moment |
|---|---|---|---|---|---|
| ATB_CS_SalesOrder | customscript_atb_cs_salesorder | CLIENT | 2.1 | — (custom) | open, per-line (validateLine) |
| Item Substitute Transactions CS | customscript_scm_is_transactions_cs | CLIENT | 2.0 | 47193 | open, per-line |
| LRC Field Manager Client Script | customscript_lrc_field_manager_cs | CLIENT | 2.1 | — (custom) | fieldChanged (subsidiary only) |
| Packship — Process on IF Order CS | customscript_packship_cs_order_ifprocess | CLIENT | 2.1 | 534418 | open + fieldChanged (queries!) |
| SCM Transactions CS | customscript_scm_cpn_cs_transactions | CLIENT | 1.0 | 47193 | open, per-field |
| STE CS Transaction | customscript_ste_cs_transaction | CLIENT | 2.0 | 237702 (tax engine) | open, per-line, save |
| USR CS Transaction | customscript_usr_cs_transaction | CLIENT | 2.1 | — (minified) | unknown (minified) |
| Item Substitute Transactions UE | customscript_scm_is_transactions_ue | USEREVENT | 2.0 | 47193 | open, save — source hidden |
| LRC Field Manager User Event | customscript_lrc_field_manager_ue | USEREVENT | 2.1 | — (custom) | open (light) |
| RAC UE Sales Order Record | customscript_rac_ue_so_record | USEREVENT | 2.0 | 266623 | open, save — source hidden |
| SCM Transactions UE | customscript_scm_cpn_ue_transactions | USEREVENT | 1.0 | 47193 | open, save — source hidden |
| STE UE Transaction | customscript_ste_ue_transaction | USEREVENT | 2.0 | 237702 (tax engine) | open, save |
| USR UE Transaction | customscript_usr_ue_transaction | USEREVENT | 2.1 | — | open, save — source hidden |
pageInit calls disableOrEnableProcessShipmentOnIFFlag(), which calls getShipCentralPreference() — a full N/query execution against customrecord_packship_shippreference (~20 columns, several with FieldContext.DISPLAY, each a joined lookup) — from the browser, synchronously, on every sales order open. The same routine re-runs on every change to shipmethod, subsidiary, or location, and each shipmethod evaluation triggers a second query (getMigrationCarrierOrNot → fetchDataFromQuery). No result caching anywhere.
File 24196, lines 8–14:
const pageInit = (scriptContext) => {
disableOrEnableProcessShipmentOnIFFlag(scriptContext); // ← query on EVERY open
}
const fieldChanged = (scriptContext) => {
if(['shipmethod', 'subsidiary', 'location'].includes(scriptContext.fieldId))
disableOrEnableProcessShipmentOnIFFlag(scriptContext); // ← query again
File 24196, lines 149–150, 243:
const getShipCentralPreference = () => {
var shipPrefQuery = query.create({ type: 'customrecord_packship_shippreference' });
...
return shipPrefQuery.run().asMappedResults(); // ← uncached round-trip
Remediation: cache the preference result in a module-scope variable after the first fetch (preferences don't change mid-session). Because this is managed-bundle code, the fix is a vendor request; the immediate mitigation is narrowing the deployment audience to fulfillment roles that actually use Ship Central (see next finding).
scriptdeployment.allroles = 'T' on all 13 active rows · Affects: open + per-line + save for all users · Effort: Trivial (config)Every user who opens a sales order — sales rep, accountant, executive — executes the full stack, including shipping/fulfillment logic (Packship) that only warehouse flows need. Narrowing Applies To → Roles on non-universal deployments is the highest-leverage zero-code fix available.
The client script initializes a dictionary at pageInit and executes SCM.CPN.Transactions_CS.init() at file-load time (line 93 — comment says it must run "because workflow's BeforeUserEdit happens before client script's pageInit"). SS1.0 code paths (nlapi*) are synchronous by design. The paired UE's source is bundle-hidden, so its beforeLoad cost is unverified.
These four run beforeLoad on every sales order open, and their contents are hidden (bundle-protected or restricted). Their aggregate cost is unknown — it could be trivial or it could be the dominant term. Confirming step: NetSuite APM's Page Time Summary attributes wall-clock per script without needing source access. Additionally, USR CS Transaction (file 24710) is minified (8 lines / 21 KB) and its entry points could not be pattern-matched.
The STE UE/CS are dispatcher shims that loop over sub-modules (custom-field lookup + prompt-payment discount) for beforeLoad, pageInit, fieldChanged, postSourcing, validateLine, and saveRecord. The dispatcher itself is clean; the beforeLoad adds a custpage_allnexuses form field. Bounded cost, required for tax; no action recommended.
TypeScript-compiled controller pattern with pageInit, validateField, lineInit, validateLine. The imported SalesOrderGateway name suggests server communication; whether it fires per line was not confirmed in this pass. Confirming step: read the gateway module or profile with APM.
UE beforeLoad does logging + field-visibility management only; client fieldChanged exits unless the changed field is subsidiary. Well-scoped, no searches, no loads.
All 10 active released workflows were enumerated with their trigger types and target record types. None target Sales Order. (Note: "Default Promise Date" — customworkflow_atlas_promise_date_dflt — targets the Purchase Order family per recordtypes=-106 and its companion field's visibility; an earlier informal pass had provisionally associated it with SO entry. The audit corrects that: zero workflow cost on SO.)
| Field type | Visible on SO | Sourced | Mandatory |
|---|---|---|---|
| Body (CUSTBODY) | 31 | 1 | 0 |
| Line / column (CUSTCOL) | 25 | 15 | 0 |
| Total | 56 | 16 | 0 |
MEDIUM 25 line-level fields multiply with every order line, and 15 of them are sourced — each sourcing evaluation stacks with the 7 client scripts' fieldChanged/postSourcing handlers on the same keystroke. Many are bundle-owned (Electronic Payments CUSTCOL_2663_*/CUSTCOL_9572_* file-format and entity-bank fields, STE tax columns, Packship pack-instructions). No mandatory custom fields — good. Remediation is form hygiene: hide unused bundle fields from the active SO entry form rather than deleting them.
The scriptnote table (script reference column: scripttype) contains zero entries for the 13 SO-deployed scripts — log levels are set above DEBUG and/or entries have aged out. Log-volume heat ranking is therefore unavailable in this account; findings above rest on code inspection instead. This also means script logging is not itself a performance drag here.
| Bundle | Contribution to SO entry path |
|---|---|
| 47193 (SCM / Item Substitute + CPN) | 4 deployments (2 CS + 2 UE), two of them SS1.0; UE sources hidden |
| 237702 (STE tax engine — Oracle) | 2 deployments (CS + UE), dispatcher pattern, bounded |
| 534418 (Packship / Ship Central) | 1 CS with the CRITICAL uncached-query finding; plus SO-visible custom fields |
| 266623 (RAC) | 1 UE, source hidden |
| Custom (no bundle) | ATB SO controller CS, LRC Field Manager CS+UE, USR CS+UE (minified/hidden) |
fieldChanged-capable keystroke and six UEs on every open/save. The sum is the product users feel; per-script review alone understates it.allroles to targeted role lists on Packship CS and any fulfillment-only deployments. Expected effect: immediate open/per-line improvement for sales roles. Do this first.getShipCentralPreference() results. Expected effect: removes 1–2 client-side query round-trips per open and per ship-field change for remaining users.All queries executed via SuiteQL under role id 3 on 2026-07-02. Tool calls: agentSession, accountFeaturesGet, runSql ×10, fileGrep ×9, fileGetLines ×3, evalJs (aggregation).
-- Phase 1: script inventory (15 rows; 13 active)
SELECT s.id, s.name, s.scripttype, s.scriptid, s.scriptfile, sd.id, sd.status,
sd.isdeployed, sd.allroles, sd.eventtype
FROM scriptdeployment sd JOIN script s ON s.id = sd.script
WHERE sd.recordtype = 'SALESORDER'
ORDER BY sd.isdeployed DESC, s.scripttype, s.name;
-- Phase 3: workflows (10 rows; none target SalesOrder)
SELECT name, scriptid, recordtypes, inittriggertype, initoncreate,
initonvieworupdate, initsavedsearchcondition, islogenabled, frombundle
FROM workflow WHERE isinactive = 'F' AND releasestatus = 'RELEASED';
-- Phase 4: custom field surface (grouped; aggregated client-side to
-- BODY=31, COLUMN=25 containing token 'SalesOrd'. Note: LIKE/INSTR on
-- customfield.visibleontransactions returns 0 in WHERE context in this
-- account — a SuiteQL quirk; grouping by the raw column then filtering
-- client-side is the reliable pattern.)
SELECT fieldtype, visibleontransactions, COUNT(*) cnt,
SUM(CASE WHEN source IS NOT NULL THEN 1 ELSE 0 END) sourced,
SUM(CASE WHEN ismandatory='T' THEN 1 ELSE 0 END) mandatory
FROM customfield WHERE fieldtype IN ('BODY','COLUMN')
GROUP BY fieldtype, visibleontransactions;
-- Phase 5: execution-log heat (0 rows — no log entries for these scripts;
-- note scriptnote's script-reference column is named 'scripttype')
SELECT scripttype, type, COUNT(*) FROM scriptnote
WHERE scripttype IN (1793,473,3365,2182,477,1201,2386,418,2192,801,436,1155,2389)
GROUP BY scripttype, type;
-- Phase 6: bundle attribution + API version (13 rows)
SELECT id, name, frombundle, apiversion FROM script
WHERE id IN (1793,473,3365,2182,477,1201,2386,418,2192,801,436,1155,2389);
Files inspected: 24196 (packship_cs_order.js — full anti-pattern review), 7568/7620 (STE dispatchers), 24576/90318 (LRC), 15869 (ATB CS), 5015 (SCM CPN CS), 24710 (USR CS — minified, unreviewable). Access denied: 5021, 5899, 5093, 24736.
Limitations: static analysis only — no wall-clock measurements; four UE sources and one minified CS unreviewed; scriptnote empty for target scripts; audit reflects account state as of 2026-07-02.