toga-ai 1.0.327 → 1.0.328
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/2.0/apps/_underscore/INDEX.md +1 -1
- package/knowledge/2.0/apps/_underscore/features/carrier-shipping-labels.md +44 -11
- package/knowledge/2.0/apps/_underscore/features/tracking-number-bridges.md +10 -3
- package/knowledge/2.0/apps/api2/workflows/codepipeline-codeconnections-deploy.md +12 -1
- package/knowledge/2.0/apps/toga2-supply/INDEX.md +1 -1
- package/knowledge/2.0/apps/toga2-supply/features/fulfill-and-ship.md +76 -6
- package/knowledge/clients/growrk/profile.md +9 -2
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php |
|
|
22
22
|
| [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, dbchanges2/Client_Compass/2026-07-02a - FixSA133377TrackingSerialAndDuplicateIF.sql |
|
|
23
23
|
| [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, _underscore/Model/Client/AclRecordScript.php, _underscore/Model/Core/RecordScript.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php |
|
|
24
|
-
| [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, dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql, dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql |
|
|
24
|
+
| [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, dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Growrk/2026-07-13a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql, dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql |
|
|
25
25
|
| [Units for Items for Purchase Orders — Data Structure](features/units-for-items-for-purchase-orders.md) | Describes how unit (serialized inventory) data is linked to sales-order and purchase-order line items behind the `units-for-items-for-purchase-orders` TableView | |
|
|
26
26
|
| [Refreshing a Local Dev Database from Beta (dev-sandbox)](workflows/local-db-refresh-from-beta.md) | How to reset a local 2.0 dev database from the **beta / dev-sandbox** environment: dump each schema (`Core`, `Client_<Id>`, `Logs_<Id>`, …) from the beta host, | api2/Config/, _underscore/Loader.php, _underscore/Model/Client/BundleTranslation.php, api2/Component/Api/V2/V2.php, toga25-supply/sync_compasscanada_schema.sql |
|
|
27
27
|
| [Running a 2.0 App Locally (browser, end-to-end via api2)](workflows/running-a-2.0-app-locally.md) | The full dependency chain required to run a 2.0 client app **through the browser**, end-to-end, against a **local `api2`** (e.g. | _underscore/Environment.php, _underscore/Config.php, _underscore/Database.php, _underscore/Route.php, api2/Component/Api/V2/V2.php, api2/index.php, api2/.htaccess |
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-14
|
|
10
10
|
owners: [mhammontree]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/ItemFulfillment.php
|
|
@@ -63,12 +63,17 @@ record instead of a hardcoded constant.
|
|
|
63
63
|
record by UUID, reads its stored raw PNG (`labelPdfFile`), and returns a **combined base64 PDF**
|
|
64
64
|
via `buildFromPngLabels`. Replaced the frontend `pdf-lib` merge (which broke once labels became
|
|
65
65
|
PNG — it expected a base64 PDF). Requires a Client-DB `AclRecordScripts` dispatch grant or it
|
|
66
|
-
403s — see the ACL permission-chain doc's record-script dispatch section.
|
|
66
|
+
403s — see the ACL permission-chain doc's record-script dispatch section. **`$caption` accepts a
|
|
67
|
+
position-aligned CSV** (one caption per uuid, in order) so a combined outbound+return PDF can
|
|
68
|
+
caption only the return page "Return Label".
|
|
67
69
|
- `_Model_Client_ItemFulfillment::generateReturnLabel(&$api, $uuid)`
|
|
68
|
-
(`Model/Client/ItemFulfillment.php`): builds a per-carrier **return** shipment request
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
`
|
|
70
|
+
(`Model/Client/ItemFulfillment.php`): builds a per-carrier **return** shipment request, creates a
|
|
71
|
+
**second** `TrackingNumbers` record, stores its raw PNG, links it as `returnTrackingNumberId` on
|
|
72
|
+
the `ItemFulfillments_TrackingNumbers` header bridge, and returns `returnTrackingNumberUuid`. The
|
|
73
|
+
**return address is now per-fulfillment**: it joins `returnAddressId` → `Addresses`/`States` and
|
|
74
|
+
ships **from** that saved return address, falling back to the `RETURN_ADDRESS_*` config constants
|
|
75
|
+
when `returnAddressId` is unset (superseding the earlier fixed `RETURN_ADDRESSES` set). The return
|
|
76
|
+
leg **reuses the outbound** weight/carrier/method/account (see the return-leg semantic below).
|
|
72
77
|
- `getLabelFormat()` (client UPS config helper): now **defaults to `PNG`** (was ZPL) and validates
|
|
73
78
|
against a supported-format allowlist, so a carrier label reliably comes back as an embeddable PNG.
|
|
74
79
|
- `_Component_Library_Carriers_Ups::submitShipmentRequest`
|
|
@@ -117,11 +122,28 @@ reprint combine moved to the backend `reprintLabelsApi` scripted API and return-
|
|
|
117
122
|
**Return labels.** When `ShipmentRequest->isReturn` is set, the carrier request injects the
|
|
118
123
|
return-service flags: UPS `Shipment.ReturnService.Code = '9'` (Print Return Label); FedEx
|
|
119
124
|
`shipmentSpecialServices.returnShipmentDetail` (`returnType = PRINT_RETURN_LABEL`, RMA reason
|
|
120
|
-
"Customer Return"). `generateReturnLabel` builds the return request
|
|
121
|
-
|
|
122
|
-
`
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
"Customer Return"). `generateReturnLabel` builds the return request, creates a 2nd
|
|
126
|
+
`TrackingNumbers` record, stores its raw PNG, links `returnTrackingNumberId` on the
|
|
127
|
+
`ItemFulfillments_TrackingNumbers` bridge, and returns `returnTrackingNumberUuid`.
|
|
128
|
+
|
|
129
|
+
**Return address is now per-fulfillment (2026-07).** `generateReturnLabel` joins
|
|
130
|
+
`ItemFulfillments.returnAddressId` → `Addresses`/`States` and ships **from** that saved return
|
|
131
|
+
address; it falls back to the `RETURN_ADDRESS_*` config constants when `returnAddressId` is unset.
|
|
132
|
+
This supersedes the earlier fixed `RETURN_ADDRESSES` set (Naperville/Plainview).
|
|
133
|
+
|
|
134
|
+
**Return-leg semantic (important — only the address is independent).** The return leg **reuses the
|
|
135
|
+
outbound shipment's weight/carrier/method/account**: `packageWeightPounds` = the outbound tracking
|
|
136
|
+
weight, and the return `TrackingNumber`'s carrier/method/account = the outbound's. **Only the
|
|
137
|
+
return ADDRESS is persisted** (`returnAddressId`). The TOGa Supply return modal's
|
|
138
|
+
weight/dims/carrier fields are prefilled from outbound **for display only** and are not persisted
|
|
139
|
+
or independently used — see the fulfill-and-ship doc's edit-trap gotcha.
|
|
140
|
+
|
|
141
|
+
**NetSuite tracking now includes both legs (fixed 2026-07).** `Trait/Netsuite/ItemFulfillment.php::createNetsuiteItemFulfillment`
|
|
142
|
+
read the **retired `itemFulfillmentPackages`** (absent post-bridge), so **no tracking reached
|
|
143
|
+
NetSuite** at all. It now iterates the `itemFulfillmentTrackingNumbers` bridge and pushes the
|
|
144
|
+
**outbound** tracking plus, when present, the **return** tracking as a **second package**
|
|
145
|
+
(`packageDescr = 'Return Label'`). (The 2026-06-16 bridge repoint fixed the four queries in
|
|
146
|
+
`Model/Client/ItemFulfillment.php`; this trait method was a separate straggler on the same table.)
|
|
125
147
|
|
|
126
148
|
## `FIELD_STORAGE` mechanics (reference)
|
|
127
149
|
|
|
@@ -222,11 +244,22 @@ still discards the unsaved in-memory value.
|
|
|
222
244
|
on the tracking record itself must be CIE-enabled.
|
|
223
245
|
- **FedEx credentials are hardcoded in `Fedex.php` and were intentionally retained** (Mark's
|
|
224
246
|
decision) — do not "fix" them into config as part of unrelated work.
|
|
247
|
+
- **Local live-UPS carrier testing setup (local-only).** With `debug_mode=1` the `_underscore` UPS
|
|
248
|
+
carrier hits the UPS **CIE test** endpoint (`wwwcie.ups.com`). To fulfill locally you need three
|
|
249
|
+
things or the call fails in confusing ways: (a) `ShippingMethods.code` populated (UPS service
|
|
250
|
+
codes: Ground=`03`, Next Day Air=`01` — passed straight through as the UPS service `Code`); (b) a
|
|
251
|
+
**`[ups]` config group with OAuth creds** (`oauth_client_id`/`oauth_client_secret`) **in the dev
|
|
252
|
+
INI** — without it, it falls back to blank legacy creds and UPS returns **"Invalid Access License
|
|
253
|
+
number"** (document *where* the creds live, never the values); (c) a **CIE-valid shipper number** —
|
|
254
|
+
the client's production UPS account (`8696XA`) is rejected by CIE with "Missing or invalid shipper
|
|
255
|
+
number". The UPS account-location map lives at the developer's local
|
|
256
|
+
`shipping_carrier_ups_account_location.md`.
|
|
225
257
|
- **Ship guards (2026-07).** Shipping now **fails fast** if the selected carrier account is empty,
|
|
226
258
|
and **errors if an Item Fulfillment has >1 tracking number** (can't determine which account to
|
|
227
259
|
bill) — expect a hard error rather than a silently-wrong bill in those cases.
|
|
228
260
|
|
|
229
261
|
## Change history
|
|
262
|
+
- 2026-07-14 — TRUE-79191 return-label increment: `generateReturnLabel` ships from the **per-fulfillment** return address (`returnAddressId` → Addresses/States, falling back to `RETURN_ADDRESS_*`; supersedes the fixed `RETURN_ADDRESSES` set) and returns `returnTrackingNumberUuid`; documented the return-leg reuse semantic (return reuses outbound weight/carrier/method/account — only the address is independent). Fixed `Trait/Netsuite/ItemFulfillment.php::createNetsuiteItemFulfillment`, which read the retired `itemFulfillmentPackages` so no tracking reached NetSuite — now iterates the `itemFulfillmentTrackingNumbers` bridge and pushes outbound + return (2nd package, `packageDescr='Return Label'`). `reprintLabelsApi` `$caption` now accepts a position-aligned CSV for per-page captions. Added the local live-UPS testing setup gotcha (`[ups]` OAuth config, CIE endpoint/shipper, `ShippingMethods.code`). (mhammontree)
|
|
230
263
|
- 2026-07-02 — Reprint combine moved to the backend: new `_Model_Client_TrackingNumber::reprintLabelsApi` scripted API (RecordScript `GET /v2/tracking-numbers/reprint`) returns a combined base64 PDF from the stored PNGs (frontend `pdf-lib` merge removed). Added return-label generation (`generateReturnLabel`; UPS ReturnService `9` / FedEx `PRINT_RETURN_LABEL`; Ground/customer-drops-off; `RETURN_ADDRESSES`; links `returnTrackingNumberId`). Carrier billing account threaded from the tracking record (`shippingCarrierAccountNumber`) — removed `SHIPPER_NUMBER`/`ACCOUNT_NUMBER` constants, fail-fast on empty account, error on >1 tracking number per IF. Ship-to now `COALESCE(IF, SO)` address. `getLabelFormat()` defaults PNG + allowlist. Fixed two SQL injections (`postPost` `$payload->uuid`, `fulfill` NetSuite `$internalId`) and removed leftover debug `echo`/`print_r` from `fulfill()`. Found + fixed the framework-core root cause of storage writes silently vanishing (two `Model.php` `FIELD_STORAGE` bugs — see FIELD_STORAGE mechanics). (mhammontree)
|
|
231
264
|
- 2026-06-18 — Implemented the label-storage rework: request PNG from UPS/FedEx, store the raw PNG, generate the printable PDF on demand via the new `_Component_Library_LabelPdf` (FPDF); dropped Labelary. Added the FedEx tracking-cred config-fallback fix and the `_Loader`→Composer FPDF autoloader toggle. Open: the `labelPdfFile` S3 write still skips on a lazy-model save. (mhammontree)
|
|
232
265
|
- 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)
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-14
|
|
10
10
|
owners: ["jcardinal", "mhammontree", "dfranks", "apeterson"]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Component/Api/V2/V2.php
|
|
@@ -23,6 +23,7 @@ files:
|
|
|
23
23
|
- dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql
|
|
24
24
|
- dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql
|
|
25
25
|
- dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql
|
|
26
|
+
- dbchanges2/Client_Growrk/2026-07-13a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql
|
|
26
27
|
- dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql
|
|
27
28
|
- dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql
|
|
28
29
|
related:
|
|
@@ -153,8 +154,13 @@ returnTrackingNumber: {...} }]`, and an IFIU's as `itemFulfillmentItemUnitTracki
|
|
|
153
154
|
integrations enabled 403s (EZ-1) on the bridge records the moment the sync exercises them. Fixed one-off
|
|
154
155
|
per client as each starts failing: **Prudential** (`Client_Prudential/2026-06-15 - ...`, recs 317/319) and
|
|
155
156
|
**Quad** (`Client_Quad/2026-06-18a - ...`, all of 317-322) and **NYCHH**
|
|
156
|
-
(`Client_Nychh/2026-06-19b - ...`, all of 317-322)
|
|
157
|
-
|
|
157
|
+
(`Client_Nychh/2026-06-19b - ...`, all of 317-322) and **GroWrk**
|
|
158
|
+
(`Client_Growrk/2026-07-13a - ...`, all of 317-322) so far. Each new client is whack-a-mole until
|
|
159
|
+
the chain is folded back into the base migration + blank-client template. **Decision (Mark,
|
|
160
|
+
TRUE-79191):** the GroWrk fix is kept **Client_Growrk-scoped** for now — GroWrk is (as far as
|
|
161
|
+
told) the only client on Fulfill & Ship and the team pattern is per-client anyway. A shared
|
|
162
|
+
`Client/` migration would fix all clients at once if the feature broadens — that remains the
|
|
163
|
+
preferred long-term fix (fold into the base migration + blank-client template).
|
|
158
164
|
|
|
159
165
|
- **`Client_CompassCanada` is missing these bridge tables on *beta* (local drift).** Beta's
|
|
160
166
|
`Client_CompassCanada` lacks 17 tables that prod has — including the `*_TrackingNumbers`
|
|
@@ -167,6 +173,7 @@ returnTrackingNumber: {...} }]`, and an IFIU's as `itemFulfillmentItemUnitTracki
|
|
|
167
173
|
- **Porting the item-fulfillment TableView fix to another client is two independent decisions, not a copy-paste.** The **re-root** (Units 31 → ItemFulfillmentItems 29 + OUTER unit chain) is universally portable and fixes the "0 records" bug everywhere. The **tracking source is client-specific**: Compass writes one tracking number per item fulfillment at the **item level (318)**, so its views read 318. Other clients populate different bridge levels — verify with `SELECT COUNT(*)` per bridge before choosing. As of 2026-06-19, **record 318 is empty in `Client_Nychh` and `Client_Quad`**; their tracking lives at the **IF/shipment level (317)** (covers IFIs: NYCHH 7955/10049 ≈ 79%, Quad 4878/4967 ≈ 98%) and the **unit level (319)** (≈ 7–9% — serialized only). Copying Compass's 318 join into a client that doesn't write 318 yields a structurally-correct view with permanently blank tracking until 318 is backfilled. (NYCHH's pre-fix view pointed at the now-deleted record 41 = old IF-level/package bridge, i.e. it originally intended IF-level 317.)
|
|
168
174
|
|
|
169
175
|
## Change history
|
|
176
|
+
- 2026-07-14 — **GroWrk** hit the bridge ACL gap (TRUE-79191): 403 EZ-1 on `item-fulfillment-tracking-numbers` made TOGa Supply's Pending Shipments list come back `isSuccess:false` (frontend showed the empty "Create your first shipment" state). GroWrk never got the fix that Prudential (2026-06-15) and Quad (2026-06-18a) already had. Added `Client_Growrk/2026-07-13a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql` (all 6 bridges 317-322, idempotent NOT-EXISTS guards, `slug='all'`/`sqlExpression='1'`, root logic group operator AND). Decision: kept Growrk-scoped for now (only client on Fulfill & Ship); shared `Client/` migration remains the long-term fix. (mhammontree)
|
|
170
177
|
- 2026-07-09 — Noted that `Client_CompassCanada` is missing these bridge tables on **beta**, so a local
|
|
171
178
|
reset from beta reintroduces the 17-table drift (1146 on SalesOrders load); fix locally with
|
|
172
179
|
`sync_compasscanada_schema.sql`. Cross-linked the new local-DB-refresh-from-beta workflow. (apeterson)
|
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
9
|
+
updated: 2026-07-14
|
|
10
10
|
owners: ["jcardinal", "mhammontree"]
|
|
11
11
|
files: []
|
|
12
12
|
related: []
|
|
@@ -20,6 +20,16 @@ the `agilantsolutions` org. A single pipeline can have multiple Source actions s
|
|
|
20
20
|
connection (e.g. `agilantsolutions/api2` and `agilantsolutions/_underscore` on the same
|
|
21
21
|
connection ARN). Deployment target is Elastic Beanstalk.
|
|
22
22
|
|
|
23
|
+
## Branch model (which branch deploys where)
|
|
24
|
+
The application repos (`_underscore`, `api2`, `toga2-supply`) deploy from **long-lived per-env
|
|
25
|
+
branches** — `_beta`, `_production` (and `_stage`, etc.) — not from `_main`. **api2 pulls
|
|
26
|
+
`_underscore`'s matching `_<env>` branch at EB build time**, so promoting a shared `_underscore`
|
|
27
|
+
change to an env means merging it into that `_underscore` `_<env>` branch (the api2 build then
|
|
28
|
+
picks it up). **`dbchanges2` has only `_main`** — its migrations are applied **per-environment by
|
|
29
|
+
the team's process**, decoupled from the app branches; a code deploy does not run migrations. So a
|
|
30
|
+
full feature promotion to an env = apply the `dbchanges2` migrations to that env **and** deploy the
|
|
31
|
+
app-repo `_<env>` branches.
|
|
32
|
+
|
|
23
33
|
## Steps
|
|
24
34
|
1. A push to the watched branch (e.g. `_stage`) triggers the pipeline.
|
|
25
35
|
2. The Source stage uses `CodeStarSourceConnection` actions, each referencing:
|
|
@@ -103,6 +113,7 @@ aws codeconnections get-connection --connection-arn "<CONN_ARN>" --region "$REGI
|
|
|
103
113
|
```
|
|
104
114
|
|
|
105
115
|
## Change history
|
|
116
|
+
- 2026-07-14 — Documented the branch model: app repos (`_underscore`/`api2`/`toga2-supply`) deploy from long-lived `_beta`/`_production` branches (not `_main`); api2 pulls `_underscore`'s `_<env>` branch at EB build; `dbchanges2` has only `_main` and its migrations are applied per-env by the team process (not by a code deploy). (mhammontree)
|
|
106
117
|
- 2026-06-18 — Added two EB-instance gotchas surfaced during the TOGa Supply beta/prod label deploys: (1) terminated instances must be **manually re-registered** as LB targets (we don't pay for auto-registration) — until then the new code never serves traffic and looks like deploy-lag; (2) on-instance `composer require` stopgap syntax (no space after the colon, fix root cause by committing `composer.lock`). (mhammontree)
|
|
107
118
|
- 2026-06-16 — Documented after a pipeline (API-QC-Security, account 975050298201) failed every
|
|
108
119
|
run at Source with "[GitHub] GitHub returned an Internal Error"; connection was AVAILABLE and
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [TOGa Supply (toga2-supply) Architecture](architecture.md) | `toga2-supply` is the **React + Vite frontend** for TOGa Supply — warehouse fulfillment tooling (shipment selection, fulfill & ship against carrier APIs, NetSui | toga2-supply/src/api/toga.ts, toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts, toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx |
|
|
6
|
-
| [Fulfill & Ship](features/fulfill-and-ship.md) | Fulfill & Ship lets a warehouse user select sales-order line items, enter serials, pick a carrier/method, and in one action: create the Item Fulfillment records | toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, toga2-supply/src/pages/EditShipment/view/components/forms/EditShipmentForm.tsx, toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts, toga2-supply/src/pages/Shipments/view/ShipmentsPage.tsx, toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx, toga2-supply/src/pages/Shipments/api/ShipmentsApi.ts, toga2-supply/src/pages/FulfilledShipments/view/FulfilledShipmentsPage.tsx, _underscore/Model/Client/ItemFulfillment.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Component/Library/Carriers/Ups/Ups.php |
|
|
6
|
+
| [Fulfill & Ship](features/fulfill-and-ship.md) | Fulfill & Ship lets a warehouse user select sales-order line items, enter serials, pick a carrier/method, and in one action: create the Item Fulfillment records | toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx, toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx, toga2-supply/src/pages/EditShipment/view/components/forms/EditShipmentForm.tsx, toga2-supply/src/pages/EditShipment/view/components/SelectedShipmentItemsTable.tsx, toga2-supply/src/pages/EditShipment/view/modals/ReturnShippingModal.tsx, toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts, toga2-supply/src/pages/EditShipment/types.ts, toga2-supply/src/pages/Shipments/view/ShipmentsPage.tsx, toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx, toga2-supply/src/pages/Shipments/api/ShipmentsApi.ts, toga2-supply/src/pages/Shipments/types.ts, toga2-supply/src/pages/FulfilledShipments/view/FulfilledShipmentsPage.tsx, toga2-supply/src/components/ui/CardTable/CardTable.tsx, toga2-supply/src/components/ui/CardTable/types.ts, toga2-supply/src/assets/pen-line.svg, _underscore/Model/Client/ItemFulfillment.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Component/Library/Carriers/Ups/Ups.php |
|
|
7
7
|
| [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How `toga2-supply` (React + Vite) builds and deploys on **AWS Amplify**. | toga2-supply/amplify.yml, toga2-supply/.gitattributes, toga2-supply/.github/workflows/sync-stage-environments.yml, toga2-supply/.env.qc-security |
|
|
@@ -6,17 +6,24 @@ project: TOGa Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-14
|
|
10
10
|
owners: [mhammontree]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-supply/src/pages/ShipmentItems/view/ShipmentItemsPage.tsx
|
|
13
13
|
- toga2-supply/src/pages/EditShipment/view/EditShipmentPage.tsx
|
|
14
14
|
- toga2-supply/src/pages/EditShipment/view/components/forms/EditShipmentForm.tsx
|
|
15
|
+
- toga2-supply/src/pages/EditShipment/view/components/SelectedShipmentItemsTable.tsx
|
|
16
|
+
- toga2-supply/src/pages/EditShipment/view/modals/ReturnShippingModal.tsx
|
|
15
17
|
- toga2-supply/src/pages/EditShipment/api/UpdateShipmentApi.ts
|
|
18
|
+
- toga2-supply/src/pages/EditShipment/types.ts
|
|
16
19
|
- toga2-supply/src/pages/Shipments/view/ShipmentsPage.tsx
|
|
17
20
|
- toga2-supply/src/pages/Shipments/view/components/ShipmentsCardTableForm/ShipmentsCardTableForm.tsx
|
|
18
21
|
- toga2-supply/src/pages/Shipments/api/ShipmentsApi.ts
|
|
22
|
+
- toga2-supply/src/pages/Shipments/types.ts
|
|
19
23
|
- toga2-supply/src/pages/FulfilledShipments/view/FulfilledShipmentsPage.tsx
|
|
24
|
+
- toga2-supply/src/components/ui/CardTable/CardTable.tsx
|
|
25
|
+
- toga2-supply/src/components/ui/CardTable/types.ts
|
|
26
|
+
- toga2-supply/src/assets/pen-line.svg
|
|
20
27
|
- _underscore/Model/Client/ItemFulfillment.php
|
|
21
28
|
- _underscore/Trait/Netsuite/ItemFulfillment.php
|
|
22
29
|
- _underscore/Component/Library/Carriers/Ups/Ups.php
|
|
@@ -59,6 +66,27 @@ GroWrk, June 2026); FedEx + UPS both need verification before prod.
|
|
|
59
66
|
`saveShipmentToNetsuite` → `createNetsuiteItemFulfillment`, which attaches the label
|
|
60
67
|
to the IF **after** creating it (the IF doesn't exist yet when the label is bought).
|
|
61
68
|
|
|
69
|
+
## Edit a saved (unfulfilled) pending shipment in place (2026-07)
|
|
70
|
+
|
|
71
|
+
A saved-but-not-yet-fulfilled shipment can now be **edited in place** rather than only
|
|
72
|
+
re-created. Pending Shipments (`ShipmentsCardTableForm`, non-fulfilled view) shows an edit
|
|
73
|
+
pencil (`src/assets/pen-line.svg`, tinted `supply-blue-400` to match the trash icon) **only**
|
|
74
|
+
on rows where `dtSubmitted == null` (i.e. not yet pushed to NetSuite). Clicking it opens the
|
|
75
|
+
Edit Shipment form at `/edit-shipment?internalId=<so>&itemFulfillmentUuid=<uuid>`, rehydrated
|
|
76
|
+
from the saved fulfillment; **Save UPDATES the existing records** instead of POSTing a new draft.
|
|
77
|
+
|
|
78
|
+
- `getShipmentForEdit(uuid)` (`UpdateShipmentApi.ts`) loads the tracking fields + uuid,
|
|
79
|
+
ship-to + return addresses + their uuids, and item lines with unit serials.
|
|
80
|
+
- `updateShipment()` PUTs `/tracking-numbers/{uuid}`, PUTs `/addresses/{shipToUuid}`, and PUTs
|
|
81
|
+
the existing return address (or creates + links one). It returns the **same shape** as
|
|
82
|
+
`saveShipment`, so the downstream fulfill/label/print flow is unchanged.
|
|
83
|
+
- **v1 scope (decision, Mark):** shipment details + ship-to address + return label/address are
|
|
84
|
+
editable; **item lines & serial numbers are READ-ONLY**. `SelectedShipmentItemsTable` gained a
|
|
85
|
+
`readOnly` prop that renders serials as text, and the "all serials provided" button-enable gate
|
|
86
|
+
is auto-satisfied in edit mode.
|
|
87
|
+
- `CardTable` was made reusable for this: optional `editIcon` + `isEditButtonDisabled` props
|
|
88
|
+
(defaults preserve prior behavior; the shipments card is the only consumer today).
|
|
89
|
+
|
|
62
90
|
## Reprint (backend-combined, 2026-07)
|
|
63
91
|
|
|
64
92
|
Fulfilled-shipments view (`FulfilledShipmentsPage` → `ShipmentsCardTableForm` with
|
|
@@ -126,6 +154,19 @@ the call 403s and returns no label.
|
|
|
126
154
|
`item-fulfillment-tracking-numbers` bridge requires the bridge record's ACL logic-group
|
|
127
155
|
chain to exist for the user's role, or it 403s and `itemFulfillmentTrackingNumbers` returns
|
|
128
156
|
`null` (so reprint has no label). See the tracking-number-bridges doc's ACL gotcha + fix.
|
|
157
|
+
- **Return modal's non-address fields are an edit-trap (not persisted, not used).** On the
|
|
158
|
+
backend the return leg **reuses the outbound shipment's weight/carrier/method/account**
|
|
159
|
+
(`generateReturnLabel`: `packageWeightPounds` = outbound tracking weight; the return
|
|
160
|
+
`TrackingNumber`'s carrier/method/account = outbound). **Only the return ADDRESS is persisted**
|
|
161
|
+
(`returnAddressId`). The return modal's weight/dims/carrier fields are prefilled from the
|
|
162
|
+
outbound shipment **for display only** — editing them changes nothing. Follow-up: make those
|
|
163
|
+
fields read-only OR persist independent return dimensions.
|
|
164
|
+
- **Declared Cost column showed a constant "$ -" on Pending Shipments (fixed 2026-07).** The
|
|
165
|
+
column + formatter existed, but `getShipments` (`ShipmentsApi.ts`) never *requested*
|
|
166
|
+
`trackingNumber.declaredCost` and the card row-builder (`ShipmentsCardTableForm.tsx`) never
|
|
167
|
+
mapped it into `flattenedData`. Added the field to the query and the row map (+ `declaredCost`
|
|
168
|
+
on the `FlattenedData` type). A missing column that always renders empty is usually a
|
|
169
|
+
not-requested / not-mapped field, not a formatter bug.
|
|
129
170
|
- **Two separate page components + a scroll/clip trap.** `/shipments` renders `ShipmentsPage`;
|
|
130
171
|
`/fulfilled-shipments` renders `FulfilledShipmentsPage` — **separate components** (a fix to one
|
|
131
172
|
does NOT touch the other; the shared list is `ShipmentsCardTableForm`). Both pages used
|
|
@@ -143,14 +184,42 @@ the call 403s and returns no label.
|
|
|
143
184
|
|
|
144
185
|
- ~~Reprint rewire~~ — done (backend `reprintLabelsApi` combine; see Reprint section).
|
|
145
186
|
- ~~Address-source decision~~ — done (`COALESCE(IF, SO)`).
|
|
146
|
-
- Return-label flow
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
187
|
+
- ~~Return-label flow (Increment 3)~~ — **done end-to-end (2026-07).** Backend `generateReturnLabel`
|
|
188
|
+
now ships FROM the per-fulfillment return address (`returnAddressId` → Addresses/States, falling
|
|
189
|
+
back to the `RETURN_ADDRESS_*` config), and the frontend fulfill flow (`UpdateShipmentApi.ts`
|
|
190
|
+
`fulfillShipment(needsReturnLabel)` + `EditShipmentForm.tsx`) prints one **combined outbound +
|
|
191
|
+
return PDF**, with the return page captioned "Return Label" (`ShipmentsApi.ts` passes a
|
|
192
|
+
position-aligned `captions` CSV to `reprintLabelsApi`). See the carrier-shipping-labels doc.
|
|
193
|
+
- **Edit-mode follow-ups (v1 punts):** (a) serial-number editing in edit mode — would need
|
|
194
|
+
unit add/remove diffing against the API (the edit route already carries the fulfillment uuid);
|
|
195
|
+
(b) the return modal's weight/dims/carrier fields are an **edit-trap** — see the gotcha below.
|
|
151
196
|
- UPS 35-char hardening, location-scoped inventory lookup, carrier/method on the NS IF,
|
|
152
197
|
responsiveness per Figma, FedEx + UPS end-to-end verification before prod.
|
|
153
198
|
|
|
199
|
+
## Deploy / provisioning requirements (per environment)
|
|
200
|
+
|
|
201
|
+
The return-label feature (TRUE-79191) needs **four** things present in a given environment or it
|
|
202
|
+
silently mis-behaves; treat these as the release checklist when promoting to a new env:
|
|
203
|
+
1. **`ItemFulfillments.returnAddressId` column** (Client DB) — the persisted return address FK.
|
|
204
|
+
2. **RecordField 2434** (Core) — the record field backing `returnAddressId`.
|
|
205
|
+
3. **`generateReturnLabel` RecordScript** (Client DB) — the scripted-API dispatch grant.
|
|
206
|
+
4. **Bridge ACL logic groups for records 317–322** (Client DB) — or reads 403 EZ-1; see the
|
|
207
|
+
tracking-number-bridges doc.
|
|
208
|
+
|
|
209
|
+
**Environment status snapshot (2026-07, TRUE-79191):** GroWrk is **not** in the beta cluster; it
|
|
210
|
+
exists non-prod only in **dev-sandbox** (closest to ready: has the bridge, bridge ACL logic
|
|
211
|
+
groups, and the `generateReturnLabel` RecordScript, but is **missing** the `returnAddressId`
|
|
212
|
+
column and RecordField 2434) and **client-sandbox** (far behind — no bridge at all), plus prod.
|
|
213
|
+
**Prod is not migrated for this feature** (missing `returnAddressId`, RecordField 2434, the
|
|
214
|
+
`generateReturnLabel` RecordScript, and all six bridge ACL logic groups — the 403 gap is live in
|
|
215
|
+
prod now).
|
|
216
|
+
|
|
217
|
+
**"Testing in prod" (PMO Aaron's call, since no client uses the feature yet) is a FULL prod
|
|
218
|
+
release, not a sandbox run.** It means applying all TRUE-79191 `dbchanges2` migrations to prod +
|
|
219
|
+
deploying code to `_production`; a live run then buys a **REAL** UPS label on Agilant account
|
|
220
|
+
`8696XA` (prod endpoint) and creates a **REAL** NetSuite Item Fulfillment. Plan to **void the
|
|
221
|
+
labels and reverse the fulfillment** afterward.
|
|
222
|
+
|
|
154
223
|
## Client variations
|
|
155
224
|
|
|
156
225
|
None in the flow itself — but the NetSuite trait is composed into **client-specific**
|
|
@@ -159,6 +228,7 @@ not the base `_Model_Client_ItemFulfillment`. Tested with GroWrk; UPS support wa
|
|
|
159
228
|
for Compass and is not yet in prod.
|
|
160
229
|
|
|
161
230
|
## Change history
|
|
231
|
+
- 2026-07-14 — TRUE-79191: added **edit-a-saved-pending-shipment-in-place** (pencil on `dtSubmitted==null` rows → `/edit-shipment`, `getShipmentForEdit`/`updateShipment` PUT existing records; item lines/serials read-only in v1; `CardTable` made reusable with `editIcon`/`isEditButtonDisabled`). Completed the Increment-3 **return-label** frontend (combined outbound+return PDF, return page captioned "Return Label" via a position-aligned `captions` CSV to `reprintLabelsApi`). Fixed the Declared Cost "$ -" column (field was never requested/mapped). Documented the return-modal edit-trap (only the return ADDRESS persists — weight/carrier/dims reuse outbound) and the per-env deploy/provisioning checklist + the "testing in prod = full prod release (real labels/NS IF)" decision. (mhammontree)
|
|
162
232
|
- 2026-07-02 — Reprint rewired to the backend: `ShipmentsApi.ts` now calls `GET /v2/tracking-numbers/reprint` (`reprintLabelsApi`) for a combined base64 PDF built from the stored PNGs; removed the stale client-side `pdf-lib` merge. Return-label backend generation landed (`generateReturnLabel`, `returnTrackingNumberId` on the bridge). Ship-to address source resolved to `COALESCE(IF, SO)`. (mhammontree)
|
|
163
233
|
- 2026-06-18 — PNG label-storage rework reflected on the frontend: labels now store as PNG and the PDF is built on the backend (`LabelPdf`), so the client-side `pdf-lib` reprint is stale and must be rewired to a backend generate endpoint. Fixed the Fulfilled Shipments responsiveness/clip bug (Reprint button unreachable at 100% zoom) — `overflow-scroll` → `overflow-auto` and gave `FulfilledShipmentsPage`'s outer its own scroll; documented the `/shipments` vs `/fulfilled-shipments` two-component trap and the `AuthLayout overflow-hidden` clip. (mhammontree)
|
|
164
234
|
- 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)
|
|
@@ -5,13 +5,14 @@ apps:
|
|
|
5
5
|
- _underscore
|
|
6
6
|
- api2
|
|
7
7
|
- worker2
|
|
8
|
+
- toga2-supply
|
|
8
9
|
- dbchanges2
|
|
9
10
|
project: _Underscore
|
|
10
11
|
client: growrk
|
|
11
12
|
type: profile
|
|
12
13
|
status: active
|
|
13
|
-
updated: 2026-
|
|
14
|
-
owners: ["rgirish"]
|
|
14
|
+
updated: 2026-07-14
|
|
15
|
+
owners: ["rgirish", "mhammontree"]
|
|
15
16
|
files: []
|
|
16
17
|
related:
|
|
17
18
|
- clients/growrk/features/transfer-order-flow.md
|
|
@@ -20,3 +21,9 @@ related:
|
|
|
20
21
|
## Summary
|
|
21
22
|
|
|
22
23
|
GroWrk is a 2.0 client using TOGA for inventory and order management. Their primary integration involves inventory movements between locations (warehouses, distribution points). NetSuite is the ERP. The key engineering challenge is that GroWrk historically used zero-dollar SalesOrders with holdInvoice=true in NetSuite as a workaround to represent internal inventory transfers — work is underway to replace this with a dedicated TransferOrders record type in the TOGA DB while keeping NetSuite unchanged.
|
|
24
|
+
|
|
25
|
+
GroWrk is (as far as told) the **only client on TOGa Supply's Fulfill & Ship** flow — it is the client used to drive that feature and its return-label increment (TRUE-79191) green. See the [Fulfill & Ship feature](../../2.0/apps/toga2-supply/features/fulfill-and-ship.md) and [tracking-number bridges](../../2.0/apps/_underscore/features/tracking-number-bridges.md).
|
|
26
|
+
|
|
27
|
+
## Local dev gotchas
|
|
28
|
+
|
|
29
|
+
- **`_Model_Growrk_Unit` declares runtime custom-field columns that must physically exist on `Client_Growrk.Units`.** The model declares `c_` fields (`c_itemDescription`, `c_chargingBrick`, `c_deviceStatus`, `c_chargingCable`, `c_grade`); these are runtime custom-field columns, so a locally-drifted `Client_Growrk` DB missing them **1054s (unknown column) on any Unit load**. Add the columns to bring a local DB current.
|
package/package.json
CHANGED