toga-ai 1.0.298 → 1.0.299
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.
|
@@ -6,8 +6,8 @@ project: Worker
|
|
|
6
6
|
client: nycdoe
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: [mhammontree]
|
|
9
|
+
updated: 2026-07-09
|
|
10
|
+
owners: [mhammontree, sking]
|
|
11
11
|
files:
|
|
12
12
|
- worker/crons/sync/nycdoe/import_asn.php
|
|
13
13
|
- worker/crons/sync/nycdoe/import_inc.php
|
|
@@ -17,6 +17,7 @@ files:
|
|
|
17
17
|
- worker/crons/sync/nycdoe/1_send_asn_to_netsuite.php
|
|
18
18
|
- worker/crons/sync/nycdoe/2_send_serials_to_netsuite.php
|
|
19
19
|
- worker/crons/sync/nycdoe/3_create_installation_ticket.php
|
|
20
|
+
- worker/crons/sync/nycdoe/test_multi_po_receipt_resolution.php
|
|
20
21
|
- worker/crons/sync/nycdoe/send_ticket_updates.php
|
|
21
22
|
- worker/crons/sync/nycdoe/send_request_item_updates.php
|
|
22
23
|
- worker/crons/sync/nycdoe/send_nycdoe_proof_of_delivery.php
|
|
@@ -34,6 +35,7 @@ files:
|
|
|
34
35
|
- library/app/asnprocessor/lexmark.php
|
|
35
36
|
- library/app/asnprocessor/acer.php
|
|
36
37
|
- library/app/edi.php
|
|
38
|
+
- library/app/netsuite.php
|
|
37
39
|
related:
|
|
38
40
|
- ../profile.md
|
|
39
41
|
- hold-status-sync.md
|
|
@@ -131,12 +133,27 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
|
|
|
131
133
|
`qtyOrder` is immutable** — there is no update path to a sent SO line; growth must be a
|
|
132
134
|
new item row → new SO line.
|
|
133
135
|
- **Stage 4:** reconciles the NetSuite **PO** (`netSuiteInternalPurchaseOrderId` — not the
|
|
134
|
-
SO id) and sends serial inventory assignments.
|
|
136
|
+
SO id) and sends serial inventory assignments. It is already multi-PO aware
|
|
137
|
+
(`listPurchaseOrdersCreatedFromSalesOrder`, groups items by PO, stamps each item's
|
|
138
|
+
`netSuiteInternalPurchaseOrderId`) **but only stamps items where the PO is NULL and never
|
|
139
|
+
re-stamps** — so an item stamped to PO-A but later *received* on PO-B is never corrected.
|
|
140
|
+
**TOGA does NOT create NetSuite POs anywhere in the DOE flow.** Stage 3 creates only the SO
|
|
141
|
+
(and, when needed, a special-order inventory Item); POs are generated inside NetSuite by
|
|
142
|
+
procurement/special-order. A single SO can therefore be fulfilled across **multiple POs**
|
|
143
|
+
(back-orders, multi-vendor, re-cut lines) — this is a legitimate NetSuite outcome, so the
|
|
144
|
+
durable fix lives downstream (resolve receipts SO-wide), not in preventing PO splits.
|
|
135
145
|
- **Stage 5:** for units `WHERE togadeskRepairOrderId IS NULL`, reads serials from NetSuite
|
|
136
146
|
item receipts (so TOGa Desk RO serials are **driven by NetSuite**, not the ASN unit),
|
|
137
147
|
creates/reuses TOGa Desk manufacturers/models/assets/serial-numbers/MSO and creates **a
|
|
138
148
|
new repair_orders row unconditionally per loop iteration** — one RO per Unit (a 50-cable
|
|
139
149
|
line = 1 unit = 1 RO). Existing-serial lookup is scoped **per item row** (`$asnItemId`).
|
|
150
|
+
Item receipts are now resolved **Sales-Order-wide** via
|
|
151
|
+
`App_NetSuite::listItemReceiptsCreatedFromSalesOrder($soId)` (fans out across ALL POs from
|
|
152
|
+
`listPurchaseOrdersCreatedFromSalesOrder`, dedupes receipts by `internalId`), cached once
|
|
153
|
+
per ASN, with `getItemReceipt` cached per receipt id. The inner item query also requires
|
|
154
|
+
`netSuiteInternalSalesOrderId IS NOT NULL` so a null-SO first row cannot poison the per-ASN
|
|
155
|
+
receipt cache. Self-healing: units previously stuck under an unstamped PO clear on
|
|
156
|
+
subsequent 5-min cron runs.
|
|
140
157
|
- **"#/N received" UI** (`togadesk/desk/template/pages/managedserviceorders/view.php`):
|
|
141
158
|
denominator = `SUM(qtyOrder)` per part (committed + unsent); numerator = Units with
|
|
142
159
|
`togadeskRepairOrderId IS NOT NULL`.
|
|
@@ -218,6 +235,36 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
|
|
|
218
235
|
- **Stage 6 is not currently running** (`4_` paused with `active: 0`, `5_` unscheduled).
|
|
219
236
|
- TRUE-77354: Stage 5 lookups changed `LIKE` → `=` to stop `_`/`%` wildcard matches in
|
|
220
237
|
serials.
|
|
238
|
+
- **Multi-PO-per-SO silently drops install tickets (FIXED 2026-07-09).** Stage 5 used to
|
|
239
|
+
fetch item receipts only for the single stamped `netSuiteInternalPurchaseOrderId`. When a
|
|
240
|
+
NetSuite SO is fulfilled across more than one PO, units received under a PO *other* than the
|
|
241
|
+
stamped one never got a TogaDesk repair order, and the every-5-min cron silently re-queried
|
|
242
|
+
the wrong PO forever. No error was raised — the symptom was serials never syncing. Fixed by
|
|
243
|
+
resolving receipts SO-wide (see Stage 5). Before, no `App_NetSuite` method listed receipts
|
|
244
|
+
by SO — only by PO (`listItemReceiptsCreateFromPurchaseOrder`) or location
|
|
245
|
+
(`listAllItemReceiptsForLocation`); the new `listItemReceiptsCreatedFromSalesOrder`
|
|
246
|
+
(`library/app/netsuite.php`, after `listItemReceiptsCreateFromPurchaseOrder`) fills that gap.
|
|
247
|
+
Concrete case: customer PO `S202643596` (ASN 26339, SO internalId 6971858) split across PO
|
|
248
|
+
164785 (internalId 6971859 → `38S0500` synced, 15 ROs) and PO 165751 (`50M7280` + `A3L980`
|
|
249
|
+
NOT synced). PRs: library#831 (merge first) then worker#1670.
|
|
250
|
+
|
|
251
|
+
## Debugging & DB topology (DOE 1.0 sync)
|
|
252
|
+
|
|
253
|
+
Reference for future DOE investigations — the 1.0 worker cannot run on a dev/Windows box;
|
|
254
|
+
use the toga DB MCP + `Logs.API` instead of running prod code locally.
|
|
255
|
+
|
|
256
|
+
- **`db_core` alias → legacy (V1) environment, schema `Core`** — holds the FLAT tables
|
|
257
|
+
`AdvanceShippingNotices` / `AdvanceShippingNoticeItems` / `AdvanceShippingNoticeUnits`
|
|
258
|
+
(columns incl. `togadeskRepairOrderId`, `serialNumber`, `netSuiteInternalSalesOrderId`,
|
|
259
|
+
`netSuiteInternalPurchaseOrderId`, `customerPurchaseOrder`). The 1.0 cron reads **legacy/Core**.
|
|
260
|
+
- **Do NOT confuse with prod (V2) `Client_Nycdoe`** — a DIFFERENT, normalized schema
|
|
261
|
+
(`AdvanceShippingNoticeItemUnits` with a `unitId` FK). The 1.0 cron does not read V2.
|
|
262
|
+
- **NetSuite SOAP request/response payloads** are logged in legacy `Logs.API` — filter
|
|
263
|
+
`sourceJob LIKE '%3_create_installation_ticket%'`; `requestPayload` contains the PO
|
|
264
|
+
internalId. (The multi-PO case above was verified this way: the receipt search for PO
|
|
265
|
+
6971859 returned `totalRecords=1`, only `38S0500`.)
|
|
266
|
+
- **`Bridge_NetSuite`** (legacy) has `SalesOrders` / `SalesOrderItems` / `SerialNumbers` but
|
|
267
|
+
**no `PurchaseOrders` table** — POs are pulled live from the NetSuite API.
|
|
221
268
|
|
|
222
269
|
## Operating rules when changing this integration
|
|
223
270
|
|
|
@@ -231,6 +278,14 @@ Vendor SFTP ───(legacy_import_asn.php, ser+non-ser)─┘ [UNIQUE ded
|
|
|
231
278
|
of the consumer query; `php -l` every touched file.
|
|
232
279
|
|
|
233
280
|
## Change history
|
|
281
|
+
- 2026-07-09 — Fixed silent install-ticket drop when a NetSuite SO is fulfilled across
|
|
282
|
+
multiple POs: Stage 5 now resolves item receipts Sales-Order-wide via new helper
|
|
283
|
+
`App_NetSuite::listItemReceiptsCreatedFromSalesOrder` (fans across all POs from the SO,
|
|
284
|
+
dedupes by internalId, cached per ASN), and its item query requires
|
|
285
|
+
`netSuiteInternalSalesOrderId IS NOT NULL`. Root cause: TOGA doesn't create DOE POs, so
|
|
286
|
+
multi-PO-per-SO is legitimate and units received on an unstamped PO were never ticketed.
|
|
287
|
+
Added multi-PO notes to Stage 4/5, a gotcha, and a DB-topology/debugging section.
|
|
288
|
+
PRs library#831 + worker#1670. (sking)
|
|
234
289
|
- 2026-06-29 — Outbound status sync now keeps DOE holds authoritative (TRUE-79922). Hold
|
|
235
290
|
detection moved to the SNOW native `state` field (not `u_status_task`); Assigned-force
|
|
236
291
|
blocks guarded against local `HOLD_*` to stop the `state:3`↔`state:2` self-clobber; RITM
|
package/package.json
CHANGED