NetSuite sales order lifecycle (3-path) risk 2 · lowemail_intakereflexion on

workflow_type: sales_order_lifecycle · owner: mike · contract v3 (R592 split — now master dispatcher) · sub-contracts so_lifecycle_inventory_path / so_lifecycle_assembly_path / so_lifecycle_dropship_path · diagram: ns-sales-order-master.html · wiki: wiki-ns-sales-order-master.html · PENDING REGEN: this v2 view is stale — regenerate from D1 workflow_definitions after migration 131

Customer order arrives by email at orders@globalfoodsolutions.co or danielle@globalfoodsolutions.co. Team reviews against customer file, keys SO into NetSuite. SO branches by item type into 3 paths: PATH 1 inventory PATH 2 assembly (WO from SO) PATH 3 dropship (PO from SO). All paths converge at Item Fulfillment, which fires an ★ automation alert to Finance — the named handoff between Operations and Finance. Finance reviews → invoices → monitors terms → dunning if past due → payment apply → close. Path 3 sidecar: vendor bill cycle in parallel.

0 · Visual flow 3-path branch · Finance handoff · dunning loopback

idle
NS sales order lifecycle (3-path) — email intake → SO review + entry → branch by item type → 3 paths → Item Fulfillment → ★ Finance alert → invoice → AR → close (dunning loopback) 01 / Email intake 02 / SO review + entry 03 / Branch by item type PATH 1 / Inventory fulfillment PATH 2 / Assembly build PATH 3 / Drop ship 04 / Item Fulfillment (converge) 05 / Finance handoff (KEY automation alert) 06 / Invoice · payment · close (dunning loopback) EMAIL INTAKE — Most customer orders arrive by email at two mailboxes. MAILBOXES orders@globalfoodsolutions.co danielle@globalfoodsolutions.co SOURCE customer email, EDI 850 (manual keying), portal upload STATUS: REAL · EDI auto-parse STUB customer email intake orders@globalfoodsolutions.co danielle@globalfoodsolutions.co EXTERNAL · EMAIL ROUTING i OTHER INTAKE CHANNELS — less common today. CHANNELS NS UI · customer portal · EDI 850 (manual keying) · phone keyed by CS STATUS: REAL · EDI auto STUB other channels NS UI · portal · phone EDI 850 (manual keying) EXTERNAL · EDI STUB i REVIEW + CONFIRM — Team reads order against customer file. CHECKS customer record + ship-to · item pack/UOM · pricing alignment · special instructions TABLES read: customers · pricing_master · customer_programs · contracts STATUS: REAL · operator-driven review customer order customer file · items · ship-to pricing · special instructions DATABASE · customers · pricing i ENTER SO IN NETSUITE — SO posted as system-of-record. ACTION create: NS SalesOrd · D1 mirror on next 2-min hot sync TABLES write: NS SalesOrd · D1 transactions · so_lines STATUS: REAL enter SO in NetSuite NS SalesOrd posted D1 sync (2-min hot tier) BACKEND · NS + D1 mirror i CLASSIFY EACH LINE BY ITEM TYPE — single SO routinely spans multiple paths. LOGIC inventory_item → Path 1 assembly_item → Path 2 (WO from SO) dropship_item OR special_order → Path 3 (PO from SO) STATUS: REAL (operator) · STUB (auto) classify each line by item type inventory · assembly · dropship single SO can hit all 3 paths SECURITY · operator · auto STUB i PATH 1 · FULFILL FROM INVENTORY — Items already on hand. ACTION check qty · reserve · pick · pack TABLES write: itemfulfillment (open) · inventory_balance (reserved_qty) STATUS: REAL fulfill from inventory qty_available ≥ so_qty reserve · pick · pack no WO, no PO PATH 1 · inventory_balance DATABASE · stock pull i P1 PICK + PACK + STAGE — warehouse executes. ACTION pick list · scan · label · palletize · stage TABLES write: itemfulfillment (in progress) STATUS: REAL pick + pack + stage pick list · scan · label palletize · stage itemfulfillment open PATH 1 · warehouse BACKEND · pick form i PATH 2 · CREATE WORK ORDERS FROM SO — for assembly_build line items. ACTION per assembly_line: create WO with parent_so_id linking back to SO ALTERNATE if FG already on hand → close WO + fulfill from inventory instead TABLES write: NS workorder · transactions (WorkOrd) STATUS: REAL create Work Orders FROM SO per assembly line parent_so_id linked BOM reserved PATH 2 · workorder MESSAGEBUS · WO create i P2 COMPLETE ASSEMBLY BUILD — production crew executes. ACTION qty · waste · scrap · raw-- · finished++ HITL /assembly-build.html → proposed_actions → Mike approves TABLES write: assemblybuild · inventory_balance · assembly_builds STATUS: REAL complete assembly build qty + waste + scrap raw-- · finished++ HITL via Mike PATH 2 · assemblybuild BACKEND · production i PATH 3 · CREATE PURCHASE ORDER FROM SO — drop-ship items. ACTION per dropship_line: create PO with parent_so_id · transmit to vendor TABLES write: NS purchaseorder · transactions (PurchOrd) STATUS: REAL create PO FROM SO per dropship line parent_so_id linked transmit to vendor PATH 3 · purchaseorder MESSAGEBUS · PO i P3 VENDOR SHIPS · ITEM RECEIPT — vendor fulfills PO. ACTION vendor ships directly to customer (or to GFS for crossdock) itemreceipt against PO (closes PO line) DOWNSTREAM vendor bill entered → paid per terms (separate cycle) TABLES write: NS itemreceipt STATUS: REAL vendor ships · item receipt vendor → customer (or crossdock) itemreceipt closes PO vendor bill follows PATH 3 · itemreceipt BACKEND · vendor ships i ITEM FULFILLMENT COMPLETED — convergence point for all 3 paths. ACTION itemfulfillment → 'Shipped' · inventory decrement · BOL/ASN TABLES write: itemfulfillment · inventory_balance · transactions STATUS: REAL Item Fulfillment completed itemfulfillment → Shipped · inventory-- · BOL/ASN CONVERGENCE · all 3 paths i ★ AUTOMATION ALERT → FINANCE — THE KEY HANDOFF SIGNAL. TRIGGER itemfulfillment.status='Shipped' ACTION fire: NS workflow alert to Finance review queue NOTE Concept REAL · code-level config STUB (verify NS workflow trigger) STATUS: REAL (concept) · STUB (code verify) ★ automation alert → Finance key Ops↔Finance handoff · fires on every fulfillment FINANCE · NS workflow trigger (verify in code) i FINANCE REVIEW — Finance reviews fulfillment before invoicing. CHECKS qty match · pricing carried · terms · tax · short-ships STATUS: REAL Finance review qty · pricing · terms · tax CLOUD · Finance role i INVOICE CUSTOMER — Finance posts CustInvc. TABLES write: transactions (CustInvc) · invoice_lines · v_customer_ar_aging STATUS: REAL invoice customer CustInvc · AR balance BACKEND · CustInvc i MONITOR TERMS — AR aging buckets surfaced. STATUS: REAL monitor terms AR aging · due_date DATABASE · v_*_aging i PAST DUE → DUNNING — ar_aging_action_plan fires. LOOPBACK 30 / 60 / 90+ days until paid or service hold STATUS: REAL past due → dunning ar_aging_action_plan SECURITY · HITL email i PAYMENT RECEIVED · APPLY — CustPymt posted. TABLES write: customer_payments · payment_applications STATUS: REAL payment received CustPymt · apply DATABASE · CustPymt i CLOSE ORDER — SO closed; order.closed event fires. STATUS: REAL close order SO status · events fire BACKEND · order.closed i VENDOR-SIDE (Path 3 only) — drop-ship vendor bill cycle in parallel. TABLES write: vendor_bills · vendor_payments STATUS: REAL vendor bill cycle (Path 3) enter · pay per terms MESSAGEBUS · vendor side i → Path 1 → Path 2 → Path 3 all 3 paths converge → Item Fulfillment ★ automation alert loop: 30 / 60 / 90+ days until paid or service hold LEGEND Path 1 inventory Path 2 assembly Path 3 dropship ★ Finance handoff HITL / dunning

