toga-ai 1.0.121 → 1.0.122
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/knowledge/1.0/apps/worker/INDEX.md +2 -1
- package/knowledge/1.0/apps/worker/features/compass-ma-sales-order-exception-report.md +82 -0
- package/knowledge/1.0/apps/worker/features/compass-partial-in-transit-delivered-emails.md +3 -8
- package/knowledge/2.0/apps/_underscore/features/email-template-sending.md +1 -1
- package/knowledge/2.0/apps/api2/features/scripted-api-post-body-args.md +3 -7
- package/knowledge/INDEX.md +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Worker (1.0 Framework) Architecture](architecture.md) | `worker` is the legacy (**1.0** `App_` framework) **background-job tier**. | worker/index.php, worker/_/app/framework.php, worker/crons/, worker/schedules/, worker/ebs/cron.worker.php, worker/.ebextensions/035_cron.worker.config |
|
|
6
|
-
| [Compass
|
|
6
|
+
| [Compass MA Sales Order Exception Report](features/compass-ma-sales-order-exception-report.md) | A worker cron that emails operations the "Compass Refresh Exception Report" — Compass `MA%` sales orders whose corresponding Office Depot (ODP) sales order has | worker/crons/toga2/compass/workflow/7_generate_ma_sales_order_exception_report.php |
|
|
7
|
+
| [Compass Partial In-Transit & Delivered Emails (per package)](features/compass-partial-in-transit-delivered-emails.md) | Compass USA and Compass Canada send a **per-package** in-transit email (and a matching delivered email) instead of one email listing the whole order. | worker/crons/toga2/compass/update_salesorder_status_from_odp.php, worker/crons/toga2/compasscanada/workflow/3_update_salesorder_status_from_grand_and_toy.php |
|
|
7
8
|
| [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools to **audit** and **repair** drift between the production `Forecast` DB (core2) and NetSuite. | test/@dave/reconcile_netsuite_totals.php, test/@dave/analyze_netsuite_forecast_diff.php, test/@dave/trueup_sales.php, test/@dave/trueup_open_orders.php, test/@dave/trueup_opportunities.php, test/@dave/probe_sales_gap_direct.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
8
9
|
| [NetSuite → TOGa Supply Per-Client Sync (thin wrappers)](features/netsuite-togasupply-per-client-sync.md) | Syncs NetSuite transactions (sales orders, purchase orders, invoices, item receipts, item fulfillments, inventory adjustments) into each TOGa Supply (2.0) clien | worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/crons/toga2/netsuite/sync_togasupply_canon.php, worker/schedules/cron.worker.sync.json, dbchanges2/_modules/netsuite/2026-04-01 - Parameters.sql |
|
|
9
10
|
| [Prudential: Send Shipments for the Day report (daily cron)](features/send-shipments-for-the-day.md) | Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all devices shipped that day, including tracking number, serial number, emp | worker/crons/notifications/reports/send_shipments_for_the_day.php |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compass MA Sales Order Exception Report
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: worker
|
|
5
|
+
project: Worker
|
|
6
|
+
client: compass-usa
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-18
|
|
10
|
+
owners: ["bala"]
|
|
11
|
+
files:
|
|
12
|
+
- worker/crons/toga2/compass/workflow/7_generate_ma_sales_order_exception_report.php
|
|
13
|
+
related: []
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
A worker cron that emails operations the "Compass Refresh Exception Report" — Compass `MA%`
|
|
18
|
+
sales orders whose corresponding Office Depot (ODP) sales order has **not** been created in
|
|
19
|
+
NetSuite yet. It is a catch-the-stragglers report: orders that should have flowed to NetSuite
|
|
20
|
+
but haven't. Runs against the Compass client DB (`db_prod_compass` / `Client_Compass`).
|
|
21
|
+
|
|
22
|
+
## Key files / entry points
|
|
23
|
+
- `worker/crons/toga2/compass/workflow/7_generate_ma_sales_order_exception_report.php` — the
|
|
24
|
+
whole job: one main SELECT, a per-row NetSuite recheck, and a PhpSpreadsheet Excel email.
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
1. **Main query** walks a two-hop bridge chain to connect the customer order to the vendor order:
|
|
28
|
+
Compass SO (`number LIKE 'MA%'`) → `SalesOrders_PurchaseOrders` → Compass PO →
|
|
29
|
+
`PurchaseOrders_SalesOrders` → **ODP SO** (`customerId = OFFICE_DEPOT`) →
|
|
30
|
+
`SalesOrders_PurchaseOrders` → ODP PO. Note the two bridge tables are used in **opposite
|
|
31
|
+
directions** at each hop — `SalesOrders_PurchaseOrders` for SO→PO, `PurchaseOrders_SalesOrders`
|
|
32
|
+
for PO→SO. It also inner-joins the ODP SO's address, state, items, item→PO-item bridge, PO
|
|
33
|
+
items, and vendor items — so a row with any of those missing silently drops out.
|
|
34
|
+
2. **Filter:** `MA%` Compass SO, ODP SO `customerId = App_Client_Compass::CUSTOMER_ID__OFFICE_DEPOT`
|
|
35
|
+
(= 1), and `OfficeDepotSalesOrders.c_netsuiteInternalSalesOrderId IS NULL`.
|
|
36
|
+
3. **Per-row NetSuite recheck:** for each surviving row it looks for an **Agilant**-customer
|
|
37
|
+
(`CUSTOMER_ID__AGILANT` = 3) sales order tied to that ODP PO number. If found → it back-fills
|
|
38
|
+
`c_netsuiteInternalSalesOrderId` on the ODP SO and skips the row (drops it off the report
|
|
39
|
+
permanently). If not found → it writes the row to the Excel.
|
|
40
|
+
4. Emails the workbook to operations only if at least one data row was written.
|
|
41
|
+
|
|
42
|
+
## Data model
|
|
43
|
+
- `Client_Compass.SalesOrders` — the ODP sales order is the one keyed on (`id AS salesOrderId`,
|
|
44
|
+
`customerId = 1` Office Depot). Relevant columns: `c_netsuiteInternalSalesOrderId` (NULL until
|
|
45
|
+
the order exists in NetSuite) and `salesOrderStageId`.
|
|
46
|
+
- `Client_Compass.SalesOrderStages` — `5 = Pending Billing`, `6 = Pending Billing/Partially
|
|
47
|
+
Fulfilled`, `7 = Billed`, `8 = Canceled`, `9 = Closed`.
|
|
48
|
+
- Bridges: `SalesOrders_PurchaseOrders` (salesOrderId, purchaseOrderId) and
|
|
49
|
+
`PurchaseOrders_SalesOrders` (purchaseOrderId, salesOrderId) — distinct tables, distinct
|
|
50
|
+
directions.
|
|
51
|
+
|
|
52
|
+
## Client variations
|
|
53
|
+
Compass USA only — this is a Compass-specific integration cron.
|
|
54
|
+
|
|
55
|
+
## Gotchas / known issues
|
|
56
|
+
- **Two removal levers, and only one used to exist.** Historically the *only* way an order left
|
|
57
|
+
the report was `c_netsuiteInternalSalesOrderId` becoming non-NULL (set by the per-row recheck
|
|
58
|
+
when the NetSuite order is found). An order **closed/canceled on Office Depot's end** never gets
|
|
59
|
+
a NetSuite order, so it never gets that id, so it stuck on the report forever. The fix (2026-06)
|
|
60
|
+
added a **stage-based exclusion** so canceling/closing the ODP SO removes it.
|
|
61
|
+
- **To remove an order, mark the OFFICE DEPOT sales order — not the Compass SO.** The query
|
|
62
|
+
filters on `OfficeDepotSalesOrders.salesOrderStageId`; the Compass SO's stage is never read.
|
|
63
|
+
Setting the Compass `MA%` order's stage does nothing.
|
|
64
|
+
- **NULL-safe stage filter is mandatory.** Active orders normally have `salesOrderStageId = NULL`.
|
|
65
|
+
In SQL `NULL NOT IN (8, 9)` evaluates to *unknown* (not true), so a bare
|
|
66
|
+
`salesOrderStageId NOT IN (8, 9)` would drop **every NULL-stage order** — i.e. almost the whole
|
|
67
|
+
report. The condition must be `(salesOrderStageId IS NULL OR salesOrderStageId NOT IN (8, 9))`,
|
|
68
|
+
and it must be parenthesized because `AND` binds tighter than `OR`.
|
|
69
|
+
- **Don't fake the NetSuite id to hide an order.** Writing a bogus `c_netsuiteInternalSalesOrderId`
|
|
70
|
+
removes it from the report but corrupts the field for anyone who reads it later. Use the stage
|
|
71
|
+
lever instead.
|
|
72
|
+
- `$inProduction = true` switches the DB link to `db_prod_compass`; set false to test against
|
|
73
|
+
`db_beta_compass`.
|
|
74
|
+
|
|
75
|
+
## Change history
|
|
76
|
+
- 2026-06-18 — Added stage-based exclusion so orders closed/canceled on ODP's end drop off the
|
|
77
|
+
report: `(salesOrderStageId IS NULL OR salesOrderStageId NOT IN (8, 9))` in the main query.
|
|
78
|
+
Removing specific stuck orders is then a data change (set the ODP SO's `salesOrderStageId` to
|
|
79
|
+
8/9), not a code change. (bala)
|
|
80
|
+
|
|
81
|
+
## Related docs
|
|
82
|
+
- [Compass USA profile](../../../clients/compass-usa/profile.md)
|
|
@@ -10,9 +10,7 @@ updated: 2026-06-18
|
|
|
10
10
|
owners: ["bala"]
|
|
11
11
|
files:
|
|
12
12
|
- worker/crons/toga2/compass/update_salesorder_status_from_odp.php
|
|
13
|
-
- worker/crons/toga2/compass/workflow/test_partial_in_transit_email.php
|
|
14
13
|
- worker/crons/toga2/compasscanada/workflow/3_update_salesorder_status_from_grand_and_toy.php
|
|
15
|
-
- worker/crons/toga2/compasscanada/workflow/test_partial_in_transit_email.php
|
|
16
14
|
related: []
|
|
17
15
|
---
|
|
18
16
|
|
|
@@ -30,8 +28,6 @@ and earlier packages). The dynamic HTML is injected into a stored `EmailTemplate
|
|
|
30
28
|
- `worker/crons/toga2/compass/update_salesorder_status_from_odp.php` — Compass USA prod cron.
|
|
31
29
|
- `worker/crons/toga2/compasscanada/workflow/3_update_salesorder_status_from_grand_and_toy.php`
|
|
32
30
|
— Compass Canada prod cron.
|
|
33
|
-
- `*/workflow/test_partial_in_transit_email.php` — read-only prod test scripts for each client
|
|
34
|
-
(email goes only to a test recipient, no DB writes). Use these to preview rendering.
|
|
35
31
|
- Shared helper set in each cron: `getOrderFulfillmentData`, `buildItemRowsHtml`,
|
|
36
32
|
`buildSectionHeaderHtml`, `buildPackageBlockHtml`, `buildTrackingUrl`, `buildOrderItemsHtml`.
|
|
37
33
|
|
|
@@ -106,14 +102,13 @@ the tracking number as emailed (it retries next run).
|
|
|
106
102
|
`getOrderFulfillmentData` — same query as Compass USA. Canada was originally on the ASN chain
|
|
107
103
|
because it had **zero `ItemFulfillmentItems`**; if that line-bridge data is not populated for a
|
|
108
104
|
Canada order, `getOrderFulfillmentData` returns no packages and the cron falls back to the
|
|
109
|
-
full email.
|
|
105
|
+
full email.
|
|
110
106
|
- **Line bridge is moving-forward only** — it began populating ~2026-06-12; pre-cutoff tracking
|
|
111
107
|
numbers are intentionally out of scope (driving-query date cutoff).
|
|
112
108
|
- The driving query still uses the ASN chain (to find shipped orders + tracking) for **both**
|
|
113
109
|
clients — that is correct and unrelated to the package-contents source.
|
|
114
|
-
-
|
|
115
|
-
|
|
116
|
-
`RecordScripts`/`AclRecordScripts` registration (prod done, beta pending) — see related docs.
|
|
110
|
+
- **Not yet deployed.** These crons depend on the api2 POST scripted-API change and its
|
|
111
|
+
`RecordScripts`/`AclRecordScripts` registration — see related docs.
|
|
117
112
|
|
|
118
113
|
## Change history
|
|
119
114
|
|
|
@@ -87,7 +87,7 @@ can keep using `sendEmail($api, ...)`.
|
|
|
87
87
|
(previously the inactive case returned `false` and an SMTP failure was swallowed entirely).
|
|
88
88
|
Any fire-and-forget caller now propagates that exception, which is intended (so an email is
|
|
89
89
|
never silently marked as sent). Blast radius is every client, including the Compass/Quad
|
|
90
|
-
`SalesOrder`/`ApprovalDecision` order-placed emails
|
|
90
|
+
`SalesOrder`/`ApprovalDecision` order-placed emails.
|
|
91
91
|
|
|
92
92
|
## Change history
|
|
93
93
|
|
|
@@ -65,13 +65,9 @@ None — this is engine behavior. Per-client access is controlled by `AclRecordS
|
|
|
65
65
|
- **Normal CRUD is unaffected.** The POST scripted block only fires when a POST Record Script
|
|
66
66
|
is registered for the route; otherwise the request falls through to the usual create path
|
|
67
67
|
(`if (!$isUsingScriptedCall && empty($routePairs))` / `locateRecord`).
|
|
68
|
-
- **Registration is environment
|
|
69
|
-
(client) rows must exist in every environment the API reads
|
|
70
|
-
|
|
71
|
-
**beta still needs them** before the POST path dispatches there.
|
|
72
|
-
- **Deploys with `_underscore`.** api2 pulls `_underscore` at deploy; `http://api2` and
|
|
73
|
-
`api.beta.togahub.com` resolve to deployed boxes (`/var/app/current`), not a local checkout —
|
|
74
|
-
so testing the change requires deploying it, not just editing locally.
|
|
68
|
+
- **Registration is per-environment.** The `RecordScripts` (Core) + `AclRecordScripts`
|
|
69
|
+
(client) rows must exist in every environment the API reads; a missing POST `RecordScripts`
|
|
70
|
+
row means the POST path silently falls through to normal CRUD.
|
|
75
71
|
- **CI commit policy.** Subject must be `TRUE-<ticket>: <Subject>` (≤80 chars, capitalized,
|
|
76
72
|
imperative, no trailing period, more than one word).
|
|
77
73
|
|
package/knowledge/INDEX.md
CHANGED
|
@@ -5,7 +5,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
5
5
|
## 1.0 framework
|
|
6
6
|
|
|
7
7
|
- **library** (Library) _(framework core)_ — 4 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
|
-
- **worker** (Worker) —
|
|
8
|
+
- **worker** (Worker) — 9 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **togadesk** (TOGa Desk) — 7 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
10
10
|
- **togaview** (TOGa View) — 5 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
|
|
11
11
|
- **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
|
package/package.json
CHANGED