toga-ai 1.0.103 → 1.0.105

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.
@@ -3,7 +3,7 @@
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
5
5
  | [_underscore Framework Architecture](architecture.md) | `_underscore` is the shared PHP backend framework for **all 2.0 applications**. | _underscore/_underscore.php, _underscore/Loader.php, _underscore/Framework.php, _underscore/Model.php, _underscore/Database.php, _underscore/Query.php, _underscore/Route.php, _underscore/Component.php |
6
- | [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
6
+ | [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
7
7
  | [Client Email Template Sending](features/email-template-sending.md) | `_Model_Client_EmailTemplate` sends a stored, client-defined email template by UUID. | _underscore/Model/Client/EmailTemplate.php, _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php, _underscore/Email.php |
8
8
  | [Recursive Item Fulfillments (upstream mirroring)](features/recursive-item-fulfillments.md) | In a multi-tier supply chain a sales order (SO) spawns a purchase order (PO) that becomes another SO downstream, and so on. | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillmentItem.php, _underscore/Model/Client/ItemFulfillmentItemUnit.php, _underscore/Model/Client/ItemFulfillmentPackage.php, _underscore/Model/Compass/AdvanceShippingNotice.php, dbchanges2/Core/2026-02-13 - 75601 - RecursiveItemFulfillmentCreation.sql, dbchanges2/Core/2026-06-04 - RecursiveItemFulfillmentPut.sql |
9
- | [Tracking-Number Bridge Migration (ASN / Item Fulfillment / Item Receipt)](features/tracking-number-bridges.md) | Shipment tracking numbers used to live as **scalar FK columns** (`trackingNumberId`, `returnTrackingNumberId`) directly on the lowest-level "unit"/"item" tables | _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Prudential/AdvanceShippingNotice.php, _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Trait/Netsuite/ItemFulfillment.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql |
9
+ | [Tracking-Number Bridge Migration (ASN / Item Fulfillment / Item Receipt)](features/tracking-number-bridges.md) | Shipment tracking numbers used to live as **scalar FK columns** (`trackingNumberId`, `returnTrackingNumberId`) directly on the lowest-level "unit"/"item" tables | api2/Component/Api/V2/V2.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Prudential/AdvanceShippingNotice.php, _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Trait/Netsuite/ItemFulfillment.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql |
@@ -6,10 +6,11 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-10
9
+ updated: 2026-06-16
10
10
  owners: [mhammontree]
11
11
  files:
12
12
  - _underscore/Model/Client/ItemFulfillment.php
13
+ - _underscore/Model/Client/ItemFulfillments/TrackingNumber.php
13
14
  - _underscore/Component/Library/Carriers/Ups/Ups.php
14
15
  - _underscore/Trait/Netsuite/ItemFulfillment.php
15
16
  - _underscore/Trait/Netsuite/SalesOrder.php
@@ -39,7 +40,10 @@ decision** (dev lead Jeff, June 2026) that supersedes what the code currently do
39
40
  the DB storage field, return `{ trackingNumber, pdfLabel, fileInternalId }` or
40
41
  `{ error, trackingNumber }`. UPS path now checks `$shipmentResponse->success` and
41
42
  fast-fails on an empty service code (it previously swallowed UPS errors and surfaced
42
- a misleading "Failed to save PDF to NetSuite").
43
+ a misleading "Failed to save PDF to NetSuite"). These methods (plus `fulfill` and
44
+ `createNetsuiteItemFulfillment`'s package-detail query) resolve the tracking record by
45
+ joining **`ItemFulfillments_TrackingNumbers`** (the bridge); they previously joined the
46
+ dropped `ItemFulfillmentPackages` table — see Gotchas.
43
47
  - `_Component_Library_Carriers_Ups::submitShipmentRequest`
44
48
  (`Component/Library/Carriers/Ups/Ups.php`): returns `{ success, errorMessage,
45
49
  trackingNumber, encodedLabel }`.
@@ -104,8 +108,20 @@ attempted.
104
108
  recommended: always scope `getInventoryNumberFromSerialNumber` by location.
105
109
  - `createNetsuiteItemFulfillment` doesn't set carrier/method on the NS IF — it defaults
106
110
  (can show FedEx for a UPS shipment). Open item.
111
+ - **Carrier-label queries joined the *dropped* `ItemFulfillmentPackages` table** (a
112
+ tracking-number-bridge migration write-back gap). `upsShipmentApi`, `fedexShipmentApi`,
113
+ `fulfill`, and `createNetsuiteItemFulfillment`'s package-detail query resolved the tracking
114
+ number by joining `ItemFulfillmentPackages` — retired by the bridge migration. Post-migration
115
+ that matched the **wrong/null** `TrackingNumbers` record, so the label + `number` saved to the
116
+ wrong row (the bridge-linked record's `labelPdfFile`/`number` stayed null → **reprint had no
117
+ label**) and the NS IF was built **without its tracking number**. **Fixed 2026-06-16** by
118
+ repointing all four joins to `ItemFulfillments_TrackingNumbers`. Diagnostic tell: the
119
+ bridge-linked `TrackingNumbers` row shows `number = NULL` after a "successful" ship. Backend
120
+ change — only effective once deployed to beta. Worth grepping `ItemFulfillmentPackage::TABLE`
121
+ across `_underscore`/`api2`/`library` for the same staleness elsewhere.
107
122
 
108
123
  ## Change history
124
+ - 2026-06-16 — Repointed the carrier-label/NS-IF tracking-number queries (`upsShipmentApi`, `fedexShipmentApi`, `fulfill`, `createNetsuiteItemFulfillment`) from the dropped `ItemFulfillmentPackages` table to the `ItemFulfillments_TrackingNumbers` bridge — they had been saving the label/`number` to the wrong/null record (reprint `labelPdfFile` null; NS IF missing tracking). Confirmed working on beta. (mhammontree)
109
125
  - 2026-06-10 — Documented carrier shipping label mechanics (UPS/FedEx) + the authoritative GIF label-storage decision and NetSuite IF attachment. (mhammontree)
110
126
 
111
127
  ## Related docs
@@ -6,9 +6,10 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-10
10
- owners: ["jcardinal"]
9
+ updated: 2026-06-16
10
+ owners: ["jcardinal", "mhammontree"]
11
11
  files:
12
+ - api2/Component/Api/V2/V2.php
12
13
  - _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php
13
14
  - _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php
14
15
  - _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php
@@ -116,8 +117,26 @@ returnTrackingNumber: {...} }]`, and an IFIU's as `itemFulfillmentItemUnitTracki
116
117
  - **Deploy coupling:** renames are NOT backward compatible — apply the DB migration and deploy