1 · Trigger FIRES WHEN…

kind
email_intake
mailboxes
orders@globalfoodsolutions.co
danielle@globalfoodsolutions.co
description
Most customer orders arrive via email at orders@ or danielle@. Team reviews, enters as SO in NetSuite. Other channels (NS UI, portal, EDI 850 manual keying, phone) feed the same downstream branching.

2 · Inputs required

namerequiredtype / hint
customer_idrequiredinteger · NS customer internal ID
itemsrequiredarray · item_code, qty, rate, requested_ship_date
shipping_requirementsrequiredobject · ship-to, carrier, delivery window
special_instructionsoptionalstring · notes the team must honor
email_thread_idoptionalstring · trace back to inbound email

3 · Context loaded D1 queries run before fan-out

name
customer
tables
customers
returns
row
SELECT id, entityid, terms, credit_limit, hold_status, service_hold
  FROM customers WHERE id = ?
name
items_inventory
tables
items · inventory_balance
returns
rows
SELECT item_code, itemtype, dropship, quantityavailable, cost
  FROM items LEFT JOIN inventory_balance USING (item_code)
  WHERE item_code IN (?)
name
customer_program
tables
customer_programs
returns
rows
SELECT item_code, override_price, override_terms
  FROM customer_programs
  WHERE customer_id = ? AND status = 'active'
