toga-ai 1.0.701 → 1.0.703
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/library/features/netsuite-suiteql-rest-shim.md +20 -1
- package/knowledge/1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md +82 -3
- package/knowledge/2.0/apps/api2/features/v2-rest-query-contract.md +20 -1
- package/knowledge/clients/nychh/features/netsuite-inventory-adjustment-fulfillment-link.md +18 -1
- package/knowledge/clients/nychh/features/netsuite-transfer-order-import.md +15 -2
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-30
|
|
10
10
|
owners: [dfranks, jcardinal, kyalamarthi]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/netsuite/rest.php
|
|
@@ -156,6 +156,19 @@ Forecast2 tables already store.
|
|
|
156
156
|
defensively from the per-id REST `salesOrder` sublist already fetched, so the SO-item shim matches what
|
|
157
157
|
the loop consumes. Same "reproduce the full sibling shape" class as the PO-shim completion.
|
|
158
158
|
|
|
159
|
+
- **⚠ `fetchPurchaseOrderById` must number PO lines by the NetSuite `line`, not `linesequencenumber` —
|
|
160
|
+
and the PO record sublist has NO `lineUniqueKey` to join on (fixed 2026-08-30).** Item receipts match
|
|
161
|
+
their PO line by the receipt's `orderLine` (the NetSuite **`line`** number). `fetchPurchaseOrderById`
|
|
162
|
+
numbered `PurchaseOrderItems.lineNumber` by physical `linesequencenumber` (1..N), so when a middle PO
|
|
163
|
+
line was deleted in NetSuite the real lines are e.g. 1,2,4 and a receipt for line 4 failed `EV-12`
|
|
164
|
+
"unable to find a unique match" (GroWrk item receipts, PO **168223**). `listPurchaseOrders` already did
|
|
165
|
+
this right via `lineUniqueKey`; the per-id path did not. **GOTCHA:** the REST `purchaseOrder` record
|
|
166
|
+
line sublist (`expandSubResources=true`) exposes **`line` but NO `lineUniqueKey`/`uniquekey`** to join
|
|
167
|
+
on (unlike `salesOrder`). **Fix:** fetch the record with `expandSubResources=true` and **ZIP the REST
|
|
168
|
+
sublist (physical line order) positionally against the SuiteQL rows (`ORDER BY linesequencenumber`)**,
|
|
169
|
+
cross-checking item id, then number each line by the NetSuite `line` (fall back to `linesequencenumber`
|
|
170
|
+
if the item ids disagree). Self-heals on the next receipt sync (it re-imports the PO). Same "join a
|
|
171
|
+
NetSuite line on `line`, not `linesequencenumber`" lesson as the `tl.id` semantics above.
|
|
159
172
|
- **A shim must produce the SOAP object's SHAPE, not just its scalar fields — an absent nested list
|
|
160
173
|
crashes 1.0 (2026-08-29).** `fetchCustomerById()`'s `addressbookList` was where the AIG lookup phase
|
|
161
174
|
crashed: a REST customer with no/odd address made the shim omit the nested `addressbook` structure the
|
|
@@ -249,6 +262,12 @@ None — uniform across clients (NetSuite is a single shared account).
|
|
|
249
262
|
|
|
250
263
|
## Change history
|
|
251
264
|
|
|
265
|
+
- 2026-08-30 — Recorded that **`fetchPurchaseOrderById` numbered PO lines by `linesequencenumber` instead
|
|
266
|
+
of the NetSuite `line`** — a receipt for a post-gap line (PO with a deleted middle line, real lines
|
|
267
|
+
1,2,4) failed `EV-12` "unable to find a unique match" (GroWrk PO 168223). The PO record line sublist
|
|
268
|
+
exposes `line` but **no `lineUniqueKey`** (unlike `salesOrder`), so the fix zips the REST sublist
|
|
269
|
+
positionally against the `ORDER BY linesequencenumber` SuiteQL rows (item-id cross-checked) and numbers
|
|
270
|
+
by `line`. `library`-only; self-heals on next receipt sync. (jcardinal)
|
|
252
271
|
- 2026-08-29 — **Completed `fetchPurchaseOrderById` to the full `listPurchaseOrders` shape** and added
|
|
253
272
|
the SO-item `createdPo`/`poRate` shim fields (same deploy/verify session, after the entity fix). The
|
|
254
273
|
entity SELECT was only the first missing field: `syncPurchaseOrderFromNetsuite` reads `createdFrom`,
|
|
@@ -6,7 +6,7 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-30
|
|
10
10
|
owners: ["dfranks", "bala", "jcardinal", "mhammontree", "snaredla"]
|
|
11
11
|
files:
|
|
12
12
|
- worker/crons/toga2/netsuite/common_sync_togasupply.php
|
|
@@ -314,6 +314,21 @@ Parameters are stored **per client DB** but accessed **through the TOGa2 API**,
|
|
|
314
314
|
checkbox `custbody_stocking_order`, read by `App_Api_Toga2::isTransferOrder()`/`isStockingOrder()`
|
|
315
315
|
— **not** a dollar/hold heuristic. Full mechanics, PO bridges, and origin-location resolution:
|
|
316
316
|
[NYCHH NetSuite → TransferOrders import](../../../clients/nychh/features/netsuite-transfer-order-import.md).
|
|
317
|
+
- **Transfer-order integration is governed by TWO DISTINCT wrapper flags — a master enable switch and a
|
|
318
|
+
NYCHH-only classification-mode switch (do not conflate them).**
|
|
319
|
+
- **`IS_ENABLED_INTEGRATION_TRANSFER_ORDERS`** — the master "do transfer-order integration at all"
|
|
320
|
+
switch, defined in every `sync_togasupply_*.php` launcher. `true` for **GroWrk, Adyen, Elite, and
|
|
321
|
+
NYCHH**; `false` for the rest. These are the clients exercised by the shared
|
|
322
|
+
`syncTransferOrderFromNetsuite` / `getTransferOrderItemsByUuid` fixes (2026-08-30 above).
|
|
323
|
+
- **`IS_ENABLED_TRANSFER_ORDER_STOCKING_FLAG_ROUTING`** — a **separate classification-mode** switch,
|
|
324
|
+
**NYCHH-only** (`sync_togasupply_hh.php`), that makes `App_Api_Toga2::isTransferOrder()` classify by
|
|
325
|
+
the NetSuite `custbody_stocking_order` checkbox instead of the legacy rule.
|
|
326
|
+
|
|
327
|
+
These orders **masquerade as NetSuite sales orders** and are split into `TransferOrders` vs
|
|
328
|
+
`SalesOrders` by `isTransferOrder()`. The classification **SIGNAL is per-client**: **NYCHH** routes by
|
|
329
|
+
the `custbody_stocking_order` stocking flag (above); **GroWrk / Elite / Adyen** use the **legacy rule**
|
|
330
|
+
(`holdInvoice AND total === 0`). Do **not** assume one universal signal — the master enable is shared,
|
|
331
|
+
the classification mode is not.
|
|
317
332
|
- `isParentCustomer` — `true` walks NetSuite child customers (`listChildCustomers`); `false`
|
|
318
333
|
syncs the single customer. Prudential-EDI and the live Quad wrapper use `false`.
|
|
319
334
|
- The original combined-array entries used `App_Api_Toga2::CLIENT_UUID_*` consts for Quad and
|
|
@@ -660,8 +675,9 @@ Parameters are stored **per client DB** but accessed **through the TOGa2 API**,
|
|
|
660
675
|
api2 request dies before the middleware and writes **no** `Logs_<Client>.Api` row — then read
|
|
661
676
|
`Logs.Issue` instead; see the 2026-08-18 poison-order diagnostic trap above.)
|
|
662
677
|
|
|
663
|
-
- **⚠ The shared `syncTransferOrderFromNetsuite` item-sync
|
|
664
|
-
`TransferOrderItems` every run (found 2026-08-29
|
|
678
|
+
- **⚠ The shared `syncTransferOrderFromNetsuite` item-sync WAS NON-IDEMPOTENT — created DUPLICATE
|
|
679
|
+
`TransferOrderItems` every run (found 2026-08-29; ROOT-CAUSED + FIXED 2026-08-30; affected stocking-SO
|
|
680
|
+
TOs too).** The shared
|
|
665
681
|
item loop does not reconcile against existing rows, so every sync appends the TO's items again: an
|
|
666
682
|
attempted real-TrnfrOrd import reached **22 duplicate items all `lineNumber` 1** on TO #15, and a
|
|
667
683
|
**pre-existing stocking-SO** transfer order (`Client_Nychh.TransferOrders` id **1** / number **62541**)
|
|
@@ -675,8 +691,71 @@ Parameters are stored **per client DB** but accessed **through the TOGa2 API**,
|
|
|
675
691
|
doc. **Do not re-enable real-TO receipts until the shared item loop is made idempotent (which also
|
|
676
692
|
fixes the stocking-SO dups and cleans the pre-existing TO 1).**
|
|
677
693
|
|
|
694
|
+
**ROOT CAUSE + FIX (2026-08-30).** The non-idempotency was NOT a bad reconcile loop — it was that
|
|
695
|
+
`syncTransferOrderFromNetsuite` read `$transferOrder->transferOrderItems` for its idempotency lookup,
|
|
696
|
+
and **api2 never inlines that child collection** (`transfer-orders` has no `Core.InherentRecordChildren`
|
|
697
|
+
row, unlike its sibling order types sales-orders/purchase-orders/item-fulfillments), so the lookup was
|
|
698
|
+
**always empty** and every line re-INSERTed each run (TransferOrder 26 grew to 84 duplicate items). New
|
|
699
|
+
private helper `App_Api_Toga2::getTransferOrderItemsByUuid` now fetches TO items via the **direct
|
|
700
|
+
`GET /transfer-order-items`** query (join `TransferOrders` by uuid, high `recordsPerPage`), used by both
|
|
701
|
+
`syncTransferOrderFromNetsuite` (idempotency) and `syncItemFulfillmentFromNetsuite` (TO-line linking);
|
|
702
|
+
**first-wins**, so pre-existing dups keep one canonical row and no new dups are created. Shared fix —
|
|
703
|
+
all TO clients (GroWrk, Adyen, Elite). The 2.0 root cause and the parity migration that also adds the
|
|
704
|
+
missing `InherentRecordChildren` row are on the
|
|
705
|
+
[V2 REST query contract](../../../2.0/apps/api2/features/v2-rest-query-contract.md). This closes
|
|
706
|
+
rebuild-spec **step 1** on the
|
|
707
|
+
[NYCHH TransferOrders import](../../../clients/nychh/features/netsuite-transfer-order-import.md); the
|
|
708
|
+
other real-TrnfrOrd-receipt blockers (api2 `transferOrderItem` reference metadata, receipt-line↔TO-line
|
|
709
|
+
mapping) remain.
|
|
710
|
+
|
|
711
|
+
- **⚠ Inventory-adjustment sync skipped NULL-quantity NetSuite serial DETAIL sub-lines (fixed 2026-08-30).**
|
|
712
|
+
NetSuite serialized inventory-number DETAIL sub-lines **repeat the main item line** with a NULL
|
|
713
|
+
`transactionline.quantity`; `syncInventoryAdjustmentFromNetsuite` tried to write
|
|
714
|
+
`InventoryAdjustmentItems` with a null `quantityAdjustBy` → api2 `EV-10` / MySQL **1048**
|
|
715
|
+
"quantityAdjustBy cannot be null." Those sub-lines carry no adjustment (the real qty is on the summary
|
|
716
|
+
line). **Fix (`library`):** skip lines whose `adjustQtyBy` is null in **BOTH** passes over
|
|
717
|
+
`inventoryList->inventory` (the item-build pass and the serial/unit pass). Shared fix; unblocked NYCHH
|
|
718
|
+
inventory adjustments.
|
|
719
|
+
- **⚠ Item-fulfillment stale-item prune must delete tracking-number children before the unit AND the item
|
|
720
|
+
(fixed 2026-08-30).** In `syncItemFulfillmentFromNetsuite`'s cleanup loop, deleting a stale
|
|
721
|
+
item-fulfillment-item-**unit** failed api2 `EV-11` / MySQL **1451** (FK
|
|
722
|
+
`ItemFulfillmentItemUnits_TrackingNumbers → ItemFulfillmentItemUnits`, RESTRICT) because the
|
|
723
|
+
tracking-number children were not removed first — freezing the fulfillment sync at `1-RUNNING`. **Fix:**
|
|
724
|
+
delete each unit's `itemFulfillmentItemUnitTrackingNumbers` (route
|
|
725
|
+
`/item-fulfillment-item-unit-tracking-numbers`) before the unit, and each item's
|
|
726
|
+
`itemFulfillmentItemTrackingNumbers` (`/item-fulfillment-item-tracking-numbers`) before the item; added
|
|
727
|
+
`itemFulfillmentItems.itemFulfillmentItemTrackingNumbers.uuid` to the GET `fields`. Shared fix (all
|
|
728
|
+
clients); resolved NYCHH ITEM_FULFILLMENTS. (Same delete-children-first rule as the 317/318/319 bridge
|
|
729
|
+
pruning above — extended to the item- and unit-level tracking children in the stale-item path.)
|
|
730
|
+
- **⚠ Item-fulfillment `/units` lookup must be scoped by the line's product on the TRANSFER-ORDER path too
|
|
731
|
+
(fixed 2026-08-30).** A serialized unit failed `POST /units` with `EV-10` / MySQL **1062** "Duplicate
|
|
732
|
+
entry '<itemId>-<serial>' for key `Units.itemId_serialNumber`" because the `Units` lookup filtered by
|
|
733
|
+
item **only on the sales-order path** (`if ($uuidSalesOrderItem)`); a transfer-order line searched
|
|
734
|
+
`Units` by `serialNumber` alone, and with **duplicate `Items` sharing a partNumber** (GroWrk Items 3861
|
|
735
|
+
& 4086, both `21QT006VUS`, each with a unit for serial `SPF65LSAC`) the serial-only lookup returned 2 →
|
|
736
|
+
it did not reuse the existing unit and the create collided on `(itemId, serialNumber)`. **Fix:** resolve
|
|
737
|
+
the line's product uuid for **both** paths into a new `$uuidItemForLine` (SO: from the sales-order-item
|
|
738
|
+
lookup; TO: from `getTransferOrderItemsByUuid`'s `->item->uuid`, so that helper was bumped to **depth
|
|
739
|
+
2**) and scope the `Units` lookup by it (returns exactly 1 → reuse). Latent data problem behind it:
|
|
740
|
+
**duplicate `Items` with the same `partNumber`** should be reconciled later (the fix is robust to it).
|
|
741
|
+
GroWrk ITEM_FULFILLMENTS went from stuck `1-RUNNING` (since Aug 21) to green.
|
|
742
|
+
|
|
678
743
|
## Change history
|
|
679
744
|
|
|
745
|
+
- 2026-08-30 — **Rebuilt GroWrk transfer-order integration + shared IF/inventory-adjustment fixes (all in
|
|
746
|
+
`library/app/api/toga2.php`).** Root-caused the shared `syncTransferOrderFromNetsuite` **non-idempotency**
|
|
747
|
+
to api2 never inlining `transferOrderItems` (`transfer-orders` has no `InherentRecordChildren` row) — the
|
|
748
|
+
idempotency lookup was always empty, so lines re-INSERTed every run (TransferOrder 26 → 84 dup items);
|
|
749
|
+
fixed with a new `getTransferOrderItemsByUuid` direct `GET /transfer-order-items` helper (first-wins),
|
|
750
|
+
used for both TO idempotency and IF→TO-line linking (all TO clients — GroWrk/Adyen/Elite). Fixed the IF
|
|
751
|
+
stale-item prune (delete unit/item tracking-number children before the unit/item — FK RESTRICT/1451/EV-11)
|
|
752
|
+
and the IF `/units` lookup (scope by the line's product on the TO path too via `$uuidItemForLine`, helper
|
|
753
|
+
bumped to depth 2 — a serial-only lookup hit two duplicate `Items` sharing a partNumber → 1062 dup-key),
|
|
754
|
+
and the inventory-adjustment sync (skip NULL-`adjustQtyBy` NetSuite serial DETAIL sub-lines in both passes
|
|
755
|
+
— 1048/EV-10). GroWrk IF unfroze (stuck since Aug 21); NYCHH IF + inventory adjustments resolved. Developer
|
|
756
|
+
also applied the 2.0 parity migration adding the `transfer-orders → transfer-order-items`
|
|
757
|
+
`InherentRecordChildren` row (dbchanges2) — see
|
|
758
|
+
[V2 REST query contract](../../../2.0/apps/api2/features/v2-rest-query-contract.md). (jcardinal)
|
|
680
759
|
- 2026-08-29 — **Stabilize session, additional durable findings.** (a) `syncItemReceiptFromNetsuite`
|
|
681
760
|
now **auto-creates a serialized unit's OWN location** (`custitemnumber_location` → POST `/locations`)
|
|
682
761
|
before the `/units` write, mirroring the item-line location create — a general fix surfaced by GroWrk
|
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-30
|
|
10
10
|
owners: [tcox, bala, apeterson, jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Component/Api/V2/V2.php
|
|
@@ -129,6 +129,13 @@ have **none** — `transfer-orders` (312) had **zero** as of 2026-08-28, so `tra
|
|
|
129
129
|
appears in the record payload no matter what `fields`/`depth` ask for. The client must call the
|
|
130
130
|
**nested route** instead:
|
|
131
131
|
|
|
132
|
+
> **This exact missing row was the ROOT CAUSE of a 1.0 sync bug (2026-08-30).** The NetSuite importer's
|
|
133
|
+
> `syncTransferOrderFromNetsuite` read `$transferOrder->transferOrderItems` for its idempotency lookup;
|
|
134
|
+
> because api2 never inlined that collection, the lookup was **always empty** and every line re-INSERTed
|
|
135
|
+
> each run (TransferOrder 26 grew to 84 duplicate items). The 1.0 fix was a direct
|
|
136
|
+
> `GET /transfer-order-items` query — see
|
|
137
|
+
> [per-client sync](../../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md).
|
|
138
|
+
|
|
132
139
|
```
|
|
133
140
|
GET /v2/transfer-orders/{uuid}/transfer-order-items
|
|
134
141
|
```
|
|
@@ -141,6 +148,12 @@ GET /v2/transfer-orders/{uuid}/transfer-order-items
|
|
|
141
148
|
and NetSuite sync — so the blast radius has to be surveyed first. The transfer-order build
|
|
142
149
|
deliberately declined to add one and named the child route in the consuming surface's config
|
|
143
150
|
instead. See [Transfer Orders page](../../toga25-supply/features/transfer-orders-page.md).
|
|
151
|
+
**Reversed 2026-08-30:** a later dbchanges2 Core migration **did** add the
|
|
152
|
+
`transfer-orders (312) → transfer-order-items (313)` row (route-based lookup + `NOT EXISTS` guard), so
|
|
153
|
+
`GET /transfer-orders` now inlines `transferOrderItems` like its sibling order types — the parity
|
|
154
|
+
alternative to the 1.0 direct-query fix (the developer applied both). **Ordering caveat:** the
|
|
155
|
+
migration must run **after** the duplicate-`TransferOrderItems` cleanup, or the inline expansion
|
|
156
|
+
returns all the dup rows.
|
|
144
157
|
|
|
145
158
|
### ⚠ `join` / `ojoin` drive the WHERE/filter — NOT the response shape
|
|
146
159
|
|
|
@@ -302,6 +315,12 @@ where=(field:op:value,LOGIC,field:op:value,(nested,OR,nested))
|
|
|
302
315
|
write against the DB / `Logs_<Client>.Api`, not the echo. See
|
|
303
316
|
[NYCHH inventory-adjustment → item-fulfillment linking](../../../../clients/nychh/features/netsuite-inventory-adjustment-fulfillment-link.md).
|
|
304
317
|
(jcardinal)
|
|
318
|
+
- 2026-08-30 — Recorded that the missing `transfer-orders` `InherentRecordChildren` row was the **root
|
|
319
|
+
cause** of the 1.0 NetSuite sync duplicating `TransferOrderItems` every run (idempotency read
|
|
320
|
+
`$transferOrder->transferOrderItems`, always empty → re-INSERT; TransferOrder 26 → 84 dups), and that a
|
|
321
|
+
dbchanges2 Core migration **added** the `transfer-orders (312) → transfer-order-items (313)` row (route
|
|
322
|
+
lookup + `NOT EXISTS` guard) for parity — reversing the earlier decision to decline it. Ordering caveat:
|
|
323
|
+
run it **after** the duplicate-TO-item cleanup or the inline expansion returns the dups. (jcardinal)
|
|
305
324
|
- 2026-08-28 — Documented two response-shape facts hit while building the Transfer Orders modal.
|
|
306
325
|
**`calcDepth` defaults to 1**, so a `FIELD_SQL` calculated field on a record one FK hop out returns
|
|
307
326
|
`null` with **no** message (Location's `_address*` fields needed `calcDepth: 2`) — raise it one per
|
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: nychh
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/toga2.php
|
|
@@ -182,6 +182,14 @@ this feature on the scheduled cron.
|
|
|
182
182
|
|
|
183
183
|
- **Older adjustments have no link.** `custbody_stock_adjustment` was added in NetSuite <1 year ago;
|
|
184
184
|
adjustments predating it will never populate an FK — not a bug.
|
|
185
|
+
- **A NULL `itemFulfillmentId`/`itemFulfillmentItemId` on a NYCHH adjustment is usually CORRECT, not a
|
|
186
|
+
bug.** Only records whose NetSuite multi-select body field `custbody_stock_adjustment` is populated get a
|
|
187
|
+
link — and **0 of 27** NYCHH adjustments carry a value there (only **~1 in 40** recent adjustments
|
|
188
|
+
account-wide do). So a null header/line FK almost always means NetSuite has **no** stock-adjustment link
|
|
189
|
+
on that record, not a code fault. The REST shim's read of `custbody_stock_adjustment` as a **scalar
|
|
190
|
+
SuiteQL column on `transaction`** works when the field IS populated (SuiteQL omits null columns from a
|
|
191
|
+
row, so an empty field just looks "absent"); the shim only builds the link ref when a value exists. (A
|
|
192
|
+
clarifying comment was added at the `customFieldList` build in `rest.php` `fetchInventoryAdjustmentById`.)
|
|
185
193
|
- **Reading the product uuid at `depth=2` silently returns nothing** — the level-3 `item` object is
|
|
186
194
|
omitted at max depth. Use `depth=3` + explicit nested `fields` (see above).
|
|
187
195
|
- **A V2 PUT echo that omits `itemFulfillment` does NOT mean the write failed** — verify against the
|
|
@@ -192,6 +200,15 @@ this feature on the scheduled cron.
|
|
|
192
200
|
|
|
193
201
|
## Change history
|
|
194
202
|
|
|
203
|
+
- 2026-08-30 — Verified that NYCHH adjustments with a NULL `itemFulfillmentId`/`itemFulfillmentItemId`
|
|
204
|
+
are **correct, not a bug**: 0 of 27 NYCHH adjustments populate NetSuite `custbody_stock_adjustment`
|
|
205
|
+
(~1 in 40 account-wide), so most carry no link. Confirmed the shim's scalar SuiteQL read of the field
|
|
206
|
+
works when populated (SuiteQL omits null columns, so an empty field reads as absent) and only builds the
|
|
207
|
+
link ref when a value exists; added a clarifying comment at the `customFieldList` build in `rest.php`
|
|
208
|
+
`fetchInventoryAdjustmentById`. Also: the shared inventory-adjustment sync now **skips NULL-`adjustQtyBy`
|
|
209
|
+
NetSuite serial DETAIL sub-lines** (they repeat the main line with null qty → previously 1048/EV-10) —
|
|
210
|
+
shared fix on the [per-client sync](../../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md).
|
|
211
|
+
(jcardinal)
|
|
195
212
|
- 2026-08-29 — **Migrated the feature to direct FK columns over REST, and made it fail loud.**
|
|
196
213
|
Replaced the two bridge tables with direct FK columns
|
|
197
214
|
(`InventoryAdjustments.itemFulfillmentId` reusing `RecordField` 2517/record 154;
|
|
@@ -6,7 +6,7 @@ project: Library
|
|
|
6
6
|
client: nychh
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-30
|
|
10
10
|
owners: [jcardinal]
|
|
11
11
|
files:
|
|
12
12
|
- library/app/api/toga2.php
|
|
@@ -213,7 +213,12 @@ refused on the prod client cluster):
|
|
|
213
213
|
**REBUILD SPEC (all four, in order, before re-enabling + removing the skip):**
|
|
214
214
|
1. Make the shared `syncTransferOrderFromNetsuite` item-sync **idempotent** (reconcile against existing
|
|
215
215
|
`TransferOrderItems` by a stable key) — this also fixes the stocking-SO dups and must **clean the
|
|
216
|
-
pre-existing TO 1** (13 dups).
|
|
216
|
+
pre-existing TO 1** (13 dups). **DONE 2026-08-30:** root cause was api2 never inlining
|
|
217
|
+
`transferOrderItems` (`transfer-orders` has no `InherentRecordChildren` row → idempotency read always
|
|
218
|
+
empty); fixed via the new `getTransferOrderItemsByUuid` direct `GET /transfer-order-items` helper
|
|
219
|
+
(first-wins) — see
|
|
220
|
+
[per-client sync](../../../1.0/apps/worker/features/netsuite-togasupply-per-client-sync.md). Steps 2–4
|
|
221
|
+
still remain, so real-TrnfrOrd receipts stay skipped.
|
|
217
222
|
2. Add api2 **`TransferOrderItems` reference metadata** so a receipt line can resolve its TO item by a
|
|
218
223
|
searchable identifier (the analogue of the `PurchaseOrderItems` `(purchaseOrder, lineNumber)` setup).
|
|
219
224
|
3. **Verify the receipt-line ↔ TO-line mapping** (the `orderLine` ↔ TO-item `lineNumber` correspondence).
|
|
@@ -236,6 +241,14 @@ refused on the prod client cluster):
|
|
|
236
241
|
|
|
237
242
|
## Change history
|
|
238
243
|
|
|
244
|
+
- 2026-08-30 — Rebuild-spec **step 1 (make `syncTransferOrderFromNetsuite` idempotent) is DONE**: the
|
|
245
|
+
non-idempotency root cause was api2 never inlining `transferOrderItems` (`transfer-orders` has no
|
|
246
|
+
`InherentRecordChildren` row), so the idempotency read was always empty; fixed via the new
|
|
247
|
+
`getTransferOrderItemsByUuid` direct `GET /transfer-order-items` helper (first-wins). Steps 2–4 (api2
|
|
248
|
+
`TransferOrderItems` reference metadata, receipt-line↔TO-line mapping, re-enable) still remain, so
|
|
249
|
+
real-TrnfrOrd item receipts stay skipped. A dbchanges2 parity migration also added the
|
|
250
|
+
`transfer-orders → transfer-order-items` `InherentRecordChildren` row — see
|
|
251
|
+
[V2 REST query contract](../../../2.0/apps/api2/features/v2-rest-query-contract.md). (jcardinal)
|
|
239
252
|
- 2026-08-29 — Recorded the **real NetSuite `TrnfrOrd` item-receipt feature as DEFERRED/SKIPPED**
|
|
240
253
|
(documented skip in `common_sync_togasupply.php`, like the `RtnAuth` skip) after attempting it and
|
|
241
254
|
hitting three blockers: the shared `syncTransferOrderFromNetsuite` item-sync is **non-idempotent**
|
package/package.json
CHANGED