117
118
  `_underscore` + `api2` + `worker` + `library` together. Run the additions/migrations DB file first;
118
119
  run the companion `..._DROPS.sql` (and the Core deletes) only after the bridges + app are confirmed.
120
+ - **⚠ Bridge ACL is incomplete — non-Super-User reads get 403 (prod + every client).** The migration
121
+ registers `AclRecordPermissions` for the new bridge records 317–322 (Core §7 = Super User; Client §6b
122
+ = per-client copies of the parent record's perms) but **never creates the
123
+ `AclLogicGroups` → `AclLogicGroupExpressions` → `AclRecordExpressions` chain beneath them.** A 2.0
124
+ record read requires that full chain (`api2/Component/Api/V2/V2.php`, `!$aclLogicGroupsDefined`), so a
125
+ role hitting a bridge route (e.g. `item-fulfillment-tracking-numbers`) gets **403 EZ-1** with DEBUG
126
+ "No ACL Logic Groups defined for ACL Record Permissions". Confirmed in **prod and every client** —
127
+ working analogs (parent 28, ASN bridges 216/217/218) have 1 logic group + 1 expression each; the IF/IR
128
+ bridges 317–322 have **0**. Downstream symptom: nested bridge fields return `null` (TOGa Supply's
129
+ fulfilled-shipments lists shipments but `itemFulfillmentTrackingNumbers` is null → reprint has no
130
+ label). **Fix:** per bridge `AclRecordPermission`, add one `AclLogicGroup` + `AclLogicGroupExpression` +
131
+ `AclRecordExpression` (`slug='all'`, `sqlExpression='1'`) — mirroring how 28 / 216 work. Run in **both**
132
+ `Core` (Super User) **and** each `Client_*` (per-role; `Client_Growrk` fixed on beta this way).
133
+ **Client-DB caveat:** `Records` is a Core-only table, so the client-side `AclRecordExpressions` insert
134
+ must derive record ids from `AclRecordPermissions` (`SELECT DISTINCT recordId ... WHERE recordId IN (...)`),
135
+ **not** join `Records`. This gap belongs back in the migration (Core §7 + Client §6b + blank-client template).
119
136
 
120
137
  ## Change history
138
+ - 2026-06-16 — Caught a migration code-update miss: four queries in `Model/Client/ItemFulfillment.php` (`upsShipmentApi`, `fedexShipmentApi`, `fulfill`, `createNetsuiteItemFulfillment`) still joined the dropped `ItemFulfillmentPackages` table to resolve tracking — repointed to `ItemFulfillments_TrackingNumbers`. See the carrier-shipping-labels doc. (mhammontree)
139
+ - 2026-06-16 — Found + documented the bridge ACL gap: the migration creates bridge `AclRecordPermissions` (317–322) but not their `AclLogicGroups`/`AclLogicGroupExpressions`/`AclRecordExpressions` chain → 403 "No ACL Logic Groups defined" for non-Super-User reads (confirmed prod + all clients). Recorded the `slug='all'`/`sqlExpression='1'` fix for Core + per-client, plus the Client-DB `Records`-table caveat. (mhammontree)
121
140
  - 2026-06-10 — Documented the tracking-number bridge migration: scalar FK columns → `*_TrackingNumbers` bridge tables across ASN/IF/IR, ASN unit table rename, packages-table consolidation. (jcardinal)
122
141
 
123
142
  ## Related docs
@@ -6,7 +6,7 @@ project: TOGa Supply
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-06-10
9
+ updated: 2026-06-16
10
10
  owners: [mhammontree]
11
11
  files:
12
12
  - toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx
@@ -40,7 +40,10 @@ GroWrk, June 2026); FedEx + UPS both need verification before prod.
40
40
  **This is the only place the SO syncs from NetSuite into Toga.**