name
credit_limit
tables
customers · transactions
returns
row
SELECT credit_limit,
       (SELECT SUM(amount_remaining) FROM transactions
         WHERE customer=? AND type='Invoice' AND status != 'paid') AS open_ar
  FROM customers WHERE id = ?
name
hold_status
tables
customers
returns
row
SELECT hold_status, service_hold FROM customers WHERE id = ?

4 · Preconditions checked before any fan-out

checkruleseverity
customer_existscustomer_id IN (SELECT id FROM customers)block
all_items_pricedevery item has a resolved price via pricing_master OR customer_programs OR contractswarn
customer_not_on_holdcustomer.hold_status = 'active' AND customer.service_hold = 0block

Mike's documented process does not explicitly show a credit gate. under_credit_limit is no longer a precondition. Confirm with Mike whether NS-side enforces this or whether it should be re-added.

5 · HITL gate

Risk level 2 < 3 — no global HITL gate. Individual fan-out steps that are HITL-gated: create_work_orders (Path 2), complete_assembly_build (Path 2), create_purchase_order (Path 3), invoice_customer (Finance), trigger_dunning email send (Finance).

6 · Fan-out targets 17 total · 3-path branching

#1classify_path chat_tool STUB auto REAL operator

tool
classify_so_line_paths
description
Classify each so_line into inventory / assembly / dropship. Today operator-driven; auto-classification is a STUB.

#2fulfill_from_inventory d1_write PATH 1 REAL

table
inventory_balance
operation
update (reserve_qty)
condition (if)
path=inventory
UPDATE inventory_balance
  SET reserved_qty = reserved_qty + ?
  WHERE item_code = ? AND location_id = ?

#3create_work_orders stage_proposed_action PATH 2 REAL

action_type
workorder_create_from_so
entity_type
sales_order
condition (if)
path=assembly
description
Per assembly_line: create WO with parent_so_id linking back to SO. Records linked end-to-end.

#4complete_assembly_build chat_tool PATH 2 REAL

tool
complete_assembly_build
condition (if)
path=assembly
description
Production crew executes build; Mike approves at /assembly-build.html. Alternate: if FG already on hand → close WO + fulfill from inventory instead.

#5create_purchase_order stage_proposed_action PATH 3 REAL

action_type
purchaseorder_create_from_so
entity_type
sales_order
condition (if)
path=dropship
description
Per dropship_line: create PO with parent_so_id. Records linked end-to-end.

#6receive_item_receipt chat_tool PATH 3 REAL

tool
post_item_receipt
condition (if)
path=dropship
description
Vendor ships; Item Receipt closes PO line.

#7item_fulfillment_complete d1_write REAL · CONVERGENCE

table
item_fulfillments
operation
insert
description
All 3 paths land here.
INSERT INTO item_fulfillments (so_id, status, shipped_at)
  VALUES (?, 'Shipped', datetime('now'))

#8notify_finance hitl_email_draft ★ KEY HANDOFF code verify

tool
propose_email_to_finance
mailbox
finance@globalfoodsolutions.co
template
itemfulfillment_to_finance_alert
description
THE KEY HANDOFF. Automation alert fires to Finance on every Item Fulfillment completion. Documented as concept; NS workflow trigger config needs code-level verification.

#9finance_review chat_tool FINANCE REAL

tool
finance_review_fulfillment
description
Finance checks fulfilled qty, pricing, terms, tax handling.

#10invoice_customer stage_proposed_action FINANCE REAL

