The operational workflow for the logistics team. When freight_routing_check classifies a SO or PO as freight-relevant (LTL / FTL / parcel-with-special-handling / dropship vendor freight / freight-collect), the record lands on the logistics queue with freight_status = 'pending_logistics_review'. This workflow is what happens next: team reviews, selects carrier, schedules pickup, generates BOL, captures tracking, notifies the SO/PO owner. Verify checks at +24h post-pickup (tracking active) and +7d post-pickup (delivery confirmed) close the loop. Customer PO# threads end-to-end: SO.otherrefnum = "72622" → BOL.shipper_ref → logistics_shipments.customer_po_number → Invoice.otherrefnum.
One field threads the entire freight chain end-to-end. If a customer calls about "PO 72622", every record on the route is reachable from that one value.
Mock of the queue surface the logistics team opens each morning. TBD URL: https://gfs-netsuite.pages.dev/logistics-review.html (pending build — SVG above is the SOT).
Team opens the queue, reviews each new entry: source record (SO/PO), classification from freight_routing_check, customer/vendor address, items, weight, volume, special handling flags. Confirm classification is correct (escalate back to check if not).
SO or PO · classification carried from checkbodyFields.shipmethod · bodyFields.shipcarrier · bodyFields.shipaddress · bodyFields.shipdate · lineFields.shippingcostcustbody_freight_status · custbody_freight_classification TBD pending MikePick carrier based on classification + lane history. LTL → preferred LTL carrier per lane. FTL → broker quote. Parcel → UPS/FedEx. Customer pickup → mark as such. Dropship vendor freight → vendor selects, we record. Freight collect → customer's carrier.
proposed_actions. Mike (or logistics lead) approves. ADR-031 invariant.SELECT carrier, AVG(cost), COUNT(*), AVG(transit_days) FROM logistics_shipments WHERE lane_origin=? AND lane_dest=? AND ship_date > date('now','-90 days')72622 carries into payloadOnce carrier is approved + freight is ready (inventory pulled, assembly built, or PO received), schedule the pickup. Write the pickup datetime back to NS as bodyFields.shipdate + custom custbody_pickup_scheduled.
UPDATE salesorder SET shipdate=?, custbody_pickup_scheduled=? WHERE id=? (through NS_PUSH_QUEUE, HITL-gated)2026-06-02 08:00–12:00 · dock door + contact phone capturedGenerate Bill of Lading PDF using the standard GFS template. Includes shipper, consignee, items (with NMFC freight class codes for LTL), weight, special handling (refrigerated / frozen / hazmat). Customer PO# threads through — BOL header carries SO.otherrefnum for tracing.
SO.bodyFields.otherrefnum · e.g. "72622"special_handling = 'hazmat', generate Shipper's Declaration of Dangerous Goods (49 CFR) as second PDFlogistics-bol/{shipment_id}/{date}.pdf · linked from NS via SuiteAttachWhen carrier picks up, capture tracking number + update freight_status = 'shipped'. Email goes out to SO owner (sales) or PO owner (purchasing) with tracking link. Customer gets shipment confirmation if SO + standard.
UPDATE salesorder SET custbody_tracking_number=?, custbody_carrier=?, freight_status='shipped' WHERE id=?"Shipped — SO#{tranid} — PO {customer_po} — tracking {tracking}""Your GFS order has shipped — PO {customer_po}" with tracking link + ETA + BOL pdf attach12345678 · carrier "R+L Carriers" · ETA 2026-06-04 · customer PO# 7262224 hours after pickup, verify the carrier's tracking system shows the shipment as picked up and in transit. If not, flag as a potential pickup-failure issue and re-escalate to logistics.
GET /carrier-api/tracking/{number} → expect status in (picked_up · in_transit · out_for_delivery)issue_type='pickup_missed')7 days post-pickup, expect delivery to be confirmed. Pull POD (proof of delivery) signature if carrier provides it. Update freight_status = 'delivered'. Close the workflow run. If delivery NOT confirmed, escalate as a delay issue.
logistics-pod/{shipment_id}/{date}.pdf · linked from NS via SuiteAttachfreight_status = 'delivered' · custbody_delivery_date = ? · custbody_pod_url = ?logistics.shipment_delivered — subscribers: finance + sales daily summary| Issue type | Trigger | Action | Notify |
|---|---|---|---|
pickup_missed | verify +24h fails OR carrier no-show reported | Re-schedule pickup, log lane reliability penalty | SO/PO owner + logistics lead |
delay_in_transit | tracking shows no movement > 48h OR carrier ETA slips | Carrier call, customer pre-notify, ETA update | SO owner + customer |
damage_on_delivery | POD notes damage OR customer reports damage within 48h | Open carrier claim, document with photos, replacement order if needed | SO owner + customer service + carrier claims |
refused_delivery | carrier returns shipment to GFS | Investigate reason: wrong item, late, customer cancelled, etc. Hold inventory, escalate to sales. | SO owner + customer + sales lead |
lost_shipment | tracking stuck > 7 days OR carrier confirms loss | Open formal loss claim, ship replacement, recover from carrier | Finance + sales + customer |
When freight_status = 'delivered' is written, an event lands on the event ledger (logistics.shipment_delivered) which triggers the universal Finance handoff (R594 NS automation, planned). Finance sees the delivered shipment + invoice goes out. Sales gets the delivery confirmation in their daily summary. The customer PO# threads all the way through: SO.otherrefnum → BOL.shipper_ref → Invoice.otherrefnum → logistics dashboard → event ledger entry.
| kind | name | purpose |
|---|---|---|
| D1 table | freight_status_mirror | workflow state — freight_status per (source_record_type, source_record_id) · customer_po_number threads |
| D1 table | logistics_shipments | final shipment scoreboard row — carrier, lane, transit_actual, on_time, cost, damage_flag, customer_po_number |
| D1 table | freight_lane_history | updated by reflexion at workflow close · feeds next freight_routing_check |
| D1 table | carriers | carrier qualifications (refrigerated, hazmat cert, oversize) |
| D1 table | proposed_actions | 4 HITL gates: carrier_select · pickup_schedule · bol_generate · issue stages |
| D1 table | events | logistics.shipment_delivered · workflow.completed · logistics.issue_opened |
| R2 bucket | logistics-bol/{id}/{date}.pdf | BOL pdf storage · SuiteAttach to NS |
| R2 bucket | logistics-pod/{id}/{date}.pdf | POD pdf storage · SuiteAttach to NS |
| Workflow contract | logistics_review_workflow | this flow · risk 2 · 4 HITL gates · 2 verify_checks (+24h, +7d) |
| Workflow contract | freight_routing_check | upstream · hands off via freight.routed_to_logistics event |
| NS field (write) | custbody_carrier · custbody_tracking_number · custbody_pickup_scheduled · custbody_delivery_date · custbody_pod_url | via NS_PUSH_QUEUE · HITL-gated |
| NS field (write, TBD) | custbody_freight_status · custbody_freight_classification | pending Mike review |
| Endpoint | /logistics-review.html | queue surface UI (build pending — SVG above is SOT) |
/logistics-review.html Pages function is TBD — D1 query is real, UI build pending.custbody_freight_status + custbody_freight_classification not yet confirmed in NS. Status lives in D1 only until Mike confirms field names.logistics@globalfoodsolutions.co expected but not yet provisioned.