toga-ai 1.0.827 → 1.0.828
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,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: nychh
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-09-
|
|
9
|
+
updated: 2026-09-16
|
|
10
10
|
owners: [jcardinal, bala, rgirish]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/toga2.php
|
|
@@ -15,11 +15,11 @@ files:
|
|
|
15
15
|
- worker/crons/toga2/netsuite/sync_togasupply_hh.php
|
|
16
16
|
- worker/crons/toga2/netsuite/common_sync_togasupply.php
|
|
17
17
|
- worker/crons/toga2/netsuite/diagnose_hh_stuck_transfer_order.php
|
|
18
|
+
- worker/crons/toga2/netsuite/probe_import_single_order_hh.php
|
|
19
|
+
- worker/crons/toga2/netsuite/relink_transfer_order_pos_hh.php
|
|
18
20
|
- dbchanges2/Core/2026-08-27a - TransferOrderUuidSearchableIdentifier.sql
|
|
19
21
|
- dbchanges2/Client/2026-08-28a - TransferOrderItemsTimestampColumns.sql
|
|
20
|
-
- dbchanges2/
|
|
21
|
-
- dbchanges2/Client/2026-08-29 - ItemReceiptTransferOrderIdFieldPermission.sql
|
|
22
|
-
- dbchanges2/Client/2026-08-29b - ItemReceiptItemTransferOrderItemIdFieldPermission.sql
|
|
22
|
+
- dbchanges2/Client_Nychh/2026-09-16a - TransferOrderBridgeAcl.sql
|
|
23
23
|
related:
|
|
24
24
|
- ../../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md
|
|
25
25
|
- ../../../1.0/apps/library/features/toga2-api-client-and-bridge.md
|
|
@@ -92,6 +92,80 @@ sales-order linker. See the shared
|
|
|
92
92
|
[SO↔PO bridge direction](../../../2.0/apps/_underscore/features/sales-order-purchase-order-bridge-direction.md)
|
|
93
93
|
doc for the bridge naming convention.
|
|
94
94
|
|
|
95
|
+
### ⚠ The bridge links were never being created — three stacked causes, fixed + prod-verified 2026-09-16
|
|
96
|
+
|
|
97
|
+
The PO↔TO bridge links (header **and** line) were silently never forming for NYCHH. Three
|
|
98
|
+
independent faults, peeled in order; the last was the real blocker:
|
|
99
|
+
|
|
100
|
+
1. **Linking only ever ran from the `PURCHASE_ORDERS` section, which never runs for NYCHH.** The
|
|
101
|
+
links depended on the PO section, so a transfer-order import created none. **Fix:** a new **public**
|
|
102
|
+
`App_Api_Toga2::linkTransferOrderPurchaseOrders()` now runs on **every** transfer-order
|
|
103
|
+
import/retry from inside `syncTransferOrderFromNetsuite()`. It is **idempotent** — re-running an
|
|
104
|
+
import repairs any missing link. In `TRANSFER_ORDER_DETECTION_MODE__STOCKING_FLAG` mode it finds
|
|
105
|
+
the customer PO by the NetSuite **PO #** (`otherRefNum`, split on `' + '`) under the
|
|
106
|
+
`clientConfiguration['importCustomerPurchaseOrdersOnVendor']` vendor (the synthetic **Agilant**
|
|
107
|
+
vendor), then calls `linkPurchaseOrderToTransferOrder` for the header
|
|
108
|
+
(`PurchaseOrders_TransferOrders`) and line (`PurchaseOrderItems_TransferOrderItems`) links.
|
|
109
|
+
2. **`linkPurchaseOrderToTransferOrder` read the TO line items from the wrong place, so line links
|
|
110
|
+
never formed.** It read `$transferOrder->transferOrderItems`, but **api2 NEVER inlines that
|
|
111
|
+
collection at any depth** (`transfer-orders` has no `InherentRecordChildren` row — same root cause
|
|
112
|
+
as the idempotency bug), so it was always empty. **Fix:** read TO items via
|
|
113
|
+
`getTransferOrderItemsByUuid` (the reliable direct `GET /transfer-order-items` query). Also lowered
|
|
114
|
+
the TO existence GET to `depth=1` and added `recordsPerPage=1000` to the PO-items GET.
|
|
115
|
+
3. **ROOT CAUSE — an ACL gap, not code.** The NYCHH **API** role had **no write ACL** on the two
|
|
116
|
+
bridge records **325** (`PurchaseOrders_TransferOrders`) and **329**
|
|
117
|
+
(`PurchaseOrderItems_TransferOrderItems`), so the link POST failed api2 **EZ-3 / WZ-2** ("no
|
|
118
|
+
fields in which you are authorized to write"). The working **sales-order** bridge (record **276**,
|
|
119
|
+
`PurchaseOrders_SalesOrders`) already had the grant, which is why SO links worked and TO links did
|
|
120
|
+
not. **Also key: on CREATE, api2 `isPermitted()` DENIES a record permission that has no
|
|
121
|
+
`AclLogicGroups` chain — a bare `AclRecordPermissions` row is inert** (the standard four-table
|
|
122
|
+
chain rule — see [ACL permission chain](../../../2.0/apps/_underscore/features/acl-permission-chain.md)).
|
|
123
|
+
|
|
124
|
+
**Fix migration:** `dbchanges2/Client_Nychh/2026-09-16a - TransferOrderBridgeAcl.sql` seeds the full
|
|
125
|
+
four-table chain (`AclRecordExpressions` `'all'` → `AclRecordPermissions` full CRUD → `AclLogicGroups`
|
|
126
|
+
AND → `AclLogicGroupExpressions`) **plus** `AclFieldPermissions isWritable = 1`, for roles **Base**
|
|
127
|
+
and **API**, on records **325** and **329**, mirroring the working record 276. Guarded/re-runnable,
|
|
128
|
+
roles resolved by name, fresh random v4 uuids, `Core` ids hardcoded (no `Client_*`→`Core` JOIN — the
|
|
129
|
+
cross-cluster rule). The only writable fields a bridge POST touches are the row `uuid` + the two FK
|
|
130
|
+
columns. **Data facts:** Core bridge record ids **276**=`PurchaseOrders_SalesOrders`,
|
|
131
|
+
**325**=`PurchaseOrders_TransferOrders`, **329**=`PurchaseOrderItems_TransferOrderItems`; Core
|
|
132
|
+
`RecordFields` **2210**=uuid/**2211**=purchaseOrderId/**2212**=transferOrderId (rec 325),
|
|
133
|
+
**2226**=uuid/**2227**=purchaseOrderItemId/**2228**=transferOrderItemId (rec 329); `Client_Nychh`
|
|
134
|
+
roles **1**=Base, **2**=Developer, **3**=API, **4**=Public. Reviews: `cto` AGREE (four-table chain),
|
|
135
|
+
`sql-reviewer` SAFE TO MERGE.
|
|
136
|
+
|
|
137
|
+
**ACL failures are now LOUD in the linker.** Both bridge existence checks **THROW** when their GET
|
|
138
|
+
returns no `meta->totalRecordCount` (an ACL **read** gap) instead of silently skipping the create;
|
|
139
|
+
the create POST already throws on a write-fail (EZ-3/WZ-2). So any future ACL gap stops the run
|
|
140
|
+
rather than quietly producing zero links.
|
|
141
|
+
|
|
142
|
+
**Verified in prod:** link `PurchaseOrderItems.id = 589` ↔ `TransferOrderItems.id = 7155` created for
|
|
143
|
+
PO **EIT0012548** ↔ TO **284624** (NetSuite SO **7326440**).
|
|
144
|
+
|
|
145
|
+
### PO discovery for a NYCHH transfer order — `otherRefNum` + Agilant vendor, NEVER `createdPo`
|
|
146
|
+
|
|
147
|
+
For NYCHH the SO **line-level `createdPo` is NULL**; the PurchaseOrder is the **customer PO**
|
|
148
|
+
(`otherRefNum`, the NetSuite "PO #" field) imported against the synthetic **Agilant** vendor. So PO
|
|
149
|
+
discovery from a transfer order must use `otherRefNum` + the Agilant vendor — never `createdPo`.
|
|
150
|
+
NetSuite proof: SO **7326440** `tranid` 284624, `otherrefnum` EIT0012548; its lines' `createdpo` are
|
|
151
|
+
all null; in NetSuite it links only to an invoice + item fulfillment (there is **no** PurchaseOrder
|
|
152
|
+
record on the SO itself).
|
|
153
|
+
|
|
154
|
+
### Operator tools for this path (manual CLI, NOT scheduled)
|
|
155
|
+
|
|
156
|
+
- **`worker/crons/toga2/netsuite/probe_import_single_order_hh.php`** — imports/relinks **one**
|
|
157
|
+
NetSuite order by internal id for NYCHH. Builds lookups by requiring `common_sync_togasupply.php`
|
|
158
|
+
with all `IS_ENABLED_INTEGRATION_*` false, fetches via `fetchSalesOrderByIdFull`, routes via
|
|
159
|
+
`isTransferOrder`, runs `syncTransferOrderFromNetsuite`, then prints diagnostics (`[diag]` PO
|
|
160
|
+
lookup, `[trace]` header-link POST response) and verifies header + line links. No cursor writes /
|
|
161
|
+
no process lock.
|
|
162
|
+
- **`worker/crons/toga2/netsuite/relink_transfer_order_pos_hh.php`** — backfills links for **all**
|
|
163
|
+
existing `Client_Nychh` transfer orders. Pages every `TransferOrders` row, fetches each NetSuite
|
|
164
|
+
order for its PO #, runs only the link step (`App_Api_Toga2::linkTransferOrderPurchaseOrders` — no
|
|
165
|
+
re-import), idempotent, per-order `try/catch` that logs + collects failures (a sanctioned
|
|
166
|
+
operator-tool exception to fail-loud), with a live progress bar + counts + end summary. Optional
|
|
167
|
+
first arg = limit.
|
|
168
|
+
|
|
95
169
|
## Transfer-order origin/destination location resolution
|
|
96
170
|
|
|
97
171
|
`TransferOrders.originLocationId` is **NOT NULL**, so a missing origin fails the V2 insert with
|
|
@@ -384,6 +458,25 @@ item receipts replays about two years unless it is rewound forward first.
|
|
|
384
458
|
|
|
385
459
|
## Change history
|
|
386
460
|
|
|
461
|
+
- 2026-09-16 - **RESOLVED: the PO↔TO bridge links were never being created** (fixed end-to-end,
|
|
462
|
+
prod-verified: PO EIT0012548 ↔ TO 284624 / SO 7326440, link `PurchaseOrderItems.id=589` ↔
|
|
463
|
+
`TransferOrderItems.id=7155`). Three stacked causes: (1) linking only ran from the `PURCHASE_ORDERS`
|
|
464
|
+
section, which never runs for NYCHH → new **public** `linkTransferOrderPurchaseOrders()` now runs on
|
|
465
|
+
every TO import/retry, idempotent, finds the customer PO by `otherRefNum` (split on `' + '`) on the
|
|
466
|
+
Agilant vendor (`clientConfiguration['importCustomerPurchaseOrdersOnVendor']`); (2)
|
|
467
|
+
`linkPurchaseOrderToTransferOrder` read TO items from `$transferOrder->transferOrderItems`, which
|
|
468
|
+
api2 NEVER inlines → now reads via `getTransferOrderItemsByUuid` (also lowered the TO GET to depth 1,
|
|
469
|
+
added `recordsPerPage=1000` to the PO-items GET); (3) **ROOT CAUSE** — the NYCHH API role had no
|
|
470
|
+
write ACL on bridge records **325** (`PurchaseOrders_TransferOrders`) / **329**
|
|
471
|
+
(`PurchaseOrderItems_TransferOrderItems`), so the POST failed **EZ-3/WZ-2**; the working SO bridge
|
|
472
|
+
(rec 276) had it. Fix migration `dbchanges2/Client_Nychh/2026-09-16a - TransferOrderBridgeAcl.sql`
|
|
473
|
+
seeds the full four-table chain + `AclFieldPermissions` for roles Base + API on 325/329, mirroring
|
|
474
|
+
276 (guarded, roles by name, random v4 uuids, Core ids hardcoded). Also made ACL failures loud in
|
|
475
|
+
the linker (both existence GETs THROW on no `totalRecordCount`). Recorded the NYCHH PO data model:
|
|
476
|
+
`createdPo` is NULL, the PO is the customer PO (`otherRefNum`) on the Agilant vendor. Added two
|
|
477
|
+
manual operator tools (`probe_import_single_order_hh.php`, `relink_transfer_order_pos_hh.php`).
|
|
478
|
+
`cto` AGREE, `sql-reviewer` SAFE TO MERGE. **Deploy: library + worker together (via a WORKER
|
|
479
|
+
deploy — the worker box runs its own `/var/www/library` clone).** (jcardinal)
|
|
387
480
|
- 2026-09-14 - **RESOLVED: the INVENTORY_ADJUSTMENTS destination wedge.** Root cause (prod): TO 277871
|
|
388
481
|
(SO 7102750) has customer **3997 "1896 Laurel Hill Management, LLC"** — not a NYCHH customer and with
|
|
389
482
|
**no `Client_Nychh.Locations` row**, so the destination never resolved and the NOT NULL insert 1048'd
|
package/package.json
CHANGED