action_type
post_customer_invoice
entity_type
sales_order
description
Finance posts CustInvc using shipped qty.

#11monitor_payment_terms flag FINANCE REAL

view
v_customer_ar_aging
field
bucket
description
Track invoice aging bucket (current / 30 / 60 / 90+).

#12trigger_dunning workflow_class_invoke FINANCE REAL

workflow_type
ar_aging_action_plan
condition (if)
invoice_overdue
description
Loops at 30 / 60 / 90+ until paid or escalated to service hold.

#13payment_apply d1_write FINANCE REAL

table
payment_applications
operation
insert
INSERT INTO payment_applications (payment_id, invoice_id, amount)
  VALUES (?,?,?)

#14close_so d1_write REAL

table
transactions
operation
update (status='Closed')
UPDATE transactions SET status='Closed'
  WHERE id=? AND type='SalesOrd'

#15enter_vendor_bill stage_proposed_action PATH 3 sidecar REAL

action_type
enter_vendor_bill
entity_type
purchase_order
condition (if)
path=dropship
description
Path 3 sidecar — vendor bill entered against PO.

#16pay_vendor_bill stage_proposed_action PATH 3 sidecar REAL

action_type
pay_vendor_bill
entity_type
vendor_bill
condition (if)
path=dropship
description
Path 3 sidecar — paid per vendor terms.

#17reflexion_write d1_write REAL

table
reflexion_log
tags
sales_order,3_path,fulfillment
INSERT INTO reflexion_log (workflow_run_id, entity_type, entity_id, outcome, tags)
  VALUES (?, 'sales_order', ?, ?, 'sales_order,3_path,fulfillment')

7 · Post actions declared + runner-automatic

idactionsource
runner_log_runINSERT into workflow_run_logrunner automatic
runner_reflexionINSERT into reflexion_log (tags=sales_order,3_path)runner automatic
log_runINSERT workflow_run_logdeclared in contract
reflexionINSERT reflexion_log with tags=sales_order,3_pathdeclared in contract
event_completedFIRE event workflow.completed (workflow_type=sales_order_lifecycle)declared in contract

8 · Verify checks written to workflow_verify_results

name
invoice_created
when_to_run
+24h after run
expected
n >= 1
SELECT COUNT(*) AS n FROM customer_invoices
  WHERE so_id=? AND created_at > datetime('now','-24 hours')
name
ns_so_status_closed
when_to_run
+72h post-payment
expected
status='Closed'
SELECT status FROM transactions WHERE id=? AND type='SalesOrd'
name
customer_payment_applied
when_to_run
+30d (typical Net 30)
expected
n >= 1
SELECT COUNT(*) AS n FROM payment_applications pa
  JOIN customer_invoices ci ON pa.invoice_id=ci.id
  WHERE ci.so_id=?

9 · Retry policy

max_attempts
3
backoff
exponential
base_ms
1000
max_ms
30000
alert_on_final_failure
true

10 · What changes when this workflow runs aggregated side effects

systemtable / resourceactionstatussource
D1inventory_balanceUPDATE (reserve_qty)REAL#2 (Path 1)
D1proposed_actionsINSERT (workorder_create_from_so)REAL#3 (Path 2)
NSassemblybuildINSERTREAL#4 (Path 2)
D1proposed_actionsINSERT (purchaseorder_create_from_so)REAL#5 (Path 3)
NSitemreceiptINSERTREAL#6 (Path 3)
D1item_fulfillmentsINSERT (Shipped)REAL#7 convergence
NS Workflowfinance_alertfire (★ key handoff)verify in code#8
D1proposed_actionsINSERT (post_customer_invoice)REAL#10 (Finance)
Workflowar_aging_action_planinvoke (if invoice_overdue)REAL#12 (Finance)
D1payment_applicationsINSERTREAL#13 (Finance)
D1transactions (SalesOrd)UPDATE status='Closed'REAL#14
D1proposed_actionsINSERT (enter_vendor_bill)REAL#15 (Path 3 sidecar)
D1proposed_actionsINSERT (pay_vendor_bill)REAL#16 (Path 3 sidecar)
D1reflexion_logINSERT (tags=sales_order,3_path)REAL#17
D1workflow_run_logINSERT (run summary)REALrunner automatic
Eventworkflow.completedfireREALrunner automatic
Eventorder.closedfireREAL#14 post-close