41
41
  2. `/edit-shipment` submit (`onFormSubmit("fulfillAndShip")` in `EditShipmentForm.tsx`):
42
42
  - `saveShipment` → POST `/item-fulfillments`, `/tracking-numbers`,
43
- `/item-fulfillment-packages`.
43
+ `/item-fulfillment-tracking-numbers` (the bridge — payload key
44
+ `itemFulfillmentTrackingNumbers`, **not** the old `itemFulfillmentPackages`; see the
45
+ `_underscore` tracking-number-bridges doc). The frontend migration to the bridge is prod
46
+ commit `b5c16592d`.
44
47
  - `fulfillShipment` → GET `/item-fulfillments/upsShipmentApi` (or `fedexShipmentApi`)
45
48
  for the label, then `saveShipmentToNetsuite` →
46
49
  GET `/item-fulfillments/createNetsuiteItemFulfillment`.
@@ -91,6 +94,29 @@ likely moves to the backend.
91
94
  `hostname LIKE '%ups.com%'`, `responsePayload`).
92
95
  - React warning: `setState`-in-render in `ShipmentItemsTable.tsx` (~line 149,
93
96
  `clearErrors` inside a `setRowsClicked` updater) — move out of the updater.
97
+ - **Local frontend runs against the *deployed* beta backend.** The dev frontend
98
+ (`growrk.togasupply:5173`) calls `api.beta.togahub.com`, so **any `_underscore` change
99
+ only takes effect after a deploy to beta** — a fix you made locally looks "unfixed" until
100
+ deployed (and a local frontend ahead of the deployed backend produces skew errors, e.g.
101
+ `Unknown named parameter $labelFileInternalId` when the FE passes a param the deployed
102
+ method lacks). When chasing a beta error, confirm what commit is deployed before assuming
103
+ the local code is what ran.
104
+ - **Fulfilled vs pending is driven by `ItemFulfillments.dtSubmitted`** (`ShipmentsApi.ts`
105
+ `getShipments`: fulfilled = `dtSubmitted ne null`, pending = `eq null`). `dtSubmitted` is
106
+ set **only** by `createNetsuiteItemFulfillment` on a successful NetSuite IF creation
107
+ (`Trait/Netsuite/ItemFulfillment.php`). So if the NetSuite step fails, the shipment stays
108
+ on the **pending** page, never the fulfilled one — "no fulfilled shipments" usually means
109
+ the NS step didn't complete, not a UI bug.
110
+ - **`createNetsuiteItemFulfillment` line mapping is fragile on partial/already-fulfilled
111
+ orders.** It `get`s the NetSuite SO and sets the fulfillment `orderLine` = the SO's `line`.
112
+ If a line is already fulfilled (or NetSuite re-sequences the fulfillable sublist because a
113
+ line isn't committed), NetSuite returns **"Unable to find a matching line for sublist item
114
+ with key: [orderLine] and value: [N]"**. Test against an SO line that's genuinely open;
115
+ robust fix = NetSuite `initialize`/`transform` (only exposes fulfillable lines).
116
+ - **Bridge ACL blocks the tracking/label read (reprint).** Reading tracking via the
117
+ `item-fulfillment-tracking-numbers` bridge requires the bridge record's ACL logic-group
118
+ chain to exist for the user's role, or it 403s and `itemFulfillmentTrackingNumbers` returns
119
+ `null` (so reprint has no label). See the tracking-number-bridges doc's ACL gotcha + fix.
94
120
 
95
121
  ## Remaining work
96
122
 
@@ -112,4 +138,5 @@ not the base `_Model_Client_ItemFulfillment`. Tested with GroWrk; UPS support wa
112
138
  for Compass and is not yet in prod.
113
139
 
114
140
  ## Change history
141
+ - 2026-06-16 — Drove the full beta flow green for UPS/GroWrk. Updated the save step to the `/item-fulfillment-tracking-numbers` bridge (FE commit `b5c16592d`, key `itemFulfillmentTrackingNumbers`). Added gotchas: local-FE↔deployed-beta-BE skew, `dtSubmitted` fulfilled/pending gating, `createNetsuiteItemFulfillment` orderLine fragility on partial/already-fulfilled orders, and the bridge-ACL 403 that nulls tracking/labels (reprint). (mhammontree)
115
142
  - 2026-06-10 — Documented the Fulfill & Ship flow (SO sync, label purchase, NetSuite IF creation, success gating, reprint). Driven green on beta for UPS/GroWrk; FedEx + prod verification pending. (mhammontree)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.103",
3
+ "version": "1.0.105",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",