toga-ai 1.0.723 → 1.0.724

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.
@@ -10,7 +10,7 @@
10
10
  | [_ApiRequest — JSON encode/decode & api-logging behavior](features/apirequest-json-content-type.md) | `_ApiRequest` is the 2.0 outbound HTTP client. | _underscore/ApiRequest.php |
11
11
  | [Assortment Name Translation (AssortmentTranslations sidecar)](features/assortment-name-translation.md) | Serves Assortment (product-grouping) **names** in multiple languages by adding a per-language **sidecar** table `AssortmentTranslations`, reusing the platform's | _underscore/Model/Client/AssortmentTranslation.php, dbchanges2/Client/2026-06-26a - AssortmentTranslations.sql, dbchanges2/Core/2026-06-26a - AssortmentTranslationsRecord.sql, dbchanges2/Client/2026-06-26b - AssortmentTranslationsAcl.sql |
12
12
  | [Asynchronous Query Execution (writes-only, via Worker)](features/async-query-execution.md) | `_Query` can run a **write** query asynchronously so a long/slow write does not hold a request-scoped DB connection open long enough to hit **"MySQL server has | _underscore/Query.php, worker2/Worker/Infrastructure/Database.php, worker2/Worker/Team/Transcripts.php |
13
- | [FIELD_SQL calculated fields — the underscore-prefix + same-name-method contract](features/calculated-sql-fields.md) | A `FIELD_SQL` (calculated) field on a `_Model` is bound by a **two-part contract that `_Model` enforces by throwing at model-construction time**, not by convent | _underscore/Model.php, _underscore/Model/Client/SalesOrder.php, _underscore/Model/Client/ServiceRequest.php, _underscore/Model/Elite/SalesOrder.php, _underscore/Model/Compass/SalesOrder.php, _underscore/Model/Compass/Canada/SalesOrder.php, api2/Component/Api/V2/V2.php, _underscore/Model/Quad/Item.php, _underscore/Model/Quad/VendorItem.php, dbchanges2/Client/2026-08-11b - SalesOrderPurchaseOrdersField.sql, dbchanges2/Client/2026-08-25 - SalesOrderPurchaseOrdersFieldAllClients.sql |
13
+ | [FIELD_SQL calculated fields — the underscore-prefix + same-name-method contract](features/calculated-sql-fields.md) | A `FIELD_SQL` (calculated) field on a `_Model` is bound by a **two-part contract that `_Model` enforces by throwing at model-construction time**, not by convent | _underscore/Model.php, _underscore/Model/Client/PurchaseOrder.php, _underscore/Model/Client/SalesOrder.php, _underscore/Model/Client/ServiceRequest.php, _underscore/Model/Elite/SalesOrder.php, _underscore/Model/Compass/SalesOrder.php, _underscore/Model/Compass/Canada/SalesOrder.php, api2/Component/Api/V2/V2.php, _underscore/Model/Quad/Item.php, _underscore/Model/Quad/VendorItem.php, dbchanges2/Client/2026-08-11b - SalesOrderPurchaseOrdersField.sql, dbchanges2/Client/2026-08-25 - SalesOrderPurchaseOrdersFieldAllClients.sql |
14
14
  | [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 | test/@Mark/true-80824-fedex-inflate-test.php, dbchanges2/Client_Growrk/2026-08-10e - GrowrkUpsServiceMethodCodes.sql, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/LabelPdf/LabelPdf.php, _underscore/Component/Library/Carriers/ShipmentRequest/ShipmentRequest.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Component/Library/Carriers/Fedex/Fedex.php, _underscore/Component/Library/Carriers/Usps/Usps.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 |
15
15
  | [Running 2.0 code from a bare CLI script (bootstrap + transactions)](features/cli-script-bootstrap.md) | A throwaway CLI script (a data check, a backfill dry-run, a render harness) that wants the real 2.0 framework — `_Model`, `_Query`, `_Database` — is **not** the | _underscore/Database.php, _underscore/Environment.php, api2/Initialize.php |
16
16
  | [_Cloud S3 helpers (copy / get / delete / list)](features/cloud-s3-helpers.md) | `_Cloud` centralizes AWS SDK S3 usage for the 2.0 stack so the `S3Client` never leaks into workers or app code. | _underscore/Cloud.php |
@@ -46,7 +46,7 @@
46
46
  | [Surface FIELD ↔ RecordField binding (maxLength / validationType / isWritable fold-in)](features/surface-field-recordfield-binding.md) | A resolver capability that makes a surface `FIELD` element carry its **input contract** — max length, validator name, and whether the caller may write it — inst | _underscore/Model/Core/Surface.php, _underscore/Model/Core/RecordField.php, _underscore/Model/Core/AclFieldPermission.php, _underscore/Model/Client/RecordFieldSetting.php, _underscore/Model/Client/ClientRecordFieldSetting.php, dbchanges2/Core/2026-08-14c - RecordFieldsValidationMetadata.sql, dbchanges2/Client/2026-08-14a - RecordFieldSettingsClientTable.sql, api2/Component/Api/V2/V2.php |
47
47
  | [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/Client/Language.php, dbchanges2/Core/2026-08-21 - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Core/2026-08-24 - RestoreApproveDenyRowActionsVisibility.sql, dbchanges2/Client_Quad/2026-08-24 - ProdPortApprovePoNumberEnabledRule.sql, dbchanges2/Client_Compass/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_CompassCanada/2026-08-24 - ProdPortApprovalsGateAndApproveStepTwoRule.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, toga25-supply/src/App.tsx, toga25-supply/src/surface/useFetchSurfaceMeta.ts, toga25-supply/src/contexts/AuthContext.tsx, dbchanges2/Core/2026-07-21a - SalesOrderDecisionSummarySurfaceSeed.sql, dbchanges2/Core/2026-07-21b - SalesOrderDecisionActionSurfaceSeed.sql, dbchanges2/Core/2026-08-21a - SalesOrderDecisionSurfacesReseed.sql, dbchanges2/Client_Compass/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_Quad/2026-07-21c - SalesOrderDecisionSummaryOverride.sql, dbchanges2/Client_CompassCanada/2026-07-21c - SalesOrderDecisionSummaryTotalConcat.sql, dbchanges2/Client_Compass/2026-08-04a - ApprovalDetailsAssignedManagerPreferredStage.sql, _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, dbchanges2/Client_Compass/2026-07-15f - SalesOrderRecordActionsRemoveDeadConfigRuleOverrides.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.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, api2/Component/Api/V2/V2.php, dbchanges2/Core/2026-08-12a - NavigationSurfaceSeed.sql, dbchanges2/Client_Compass/2026-08-12a - NavigationRoleGrants.sql, toga25-supply/surface-layer-guide.md |
48
48
  | [Table-View Hyperlink Columns (meta → ACL → computed URL → render)](features/tableview-hyperlink-columns.md) | Any 2.0 table-view column can render its value as a clickable link instead of plain text. | _underscore/Model/Client/TableView.php, _underscore/Model/Client/TrackingNumber.php, api2/Component/Api/V2/V2.php, toga2-supply/src/api/toga.ts, toga2-supply/src/components/ui/Tables/PrimaryTable/helperFunctions/formatTableData.tsx, toga2-supply/src/components/ui/Tables/PrimaryTable/helperFunctions/convertData.tsx, toga2-supply/src/components/ui/Tables/hooks/useDataTableState.tsx, dbchanges2/Client/2026-07-20 - TrackingNumberHyperlinkAndFieldPermission.sql |
49
- | [TableView joins (TableViewJoins → SQL) — aliasing, chained multi-hop joins, ACL](features/tableview-joins.md) | `Client_*.TableViewJoins` rows are what let a table view show a column from a table other than its base record. | _underscore/Model/Client/TableView.php, _underscore/Model.php, api2/Component/Api/V2/V2.php, dbchanges2/Client/2026-08-11a - ServiceRequestsInventoryUnitsTableViews.sql, dbchanges2/Client_Elite/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_CompassCanada/2026-08-27a - ItemFulfillmentTableViewsRebuild.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql |
49
+ | [TableView joins (TableViewJoins → SQL) — aliasing, chained multi-hop joins, ACL](features/tableview-joins.md) | `Client_*.TableViewJoins` rows are what let a table view show a column from a table other than its base record. | _underscore/Model/Client/TableView.php, _underscore/Model.php, api2/Component/Api/V2/V2.php, dbchanges2/Client/2026-08-11a - ServiceRequestsInventoryUnitsTableViews.sql, dbchanges2/Client_Elite/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_CompassCanada/2026-08-27a - ItemFulfillmentTableViewsRebuild.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql, dbchanges2/Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql |
50
50
  | [TogaIQ Gateway Client (_Component_Api_Togaiq) — AI generate/translate from 2.0](features/togaiq-gateway-client.md) | `_Component_Api_Togaiq` is the 2.0 framework's client for the **TogaIQ** (Talos) AI gateway. | _underscore/Component/Api/Togaiq/Togaiq.php, _underscore/ApiRequest.php |
51
51
  | [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, dbchanges2/Client_Elite/2026-08-17 - FulfillmentTableViews.sql, dbchanges2/Client_Quad/2026-08-26a - BackfillQuadUnitLevelTrackingSingleTn.sql, dbchanges2/Client_Quad/2026-08-26b - BackfillQuadItemLevelTrackingSingleTn.sql, dbchanges2/Client_CompassCanada/2026-08-27a - ItemFulfillmentTableViewsRebuild.sql |
52
52
  | [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 | _underscore/Model/Client/ServiceRequest.php, dbchanges2/Client/2026-08-11a - ServiceRequestsInventoryUnitsTableViews.sql |
@@ -6,10 +6,11 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-26
9
+ updated: 2026-09-01
10
10
  owners: [snaredla, jcardinal, bala]
11
11
  files:
12
12
  - _underscore/Model.php
13
+ - _underscore/Model/Client/PurchaseOrder.php
13
14
  - _underscore/Model/Client/SalesOrder.php
14
15
  - _underscore/Model/Client/ServiceRequest.php
15
16
  - _underscore/Model/Elite/SalesOrder.php
@@ -210,6 +211,13 @@ characters — that is the standard of evidence for touching a field that runs o
210
211
  [save-cascade stored-field deadlocks](./model-save-parent-cascade-stored-field-deadlock.md).
211
212
 
212
213
  ## Change history
214
+ - 2026-09-01 — Added `_shipTo` to the base `_Model_Client_PurchaseOrder` (`public $_shipTo =
215
+ self::FIELD_SQL;` + static `_shipTo($table = self::TABLE)` returning a correlated subquery
216
+ `SELECT Addresses.addressee FROM Addresses WHERE Addresses.id = $table.shipToAddressId`),
217
+ paralleling `SalesOrders._shipTo`. Registered here via a **`Core.RecordFields`** row (id 2555,
218
+ recordId 17 `purchase-orders`, type STRING, mirroring `SalesOrders._shipTo` id 626) —
219
+ i.e. the Core-registration path, not the `CustomRecordFields`-only path this doc shows is also
220
+ sufficient. Additive and shared: it renders only where a view references it. (jcardinal)
213
221
  - 2026-08-26 - Documented **how to override a calculated field for one client / sub-client**: api2
214
222
  resolves the model class by `str_replace('_Model_Client_', '_Model_' . $clientIdentifier . '_', ...)`
215
223
  (`Component/Api/V2/V2.php`), and because the expression is invoked as
@@ -6,8 +6,8 @@ project: _Underscore
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-08-28
10
- owners: [bala, apeterson]
9
+ updated: 2026-09-01
10
+ owners: [bala, apeterson, jcardinal]
11
11
  files:
12
12
  - _underscore/Model/Client/TableView.php
13
13
  - _underscore/Model.php
@@ -17,6 +17,7 @@ files:
17
17
  - dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql
18
18
  - dbchanges2/Client_CompassCanada/2026-08-27a - ItemFulfillmentTableViewsRebuild.sql
19
19
  - dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql
20
+ - dbchanges2/Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql
20
21
  related:
21
22
  - ../../api2/features/tableview-field-metadata.md
22
23
  - ./page-meta-context-field-settings.md
@@ -193,6 +194,28 @@ grants of any kind — `Records` **351** (`transfer-order-stages`) had none befo
193
194
  `Client_Nychh/2026-08-28a`, so the Status column of a brand-new view would have vanished silently.
194
195
  Check the joined record's grants before assuming an existing record is grant-covered.
195
196
 
197
+ ## A third mode: an INNER join to an EMPTY FK returns an EMPTY GRID — not an error
198
+
199
+ The two `meta()` failures above both throw. There is a third, quieter mode that is **not an
200
+ error at all**: a view loads, the header/meta looks right, and the data grid shows **zero rows**.
201
+
202
+ Cause: an **INNER** `TableViewJoins` on a foreign-key column that is **unpopulated for that
203
+ tenant** drops every row, because an inner join with no matching parent row returns nothing.
204
+ Confirmed 2026-09-01 on the NYCHH `purchase-orders` view: `Client_Nychh.PurchaseOrders` had **0 of
205
+ 175 rows** with a populated `locationId`, so an INNER `Locations` join
206
+ (`Locations.id = PurchaseOrders.locationId`) emptied the whole grid. The meta API looked correct;
207
+ the data API just returned 0 results.
208
+
209
+ - **The blast radius is per tenant.** The same view can serve fine for a client whose FK is
210
+ populated and go empty for one whose FK is not — so it reads as "the grid is broken for this
211
+ client only", exactly like an ACL gap, but the join type is the cause.
212
+ - **Fix / avoid:** for an **optional / possibly-empty** FK, use **LEFT OUTER** (rows survive with
213
+ nulls in the joined columns) or omit the column entirely. Only use INNER when the FK is
214
+ guaranteed populated for the tenant.
215
+ - **Check before you add:** verify FK population in the target tenant
216
+ (`SELECT COUNT(*) ... WHERE <fk> IS NOT NULL`) before choosing INNER. NYCHH's `purchase-orders`
217
+ ultimately **dropped** the Location (and Ship To) column rather than switch to OUTER.
218
+
196
219
  ## Context RecordFieldSettings are OPTIONAL for a joined column to render
197
220
 
198
221
  `meta()` looks up `contextRecordFieldId`-scoped settings (`DefaultRecordFieldSettings` plus the
@@ -251,9 +274,19 @@ Core-level reference ids used (identical across all clients and environments): *
251
274
  read the missing log row as "the request never happened".
252
275
  - **An unused join can already exist.** Confirm before inserting; a duplicate join of the same table
253
276
  is what breaks chained joins.
277
+ - **An INNER join to an EMPTY FK empties the whole grid with NO error.** Third failure mode: an
278
+ inner join on an FK that is unpopulated for the tenant drops every row (meta looks fine, data
279
+ returns 0). Use LEFT OUTER for an optional FK, or verify FK population before choosing INNER.
254
280
 
255
281
  ## Change history
256
282
 
283
+ - 2026-09-01 — Added a **third `meta()` failure mode that is not an error**: an **INNER** join to a
284
+ foreign key that is **unpopulated for the tenant** returns an **empty grid** (meta correct, data
285
+ 0 rows), because an inner join with no matching parent row drops everything. Found on NYCHH's
286
+ `purchase-orders` view — `Client_Nychh.PurchaseOrders` had 0 of 175 rows with a populated
287
+ `locationId`, so an INNER `Locations` join emptied the grid. Rule: use LEFT OUTER (or omit the
288
+ column) for an optional/possibly-empty FK, and verify FK population in the target tenant before
289
+ using INNER. (jcardinal)
257
290
  - 2026-08-28 — Separated the **two distinct ways `meta()` 500s**, after Compass Canada's
258
291
  `item-fulfillments-for-sales-order(-item)s` views returned 500 while Compass USA's served fine.
259
292
  (a) A join pointing at a **deleted `Core.Records` / `Core.RecordFields` row** throws from
@@ -6,4 +6,4 @@
6
6
  | [NYCHH NetSuite → TransferOrders import (stocking-flag routing, PO bridges, origin location)](features/netsuite-transfer-order-import.md) | 1.0 | NYCHH's NetSuite **transfer orders are represented as NetSuite sales orders** (same as the GroWrk pattern), so the shared NetSuite → TOGa Supply importer (`App_ | library/app/api/toga2.php, library/app/api/netsuite/rest.php, library/app/netsuite.php, worker/crons/toga2/netsuite/sync_togasupply_hh.php, worker/crons/toga2/netsuite/common_sync_togasupply.php, worker/crons/toga2/netsuite/diagnose_hh_stuck_transfer_order.php, dbchanges2/Core/2026-08-27a - TransferOrderUuidSearchableIdentifier.sql, dbchanges2/Client/2026-08-28a - TransferOrderItemsTimestampColumns.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestampColumnsReposition.sql, dbchanges2/Client/2026-08-29 - ItemReceiptTransferOrderIdFieldPermission.sql, dbchanges2/Client/2026-08-29b - ItemReceiptItemTransferOrderItemIdFieldPermission.sql |
7
7
  | [NYCHH PO links are UPSTREAM — the downstream SO→PO route returns empty](features/po-number-upstream-direction.md) | 2.0 | NYCHH's sales orders are created **from the customer's purchase order**, so their SO↔PO links live in the **upstream** table `PurchaseOrders_SalesOrders` (route | _underscore/Model/Client/SalesOrder.php, _underscore/Trait/Netsuite/SalesOrder.php, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, dbchanges2/Client/2026-08-11b - SalesOrderPurchaseOrdersField.sql, dbchanges2/Client/2026-08-25 - SalesOrderPurchaseOrdersFieldAllClients.sql |
8
8
  | [NYCHH transfer-order 2.0 model — inventory quantities + V2 field enablement](features/transfer-order-inventory-quantities.md) | 2.0 | The 2.0 (`_underscore`) side of NYCHH transfer-order support: a **two-branch inventory quantity model** on the NYCHH `Item` override, plus the **client-override | _underscore/Model/Nychh/Item.php, _underscore/Model/Nychh/PurchaseOrderItem.php, _underscore/Model/Nychh/TransferOrder.php, _underscore/Model/Nychh/TransferOrderStage.php, _underscore/Model/Client/TransferOrder.php, _underscore/Model/Client/TransferOrderItem.php, dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql, dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql, dbchanges2/Client_Nychh/2026-08-28c - TransferOrderRecordAcl.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestamps.sql |
9
- | [NYC Health & Hospitals](profile.md) | 2.0 | NYC Health & Hospitals (NYCHH) is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Nychh`. | dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql, dbchanges2/Client_Nychh/2026-08-28c - TransferOrderRecordAcl.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestamps.sql |
9
+ | [NYC Health & Hospitals](profile.md) | 2.0 | NYC Health & Hospitals (NYCHH) is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Nychh`. | dbchanges2/Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql, dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql, dbchanges2/Client_Nychh/2026-08-28c - TransferOrderRecordAcl.sql, dbchanges2/Client/2026-08-28b - TransferOrderItemsTimestamps.sql |
@@ -16,9 +16,10 @@ project: _Underscore
16
16
  client: nychh
17
17
  type: profile
18
18
  status: active
19
- updated: 2026-08-31
19
+ updated: 2026-09-01
20
20
  owners: ["jcardinal", "apeterson", "bala", "akhokhani"]
21
21
  files:
22
+ - dbchanges2/Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql
22
23
  - dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql
23
24
  - dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql
24
25
  - dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql
@@ -48,6 +49,19 @@ table views. Client-specific DB change-sets live in `dbchanges2/Client_Nychh/`.
48
49
  run the NetSuite→TOGa Supply sync and the asset-tag verification/backfill diagnostics.
49
50
 
50
51
  ## Key features (this client)
52
+ - **`purchase-orders` table view was rebased off the wrong record (2026-09-01).** The view was
53
+ based on **SalesOrders (Core record 14)** but had to be **PurchaseOrders (record 17)** — it was
54
+ mislabeled. `Client_Nychh/2026-08-31a - PurchaseOrdersTableViewRebase.sql` flips
55
+ `TableViews.recordId` 14→17, drops the SalesOrders→bridge→PurchaseOrders join chain, removes the
56
+ "Sales Order number" column (`SalesOrders.number`, RecordFields 49), and repoints the rest to PO
57
+ fields — final columns **number (base field 87), dateOrder (86), total (`_total` 1429)**. Location
58
+ and Ship To were intentionally **omitted**: PO `locationId` is empty for this tenant, so an INNER
59
+ Locations join would empty the grid (see the third failure mode in
60
+ [tableview-joins](../../2.0/apps/_underscore/features/tableview-joins.md)). The migration also
61
+ seeds a **Developer-role (role 2)** record ACL grant chain (`AclRecordPermissions` →
62
+ `AclLogicGroups` → `AclLogicGroupExpressions`, reusing record 17's `all` expression) and reads
63
+ `AclFieldPermissions` for the displayed fields, resolving `roleId` by role **name**. Written
64
+ idempotent / uuid-keyed; applied to **prod and client-sandbox**.
51
65
  - **`inventory_units` table view carries item detail as of 2026-08-18** — Part Number, Manufacturer
52
66
  and Item Description sit directly after Asset Tag, reached through a **chained** Units → Items →
53
67
  Manufacturers join (`dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql`, identical
@@ -112,6 +126,8 @@ table views. Client-specific DB change-sets live in `dbchanges2/Client_Nychh/`.
112
126
  [NYCHH PO Number direction](./features/po-number-upstream-direction.md).
113
127
 
114
128
  ## Notes
129
+ - **Role ids in `Client_Nychh` (verified 2026-09-01):** `1 = Base`, `2 = Developer`, `3 = API`.
130
+ Role ids differ per client DB — resolve by **name** in migrations, never hard-code these.
115
131
  - **PO Number is upstream-sourced** (`PurchaseOrders_SalesOrders`), which is why the downstream
116
132
  SO→PO route and the shared `_purchaseOrders` field came back empty. Details, and the
117
133
  now-closed-on-`_beta` fix: [NYCHH PO Number](./features/po-number-upstream-direction.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.723",
3
+ "version": "1.0.724",
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",