toga-ai 1.0.1205 → 1.0.1206
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/features/fulfillable-item-propagation.md +2 -1
- package/knowledge/2.0/apps/toga25-supply/features/sales-order-items-table.md +5 -2
- package/knowledge/2.0/apps/toga25-supply/features/surface-frontend.md +7 -1
- package/knowledge/clients/compass-canada/INDEX.md +1 -1
- package/knowledge/clients/compass-canada/features/order-fulfillment-status-per-line.md +28 -11
- package/knowledge/clients/compass-canada/profile.md +7 -5
- package/knowledge/clients/compass-usa/features/isfulfillable-data-quality-and-type-rule.md +10 -4
- package/knowledge/clients/compass-usa/features/order-fulfillment-status-per-line.md +6 -1
- package/knowledge/clients/compass-usa/profile.md +3 -2
- package/package.json +1 -1
|
@@ -53,7 +53,8 @@ same bridge topology, walked for a different payload (a scalar flag rather than
|
|
|
53
53
|
### Mechanism
|
|
54
54
|
1. **Interceptor gate.** `postPost`/`postPut` call `propagateFulfillableWhenPayloadCarriesTheFlag`,
|
|
55
55
|
which returns immediately unless the payload carried `isFulfillable`. Senders: the sync, the
|
|
56
|
-
one-time backfill, and the toga25-supply item modal Fulfillable toggle (Compass USA + Canada
|
|
56
|
+
one-time backfill, and the toga25-supply item modal Fulfillable toggle (Compass USA + Canada;
|
|
57
|
+
edit PUT and, since 2026-10-29, create POST — a new item has no order lines, so the walk is a no-op).
|
|
57
58
|
**A UI caller must send the key ONLY when the user changed it** — `useItemEditForm` adds it to
|
|
58
59
|
the PUT only when `dirtyFields.isFulfillable` is set. Sending it on every save would walk the
|
|
59
60
|
whole SO/PO chain on every item edit for nothing.
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-29
|
|
10
10
|
owners: ["bala"]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderUpdatedItemsTable/SalesOrderUpdatedItemsTable.tsx
|
|
@@ -17,6 +17,7 @@ related:
|
|
|
17
17
|
- ./record-modals-and-nested-tables.md
|
|
18
18
|
- ./bundle-item-pricing.md
|
|
19
19
|
- ../../../clients/compass-usa/workflows/granting-persona-bundle-access.md
|
|
20
|
+
- ../../../clients/compass-usa/features/isfulfillable-data-quality-and-type-rule.md
|
|
20
21
|
---
|
|
21
22
|
The Items table inside the Supply sales order / service request modal: an INTERIM hardcoded table (not Surface-driven) that flattens standalone lines, kits, kit add-ons, parts and fees into tiered rows; open when an order line is missing or mis-drawn in that table.
|
|
22
23
|
|
|
@@ -40,12 +41,14 @@ The Items table inside the Supply sales order / service request modal: an INTERI
|
|
|
40
41
|
- **Add-on header key = the add-on's first order-line uuid**, not the bundle uuid. The same add-on bundle can appear twice on one order; a bundle-uuid key would collide.
|
|
41
42
|
- **Add-on lines keep their real `isPrimary`.** The kit-level "Computer Support" badge and the child sort read only each child group's LEAD row; for an add-on that is the header row, which has no `isPrimary`. So an add-on's own primary part shows its "Computer Support" badge, and nothing leaks to the kit. Do not force `isPrimary = false` in `buildAddOnRows()`; it protects nothing and hides that badge.
|
|
42
43
|
- The developer decision (TRUE-82981): the add-on must match the main kit layout exactly. Do not invent a different style for it.
|
|
44
|
+
- **Qty Fulfilled click → `ItemFulfillmentModal`.** `isQtyFulfilledClickable()` (copy of toga2-supply `OrderItemsTableSection`) makes the cell clickable only when `item.isFulfillable` is `true` or `"1"` AND qty fulfilled != 0. NULL and 0 are both dead. For hostname `COMPASS`, an `assetType.name` of `FEE` is never clickable. Kit parent rows are never clickable. Flag data: [isFulfillable data quality](../../../clients/compass-usa/features/isfulfillable-data-quality-and-type-rule.md).
|
|
43
45
|
|
|
44
46
|
## Gotchas
|
|
45
47
|
- **⚠ Before 2026-10-21 add-on parts never showed.** From the first commit (`983686a`, 29 Jul 2026) `buildRows()` drew a `formatChildBundle` entry as one minimal row with "–" for part number / SKU / manufacturer and skipped `childBundle.bundleItems`. Fixed in PR agilantsolutions/toga25-supply#71 (`b2679f2`, `f4c604c`).
|
|
46
48
|
- **An add-on that shows blank (no name, no Kit ID) is usually data, not this table.** If the persona has no `Personas_Bundles` grant on the add-on bundle, the API returns it without a uuid. See [granting persona bundle access](../../../clients/compass-usa/workflows/granting-persona-bundle-access.md#kit-add-on-bundles-need-their-own-personas_bundles-grant).
|
|
47
|
-
- Test orders: copies of Compass SA139536 and SA139507 on client-sandbox carry kits with add-ons. How to copy a prod order: [Compass order lifecycle](../../../clients/compass-usa/workflows/order-lifecycle-and-data-integrity.md#copying-a-prod-order-into-client-sandbox-for-testing).
|
|
49
|
+
- Test orders: copies of Compass SA139536 and SA139507 on client-sandbox carry kits with add-ons. Clickable Qty Fulfilled: Compass SA118967 (laptop `C40QYUC`, 1 fulfilled) on client-sandbox. How to copy a prod order: [Compass order lifecycle](../../../clients/compass-usa/workflows/order-lifecycle-and-data-integrity.md#copying-a-prod-order-into-client-sandbox-for-testing).
|
|
48
50
|
|
|
49
51
|
## Change history
|
|
52
|
+
- 2026-10-29 — Documented the Qty Fulfilled click gate (`isFulfillable`, Compass FEE rule) (TRUE-82989). (bala)
|
|
50
53
|
- 2026-10-21 — Added the `addOn` tier: add-ons render like the main kit with their parts listed (TRUE-82981, PR #71). (bala)
|
|
51
54
|
- 2026-10-21 — `buildAddOnRows()` no longer forces `isPrimary = false` on add-on lines; badge propagation reads only group lead rows (TRUE-82981, commit `26ac427`, CodeRabbit review). (bala)
|
|
@@ -64,6 +64,10 @@ files:
|
|
|
64
64
|
- toga25-supply/src/surface/SurfaceHeader.tsx
|
|
65
65
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/helpers/surfaceBundlesToDecisionFields.ts
|
|
66
66
|
- toga25-supply/src/pages/SalesOrders/view/SalesOrderApprovalModalsLayout/viewModel/useApprovalModalViewModel.tsx
|
|
67
|
+
- toga25-supply/src/layout/ItemRecordModalLayout/ItemRecordCreateModalLayout.tsx
|
|
68
|
+
- toga25-supply/src/layout/ItemRecordModalLayout/hooks/useItemCreateForm.tsx
|
|
69
|
+
- toga25-supply/src/layout/ItemRecordModalLayout/viewModel/FIELDS/COMPASS/itemRecordCreateFields.json
|
|
70
|
+
- toga25-supply/src/layout/ItemRecordModalLayout/viewModel/FIELDS/COMPASSCANADA/itemRecordCreateFields.json
|
|
67
71
|
related:
|
|
68
72
|
- ../workflows/cypress-testing.md
|
|
69
73
|
- ../../_underscore/features/surface-resolver.md
|
|
@@ -165,6 +169,7 @@ The item-record modal's **VIEW** sections are now resolved from Surface for **ev
|
|
|
165
169
|
- **Header Edit button** — an element in `item-record-header`, matched **id-agnostically** by `renderType='BUTTON'` + `config.kind='itemEdit'`. Core seeds it OFF; Compass / Compass Canada opt in.
|
|
166
170
|
- **Vendor-items table** — a dedicated `item-record-vendor-items` **toggle surface** carrying a `config.role='sectionVisibility'` marker element; the FE reads it as **`vendorItemsEnabled`** and conditionally renders the vendor table in `ItemRecordView`. Core-OFF; Compass / Compass Canada opt in.
|
|
167
171
|
- **Fulfillable toggle** (Attributes, after Store Visible; TRUE-82989) — Core element 236 on `item-record-attributes` (surface 17), Core-OFF; Compass / Compass Canada opt in. **Adding a field to this modal takes three edits:** the Surface element (view), the client's `itemRecordEditFields.json` (edit), and the client's `apiFields.json` delta (fetch). `isFulfillable` sits in the COMPASS / COMPASSCANADA deltas only ([why](client-api-fetch-fields.md)). Why it is sent only when dirty: [propagation](../../_underscore/features/fulfillable-item-propagation.md).
|
|
172
|
+
- **Create modal too (2026-10-29).** The create form is JSON, not Surface: the toggle is in COMPASS / COMPASSCANADA `itemRecordCreateFields.json` after Store Visible, starts **ON** (`emptyItemDefaults.isFulfillable: true` in `hooks/useItemCreateForm.tsx`). `ItemRecordCreateModalLayout.tsx` sets `isFulfillableOnCreateForm` when any **section** field has `valueKey: "isFulfillable"` (`headerFields` are not checked); only then does `useItemCreateForm` add `isFulfillable` (true or false) to the `POST /items` body. Other clients' roles have no write grant on 2434, so they never receive the key.
|
|
168
173
|
|
|
169
174
|
#### `showNullAsEmpty` — show `—` for a NULL boolean instead of "No" (opt-in element config)
|
|
170
175
|
|
|
@@ -206,7 +211,7 @@ The item modal's **create** payload now takes its per-tenant defaults from the S
|
|
|
206
211
|
|
|
207
212
|
#### Sending `catalog` by NAME does not trip the Compass POST interceptor
|
|
208
213
|
|
|
209
|
-
`_Model_Compass_Item::postPost` throws *"Could not load catalog uuid"* when it receives a catalog with no uuid, which looks like a reason to send a uuid instead of a name. It is not. api2 invokes the POST payload interceptor with **`$outData` — the created record, not the submitted body** (`V2.php:6019`), and the created record always carries the resolved catalog uuid. Compass has an active POST/POST interceptor on `recordId 21` (Items); Compass Canada has one too, but there is no `_Model_CompassCanada_Item`, so it falls back to `_Model_Client_Item::postPost`, which returns early unless `isFulfillable` was sent. Background: [API payload interceptors](../../api2/features/api-payload-interceptors.md). The name→row match itself is safe because `Items.catalogId` is a `MATCH` field over a record whose `name` is an identifier — [nested-relationship writes](../../api2/features/nested-relationship-writes.md).
|
|
214
|
+
`_Model_Compass_Item::postPost` throws *"Could not load catalog uuid"* when it receives a catalog with no uuid, which looks like a reason to send a uuid instead of a name. It is not. api2 invokes the POST payload interceptor with **`$outData` — the created record, not the submitted body** (`V2.php:6019`), and the created record always carries the resolved catalog uuid. Compass has an active POST/POST interceptor on `recordId 21` (Items); Compass Canada has one too, but there is no `_Model_CompassCanada_Item`, so it falls back to `_Model_Client_Item::postPost`, which returns early unless `isFulfillable` was sent. Since 2026-10-29 the Compass / Canada create form always sends it; the chain walk on a brand-new item finds no order lines and changes nothing. Background: [API payload interceptors](../../api2/features/api-payload-interceptors.md). The name→row match itself is safe because `Items.catalogId` is a `MATCH` field over a record whose `name` is an identifier — [nested-relationship writes](../../api2/features/nested-relationship-writes.md).
|
|
210
215
|
|
|
211
216
|
### SalesOrders approval-decision modal (approve + deny) — migrated via an OVERLAY adapter seam
|
|
212
217
|
|
|
@@ -443,4 +448,5 @@ Related: [legacy page meta](../../_underscore/features/page-meta-context-field-s
|
|
|
443
448
|
- **🚨 Header surfaces use `order.`-prefixed valueKeys; section surfaces use BARE keys.** The record modal top bar builds its surface record as `{ order }`, so header elements read `order.dateOrder`, `order._status`. Section surfaces (`order-details` etc.) resolve against the order **directly**, so their keys are bare: `contact._name`, `_purchaseOrders`, `description`. The same field therefore has two different valueKeys depending on which surface it lives in, and copying one into the other renders blank with no error.
|
|
444
449
|
|
|
445
450
|
## Change history
|
|
451
|
+
- 2026-10-29 — Fulfillable toggle added to the Compass USA + Canada item create modal, default ON (TRUE-82989). (bala)
|
|
446
452
|
- 2026-10-28 — Item modal Fulfillable toggle (Compass USA + Canada) and the opt-in `showNullAsEmpty` element flag (TRUE-82989). (bala)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| [Compass Canada: incoming MITS purchase-order monitor (Monitor/Compass/CompassCanadaIncomingPurchaseOrders)](features/oneuptime-incoming-purchase-orders-monitor.md) | 2.0 | worker2 OneUptime push monitor for Compass Canada sales orders sent to MITS that have not got their full purchase order back, plus how MITS links a Canada PO to |
|
|
10
10
|
| [Compass Canada: PO-to-vendor transmission monitor (Monitor/Compass/CompassCanadaPurchaseOrderTransmissionsToVendors)](features/oneuptime-po-transmissions-to-vendors-monitor.md) | 2.0 | worker2 OneUptime push monitor for Compass Canada POs the 1.0 cron has not yet sent to the vendor (Grand & Toy), plus how the Canada PO transmit cron differs fr |
|
|
11
11
|
| [Compass Canada: sales-order-to-MITS transmission monitor (Monitor/Compass/CompassCanadaSalesOrderTransmission)](features/oneuptime-sales-order-transmission-monitor.md) | 2.0 | worker2 OneUptime push monitor for approved Compass Canada sales orders the 1.0 cron has not yet sent to MITS, plus Canada MITS send-cron timing facts; open whe |
|
|
12
|
-
| [Compass Canada — order fulfillment status (
|
|
12
|
+
| [Compass Canada — order fulfillment status (deployed ASN per-line override; TRUE-79669 base rule pending)](features/order-fulfillment-status-per-line.md) | 2.0 | Canada-specific facts for Compass order fulfillment status: the deployed per-line ASN override that reads `Items.isFulfillable`, and the TRUE-79669 base rule th |
|
|
13
13
|
| [Compass Canada Persona Model (sector-granted vs hand-assigned)](features/persona-model.md) | 2.0 | Where each `Client_CompassCanada` persona comes from: PEOPLE cron (only "All"), sector `Locations_Personas`, or hand-assigned with nothing keeping it in step. |
|
|
14
14
|
| [Compass Canada](profile.md) | 2.0 | Compass Canada is the Canadian arm of the Compass account — a separate TOGA tenant, related to but distinct from Compass USA. |
|
|
15
15
|
| [Copying a Compass USA user into the Canada tenant (cross-tenant hand-add)](workflows/copying-a-us-user-into-the-canada-tenant.md) | 2.0 | Giving a Compass **USA** person a login on the Canada TechHub portal: the guarded insert chain, the uuid role/persona mapping, and the worker2 guard that stops |
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Compass Canada — order fulfillment status (
|
|
2
|
+
title: Compass Canada — order fulfillment status (deployed ASN per-line override; TRUE-79669 base rule pending)
|
|
3
3
|
framework: "2.0"
|
|
4
4
|
repo: _underscore
|
|
5
5
|
project: _Underscore
|
|
6
6
|
client: compass-canada
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-29
|
|
10
10
|
owners: ["bala", "jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/SalesOrder.php
|
|
@@ -18,24 +18,41 @@ related:
|
|
|
18
18
|
- ../../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
|
|
19
19
|
- grand-and-toy-asn-import.md
|
|
20
20
|
---
|
|
21
|
-
Canada-specific facts for
|
|
21
|
+
Canada-specific facts for Compass order fulfillment status: the deployed per-line ASN override that reads `Items.isFulfillable`, and the TRUE-79669 base rule that will replace it; open before touching Canada order status or Canada `isFulfillable`.
|
|
22
22
|
|
|
23
23
|
## Summary
|
|
24
|
-
|
|
24
|
+
- **Deployed today** (verified 2026-10-29: `_underscore` `origin/_sandbox-client` and `_production`, same file): Canada has its **own** `_fulfillmentStatus()` override, a per-line rule on ASN quantity. It skips lines with `Items.isFulfillable = 0`. So the TOGa Supply Fulfillable toggle changes Canada order status **now**.
|
|
25
|
+
- **Decided, not merged** (TRUE-79669, 2026-10-15): delete the override and run the standard base per-line rule, same as USA. Rule, gates and blast radius: **[Compass USA + Canada — order fulfillment status](../../compass-usa/features/order-fulfillment-status-per-line.md)**.
|
|
25
26
|
|
|
26
27
|
## How it works
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
### Deployed override (`_Model_Compass_Canada_SalesOrder`)
|
|
29
|
+
```
|
|
30
|
+
pendingFulfillment ASN qty on expected lines = 0
|
|
31
|
+
partiallyFulfilled any expected line has quantity > ASN qty
|
|
32
|
+
fulfilled otherwise
|
|
33
|
+
```
|
|
34
|
+
- **Expected line** (`_isExpectedToShipLine`): `price > 0` AND has a `SalesOrderItems_PurchaseOrderItems` row AND `ItemTypes.name` not in `ITEM_TYPES__NOT_SHIPPABLE` (`SERVICE`, `SERVICES`, `CONSULTING`, `WARRANTY`) AND `COALESCE(Items.isFulfillable, 1) = 1`.
|
|
35
|
+
- **Shipped qty** (`_qtyShippedByAsn`): `SUM(AdvanceShippingNoticeItems.quantity)` through the SO→PO item bridge. ASN, not ItemFulfillmentItems.
|
|
36
|
+
- Effect of the toggle: switching an **unshipped** item OFF drops its line from the check, so the order can move Partially Fulfilled → Fulfilled. NULL counts as ON.
|
|
37
|
+
|
|
38
|
+
### After TRUE-79669 (not deployed)
|
|
39
|
+
- Shipped qty comes from **ItemFulfillmentItems** (created from Grand & Toy ASNs — [G&T ASN Import](grand-and-toy-asn-import.md)).
|
|
40
|
+
- Non-shipping lines are excluded only by `Items.isFulfillable = 0` (no type list, no price / PO-link filter). `2026-10-15a - NonShippableItemTypesNotFulfillable.sql` sets CONSULTING / SERVICE / SERVICES / WARRANTY items to 0.
|
|
29
41
|
- `ItemTypes` is the only usable type column in Canada (no `FEE` asset type).
|
|
30
42
|
|
|
43
|
+
### Test orders (client-sandbox, 2026-10-29)
|
|
44
|
+
- `SAC100804`: `77-87476` shipped, `MXPN3CL/A` not shipped = Partially Fulfilled. Toggle `MXPN3CL/A` OFF → Fulfilled.
|
|
45
|
+
- `SAC100724`: Fulfilled.
|
|
46
|
+
|
|
31
47
|
## Gotchas
|
|
32
|
-
- **⚠
|
|
33
|
-
- **46 open Canada orders have an ASN but no IF** (measured locally 2026-10-15)
|
|
34
|
-
-
|
|
48
|
+
- **⚠ New items created in TOGa Supply start `isFulfillable = 1`** (create toggle default ON, 2026-10-29). A new SERVICE / CONSULTING / WARRANTY item is still skipped by the deployed type list, but after TRUE-79669 it holds orders at Partially Fulfilled unless switched OFF.
|
|
49
|
+
- **46 open Canada orders have an ASN but no IF** (measured locally 2026-10-15). The deployed ASN rule counts them as shipped; they will read **Pending Fulfillment** after TRUE-79669. Fix by creating the missing IF, not by changing the rule.
|
|
50
|
+
- Do not trust "no Canada override" in older notes: the override is still live until TRUE-79669 merges. Check the deployed branch before reasoning about Canada status.
|
|
35
51
|
|
|
36
52
|
## Change history
|
|
37
|
-
- 2026-10-
|
|
38
|
-
- 2026-
|
|
53
|
+
- 2026-10-29 — Verified the deployed override still runs and reads `isFulfillable`; toggle test on SAC100804 (TRUE-82989). (bala)
|
|
54
|
+
- 2026-10-15 — TRUE-79669: Canada override and `ITEM_TYPES__NOT_SHIPPABLE` deleted on branch; service item types set to `isFulfillable = 0`. Not deployed. (jcardinal)
|
|
55
|
+
- 2026-09-16 — Canada per-line ASN-bridge rule (90 orders corrected). (bala)
|
|
39
56
|
|
|
40
57
|
## Related
|
|
41
58
|
- [Compass USA + Canada — order fulfillment status](../../compass-usa/features/order-fulfillment-status-per-line.md)
|
|
@@ -248,14 +248,16 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
|
|
|
248
248
|
All **228** prod items were still NULL (never stamped; Canada has no NetSuite, so no sync ever
|
|
249
249
|
writes it). `Client_CompassCanada/2026-10-28a` sets NULL rows to 0 for `Fee` / `Services` asset
|
|
250
250
|
types and service / consulting / warranty item types (**14**), else 1 (**214**), and turns on the
|
|
251
|
-
Fulfillable toggle in the toga25-supply item modal.
|
|
252
|
-
toggle
|
|
251
|
+
Fulfillable toggle in the toga25-supply item modal. Since 2026-10-29 the create modal has the
|
|
252
|
+
toggle too (default ON), so new items start at 1; switch it OFF for service items. The deployed
|
|
253
|
+
Canada status rule already skips `isFulfillable = 0` lines. Canada uses a **different type vocabulary** than USA (title-case asset types, its own
|
|
253
254
|
item types). See
|
|
254
255
|
[isFulfillable — Data Quality & the Type-Derived Rule](../compass-usa/features/isfulfillable-data-quality-and-type-rule.md).
|
|
255
256
|
- The 2026-06-08 ASN → ItemFulfillment work was for **Compass USA**, not Compass Canada.
|
|
256
|
-
- **Order status =
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
- **Order status: deployed = Canada's own per-line ASN override (reads `isFulfillable`, verified
|
|
258
|
+
2026-10-29); decided = the standard base per-line rule (TRUE-79669, 2026-10-15, not merged).**
|
|
259
|
+
TRUE-79669 deletes the override and `ITEM_TYPES__NOT_SHIPPABLE`; service item types are set to
|
|
260
|
+
`isFulfillable = 0` instead. IF stages (picked/packed/shipped) are seeded by
|
|
259
261
|
`dbchanges2/Client_CompassCanada/2026-06-30a - ItemFulfillmentLifecycleAndShippedBackfill.sql`.
|
|
260
262
|
[Canada order fulfillment status](features/order-fulfillment-status-per-line.md).
|
|
261
263
|
- **Item titles in customer emails** come from the `ItemTranslations` sidecar (prod: 220 fr-CA rows,
|
|
@@ -19,6 +19,8 @@ files:
|
|
|
19
19
|
- dbchanges2/Client_Compass/2026-10-28a - ItemsIsFulfillableToggleVisible.sql
|
|
20
20
|
- dbchanges2/Client_CompassCanada/2026-10-28a - ItemsIsFulfillableToggleAndBackfill.sql
|
|
21
21
|
- toga25-supply/src/layout/ItemRecordModalLayout/hooks/useItemEditForm.tsx
|
|
22
|
+
- toga25-supply/src/layout/ItemRecordModalLayout/hooks/useItemCreateForm.tsx
|
|
23
|
+
- _underscore/Model/Compass/Canada/SalesOrder.php
|
|
22
24
|
related:
|
|
23
25
|
- ../profile.md
|
|
24
26
|
- ../../compass-canada/profile.md
|
|
@@ -32,7 +34,7 @@ Why Compass storefront Qty-Fulfilled cells stay dead — `Items.isFulfillable` N
|
|
|
32
34
|
## Summary
|
|
33
35
|
A prod-data investigation (2026-08-12, read-only) into why so many Compass storefront lines still have a dead **Qty Fulfilled** cell. Conclusion: the remaining `Items.isFulfillable` NULLs are **not a backfill backlog — they are structurally unreachable**, and the values that *are* set are partly wrong. Records the measured state of `Client_Compass` / `Client_CompassCanada`, the evidence for/against deriving the flag from item type, the **decision** to override NetSuite with a type-derived rule for Compass, and the **write-time guard** that decision requires to survive the daily NetSuite sync.
|
|
34
36
|
|
|
35
|
-
**⚠
|
|
37
|
+
**⚠ The flag also drives order status.** Deployed today (verified 2026-10-29): **Canada only** — its override skips `isFulfillable = 0` lines ([Canada status](../../compass-canada/features/order-fulfillment-status-per-line.md)); USA still uses order totals and ignores the flag. Once TRUE-79669 merges, both use the base rule, which skips 0 and counts NULL as fulfillable ([order fulfillment status](order-fulfillment-status-per-line.md)). A wrong 1/NULL on a non-shipping item then holds orders at Partially Fulfilled. Figures dated 2026-08-12 were read from production that date; later sections (retraction, column choice, data-fix status) were measured 2026-08-27 against prod and client-sandbox as marked.
|
|
36
38
|
|
|
37
39
|
## How it works
|
|
38
40
|
|
|
@@ -104,6 +106,7 @@ String(item?.Items?.isFulfillable) === "1" && Number(item?._qtyFulfilled) !== 0
|
|
|
104
106
|
plus an extra **hardcoded** `hostName === COMPASS && AssetTypes.name === 'FEE' → false`.
|
|
105
107
|
- NULL and 0 behave identically at this gate.
|
|
106
108
|
- That FEE hardcode duplicates the proposed data rule — once the rule lands in the DB it should be deleted so the logic lives in one place.
|
|
109
|
+
- toga25-supply mirrors this gate (true or 1, FEE hardcode included) in the sales order Items table — see [Sales order Items table](../../../2.0/apps/toga25-supply/features/sales-order-items-table.md).
|
|
107
110
|
|
|
108
111
|
### Compass Canada uses a DIFFERENT type vocabulary
|
|
109
112
|
Canada's `assetTypes` are **title case** (`Equipment`, `Hardware`, `Services`, `Fee`, `Consulting`) and its `itemTypes` are a separate vocabulary (`LAPTOP`, `MACBOOK`, `MONITORS`, `CABLES`, `SERVICE`, `Services`, `CONSULTING`, `SOFTWARE LICENSING`) — it has **no `FEE` or `SERVICEFEES` itemType at all**.
|
|
@@ -125,6 +128,8 @@ The two columns disagree, and the gap matters:
|
|
|
125
128
|
**Compass Canada reads both columns.** `2026-10-15a` set only Canada's non-shipping `ItemTypes` (`SERVICE`, `SERVICES`, `CONSULTING`, `WARRANTY`) to 0; the 2026-10-28 backfill (below) also uses `AssetTypes` `Fee` / `Services`, which do exist in Canada. See [Compass Canada — order fulfillment status](../../compass-canada/features/order-fulfillment-status-per-line.md).
|
|
126
129
|
|
|
127
130
|
### Editing the flag in TOGa Supply — the item modal toggle (TRUE-82989, 2026-10-28)
|
|
131
|
+
- **Why it exists:** the Dev Team sets `Items.isFulfillable` from TOGa Supply instead of a DB update, because the flag drives order fulfillment status (Canada today, USA after TRUE-79669) and the Qty Fulfilled drill-down.
|
|
132
|
+
- **Create modal (2026-10-29):** same toggle on item create, **default ON**, so a new Compass / Canada item is saved with `isFulfillable = 1`, not NULL. Turn it OFF on create for a fee / service / warranty item. FE detail: [Surface Frontend](../../../2.0/apps/toga25-supply/features/surface-frontend.md).
|
|
128
133
|
- **Fulfillable toggle** in the toga25-supply item record modal, Attributes section after Store Visible, **Compass USA + Compass Canada only**. FE wiring (view = Surface, edit = JSON, `apiFields` scoping): [Surface Frontend](../../../2.0/apps/toga25-supply/features/surface-frontend.md). Seed (Core element 236, client opt-in): [Surface Layer Schema](../../../2.0/apps/dbchanges2/features/surface-layer-schema.md).
|
|
129
134
|
- **Save sends `isFulfillable` only when the toggle changed**, because the key alone triggers a chain walk — see [propagation](../../../2.0/apps/_underscore/features/fulfillable-item-propagation.md).
|
|
130
135
|
- **View shows `—` for NULL** ("not set yet"; propagation skips NULL), `No` for 0, `Yes` for 1.
|
|
@@ -133,7 +138,7 @@ The two columns disagree, and the gap matters:
|
|
|
133
138
|
- **USA** values still come from the NetSuite item sync (gotchas below); **67** USA items still NULL in prod (2026-10-28).
|
|
134
139
|
|
|
135
140
|
### Data fixes written for TRUE-79669 (2026-10-15, `dbchanges2` branch `TRUE-79669`, not run in prod)
|
|
136
|
-
- `Client_Compass/2026-10-15a - FeeItemsNotFulfillable.sql` — every `ItemTypes.name = 'FEE'` item → 0 (13 of 16 already 0; `LT-FREIGHT`, `LT-PROPERTY TAX`, `TabAdminSupp` were 1). ItemTypes only — the wider assetType/catalog rule below is still pending.
|
|
141
|
+
- `Client_Compass/2026-10-15a - FeeItemsNotFulfillable.sql` — every `ItemTypes.name = 'FEE'` item → 0 (13 of 16 already 0; `LT-FREIGHT`, `LT-PROPERTY TAX`, `TabAdminSupp` were 1; `LT-FREIGHT` and `LT-PROPERTY TAX` still 1 on client-sandbox 2026-10-29, so they will hold USA orders at Partially Fulfilled once the per-line rule ships unless this file runs first). ItemTypes only — the wider assetType/catalog rule below is still pending.
|
|
137
142
|
- `Client_CompassCanada/2026-10-15a - NonShippableItemTypesNotFulfillable.sql` — CONSULTING / SERVICE / SERVICES / WARRANTY → 0.
|
|
138
143
|
|
|
139
144
|
### Status of the type-derived data fix (verified 2026-08-27)
|
|
@@ -146,7 +151,7 @@ The developer's two-statement `UPDATE`, scoped to `catalogId = 1`, sets `isFulfi
|
|
|
146
151
|
| prod | not applied |
|
|
147
152
|
|
|
148
153
|
## Gotchas
|
|
149
|
-
- **⚠ New Compass Canada
|
|
154
|
+
- **⚠ New Compass / Canada items created in TOGa Supply start with `isFulfillable = 1`** (create toggle defaults ON, 2026-10-29). A new fee / service / warranty item must be switched OFF on create or later, or it counts as a shipping line. Items created any other way (api2 without the key) still start NULL. No write-time guard yet.
|
|
150
155
|
- **⚠ `Client_Compass/2026-08-11 - ItemsIsFulfillableFieldPermissions.sql` grants the WRONG field.** It uses `recordFieldId 2615`, which is `inventoryAdjustmentItemId`, not `isFulfillable` (**2434**). Check the RecordFields id against prod before trusting a grant file's name.
|
|
151
156
|
- **⚠ CRITICAL — a backfill alone will be undone by the daily NetSuite sync.** Phase 1's `getCreateItem` **refreshes `isFulfillable` on EXISTING items** whenever NetSuite's value differs from the stored value. NetSuite returns **`T` for service (`NonInvtPart`) items**, so any type-derived **0** is flipped back to 1 on the next sync run. Proven from the audit log: Compass items **2382 / 2384 / 2385** (`US-IOS-SSC-SHR`, `US-IOS-VENUENEXT`, `US-IOS-VIRTUALMGR` — itemType `SERVICES`, assetType `CONSULTING`) were stamped NULL → 1 on 2026-08-04 13:56:00-01 by `apiId 1`, `userId NULL`, inside a 1–2 items/second cron sweep that began 13:45 and set every item to 1. **Therefore the rule MUST be enforced at write time** — a `prePut`/`prePost` guard on Items in `_Model_Client_Item` — in addition to the backfill migration. A migration on its own silently reverts within a day.
|
|
152
157
|
- **⚠ Recorded caveat — the SERVICES/CONSULTING half of the rule is NOT supported by the evidence.** 413 `SERVICES` fulfillment rows carry their own tracking, and the rule flips **131 currently-clickable items off**. That half needs product sign-off. `SOFTWARE` (100% ride-along) is the *stronger* candidate on the evidence but was deliberately left out of scope.
|
|
@@ -158,8 +163,9 @@ The developer's two-statement `UPDATE`, scoped to `catalogId = 1`, sets `isFulfi
|
|
|
158
163
|
- **⚠ The `catalogId = 1` scope misses 49 items carrying 52,367 priced order lines** — `PC-KIT-OPT2` (33,259 lines), `CG-MEDKITTING` (6,317), `CG-MEDKITTING-NWN-APPLE`, `ASI-WAREHAND`, `ODP-COMPASS_KIOSKBUILD` — all on catalog 2 or NULL, all flagged `isFulfillable = 1`, and **none has ever shipped**. They cause no problem *today* only because none has a PO link, so a purchased-line test excludes them anyway. Widen the scope or accept the flag is wrong on the largest-volume non-shipping SKU in the catalog.
|
|
159
164
|
|
|
160
165
|
## Change history
|
|
166
|
+
- 2026-10-29 — Fulfillable toggle on the item create modal, default ON (new items no longer start NULL); deployed status rule verified: Canada reads the flag, USA does not (TRUE-82989). (bala)
|
|
161
167
|
- 2026-10-28 — Fulfillable toggle in the toga25-supply item modal for USA + Canada; USA write grant on 2434 for roles 4/7; Canada NULL backfill 14 → 0 / 214 → 1 (TRUE-82989). (bala)
|
|
162
|
-
- 2026-10-15 — The flag now drives Compass order status (TRUE-79669); FEE (USA) and service-type (Canada) data fixes written; new Canada service items
|
|
168
|
+
- 2026-10-15 — The flag now drives Compass order status (TRUE-79669); FEE (USA) and service-type (Canada) data fixes written; new Canada service items started NULL (follow-up, closed 2026-10-29 by the create toggle). (jcardinal)
|
|
163
169
|
|
|
164
170
|
## Related
|
|
165
171
|
- [Phase 1 — isFulfillable from NetSuite during item sync (1.0)](../../../1.0/apps/library/features/netsuite-item-isfulfillable-sync.md) — where the value is born and the refresh that reverts overrides.
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: compass-usa
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-29
|
|
10
10
|
owners: ["bala", "jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/SalesOrder.php
|
|
@@ -35,6 +35,10 @@ Why now: the old reason to keep USA on order totals (ODP duplicate ASNs, broken
|
|
|
35
35
|
|
|
36
36
|
**State:** `_underscore` branch `TRUE-79669` (not yet merged), data SQL committed on `dbchanges2` `TRUE-79669`. **Not deployed** — non-prod test planned first.
|
|
37
37
|
|
|
38
|
+
**Deployed today (verified 2026-10-29 on `origin/_sandbox-client` and `_production`):**
|
|
39
|
+
- **USA:** `_Model_Compass_SalesOrder::_fulfillmentStatus()` is still the **order-total** rule (TOGA Tech IFs + Strategic Systems ASNs). It does **not** read `isFulfillable`, so the TOGa Supply Fulfillable toggle does not change USA order status yet. Test orders on client-sandbox: `SA118967`, `SA132389`.
|
|
40
|
+
- **Canada:** still its own per-line ASN override, which **does** skip `isFulfillable = 0` lines — see [Canada status](../../compass-canada/features/order-fulfillment-status-per-line.md).
|
|
41
|
+
|
|
38
42
|
## How it works
|
|
39
43
|
|
|
40
44
|
### Key files / entry points
|
|
@@ -80,6 +84,7 @@ fulfilled otherwise
|
|
|
80
84
|
- **Superseded — do not resurrect:** the USA "order-total kept on purpose (2026-08-27)" decision and Canada's ASN-bridge per-line rule (90 orders corrected, `ITEM_TYPES__NOT_SHIPPABLE`). Order totals let one line's surplus hide another's gap; the base per-line rule replaces both.
|
|
81
85
|
|
|
82
86
|
## Change history
|
|
87
|
+
- 2026-10-29 — Verified deployed state: USA still order-total (ignores `isFulfillable`), Canada override still live (TRUE-82989). (bala)
|
|
83
88
|
- 2026-10-15 — TRUE-79669: Compass USA + Canada switched to the standard base `_fulfillmentStatus()` (per line, skips `isFulfillable = 0`, adds Picked/Packed); deleted USA order-total rule and Canada ASN override; FEE / service item data fixes. Supersedes the 2026-08-27 "USA keeps order-total" decision. Not deployed. (jcardinal)
|
|
84
89
|
- 2026-10-13 — Noted that Fulfilled has no stage and is reached only through shipped quantity. (bala)
|
|
85
90
|
- 2026-08-27 — Per-line USA rule built, measured (5,223 orders) and reverted; Canada got its own ASN per-line rule. (bala)
|
|
@@ -288,7 +288,8 @@ separate, related client (see its own profile).
|
|
|
288
288
|
Compass USA + Canada keep only their approval gates in `_Model_Compass_SalesOrder::_status`; the
|
|
289
289
|
fulfillment half is the base `_Model_Client_SalesOrder::_fulfillmentStatus()` (per line, shipped
|
|
290
290
|
IF qty, skips `isFulfillable = 0`, shows Picked/Packed). Replaces the order-total rule kept on
|
|
291
|
-
purpose since 2026-08-27. Needs fee items at `isFulfillable = 0`.
|
|
291
|
+
purpose since 2026-08-27. Needs fee items at `isFulfillable = 0`. **Deployed code (verified
|
|
292
|
+
2026-10-29) still runs the order-total rule and ignores `isFulfillable`.**
|
|
292
293
|
[Order fulfillment status](features/order-fulfillment-status-per-line.md).
|
|
293
294
|
- **⚠ The approval gate strands far more orders than the fulfillment rule mislabels (2026-08-27).**
|
|
294
295
|
**11,341** Compass USA orders sit at a pending-approval status and never reach the fulfillment
|
|
@@ -313,7 +314,7 @@ separate, related client (see its own profile).
|
|
|
313
314
|
[isFulfillable — Data Quality & the Type-Derived Rule](features/isfulfillable-data-quality-and-type-rule.md).
|
|
314
315
|
**Editable in TOGa Supply since TRUE-82989 (2026-10-28):** Fulfillable toggle in the toga25-supply
|
|
315
316
|
item modal; `Client_Compass/2026-10-28a` grants write on 2434 to roles 4 (Admin) + 7 (Compass
|
|
316
|
-
Base). Same doc.
|
|
317
|
+
Base). Create modal too since 2026-10-29 (default ON). Same doc.
|
|
317
318
|
|
|
318
319
|
|
|
319
320
|
## Talos tenant reference
|
package/package.json
CHANGED