toga-ai 1.0.55 → 1.0.57
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/INDEX.md
CHANGED
|
@@ -9,7 +9,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
9
9
|
|
|
10
10
|
## 2.0 framework
|
|
11
11
|
|
|
12
|
-
- **_underscore** (_Underscore) _(framework core)_ —
|
|
12
|
+
- **_underscore** (_Underscore) _(framework core)_ — 5 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
13
13
|
- **worker2** (Worker) — 5 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
14
14
|
- **api2** (API) — 1 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
15
15
|
- **dbchanges2** (Database Changes) _(framework core)_ — 1 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
| Doc | Framework | Summary | Files |
|
|
4
4
|
|-----|-----------|---------|-------|
|
|
5
5
|
| [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql |
|
|
6
|
-
| [Compass: Item
|
|
6
|
+
| [Compass: Item-Fulfillment TableViews (for-sales-order-items & for-sales-orders, tracking via bridge)](features/item-fulfillment-tracking-tableview.md) | 2.0 | Two sibling Compass TableViews in `Client_Compass` display fulfilled items in toga2-supply, both driven by `TableViews` / `TableViewJoins` / `TableViewFields` c | dbchanges2/Client_Compass/2026-06-10 - ItemFulfillmentsForSalesOrderItemsTableView.sql, dbchanges2/Client_Compass/2026-06-11 - ItemFulfillmentsForSalesOrdersTableView.sql |
|
|
7
|
+
| [Compass MITS PO → SO Item Linking](features/mits-po-to-so-item-linking.md) | 2.0 | MITS sends Compass inbound Purchase Orders (`POST /v2/purchase-orders`) against a Sales Order (`mitsSalesOrder`). | _underscore/Model/Compass/PurchaseOrder.php |
|
|
7
8
|
| [Compass USA](profile.md) | 2.0 | Compass USA is a TOGA client running a multi-tier supply-chain commerce operation. | |
|
|
@@ -1,46 +1,85 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Compass: Item
|
|
2
|
+
title: "Compass: Item-Fulfillment TableViews (for-sales-order-items & for-sales-orders, tracking via bridge)"
|
|
3
3
|
framework: "2.0"
|
|
4
4
|
project: _Underscore
|
|
5
5
|
client: compass-usa
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
8
|
+
updated: 2026-06-11
|
|
9
9
|
owners: ["jcardinal"]
|
|
10
10
|
files:
|
|
11
11
|
- dbchanges2/Client_Compass/2026-06-10 - ItemFulfillmentsForSalesOrderItemsTableView.sql
|
|
12
|
+
- dbchanges2/Client_Compass/2026-06-11 - ItemFulfillmentsForSalesOrdersTableView.sql
|
|
12
13
|
related:
|
|
13
14
|
- ../../../2.0/apps/_underscore/features/tracking-number-bridges.md
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
## Summary
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
**Units** with INNER joins (so non-serialized items with no unit never appeared) and sourced the
|
|
21
|
-
outbound tracking number from the now-dropped `ItemFulfillmentItemUnits.trackingNumberId`.
|
|
19
|
+
Two sibling Compass TableViews in `Client_Compass` display fulfilled items in toga2-supply,
|
|
20
|
+
both driven by `TableViews` / `TableViewJoins` / `TableViewFields` config (no PHP):
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
- **`item-fulfillments-for-sales-order-items`** (`TableViews.id = 13`) — fulfilled items for a
|
|
23
|
+
single sales-order line.
|
|
24
|
+
- **`item-fulfillments-for-sales-orders`** (`TableViews.id = 12`) — fulfilled items across the
|
|
25
|
+
whole sales order.
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
Both were originally **rooted at `Units` (record 31) with INNER joins upward**, so any fulfilled
|
|
28
|
+
item with no serialized unit (no `ItemFulfillmentItemUnits` / `Units`) never appeared — and for
|
|
29
|
+
view 12, an entire order with zero unit-level rows returned **0 records** even though its items
|
|
30
|
+
were fulfilled. View 13 was re-rooted on 2026-06-10; view 12 on 2026-06-11.
|
|
31
|
+
|
|
32
|
+
## How it works (new definitions)
|
|
33
|
+
|
|
34
|
+
Both views are re-rooted at **`ItemFulfillmentItems` (record 29)** so every fulfilled item appears,
|
|
35
|
+
with the unit/tracking chain made **OUTER** so missing units no longer drop rows.
|
|
36
|
+
|
|
37
|
+
**View 13 — `item-fulfillments-for-sales-order-items`:**
|
|
38
|
+
- INNER `SalesOrderItems`; OUTER `ItemFulfillmentItemUnits` → OUTER `Units` → OUTER
|
|
39
|
+
`ItemFulfillmentItemUnits_TrackingNumbers` (record 319) → OUTER `TrackingNumbers` → OUTER `ShippingCarriers`.
|
|
40
|
+
- Columns: **Sales Order Line Number, Quantity Fulfilled (`ItemFulfillmentItems.quantity`),
|
|
30
41
|
Outbound Tracking #, Carrier, Serial #, Asset Tag.**
|
|
31
|
-
|
|
42
|
+
|
|
43
|
+
**View 12 — `item-fulfillments-for-sales-orders`:**
|
|
44
|
+
- Same base + OUTER unit/tracking chain, plus the order-scoping INNER joins:
|
|
45
|
+
INNER `SalesOrderItems`, INNER `ItemFulfillments`, INNER `SalesOrders`, INNER `Items`.
|
|
46
|
+
- Columns: **Sales Order Line Number, Part Number (`Items.partNumber`), Quantity Fulfilled,
|
|
47
|
+
Outbound Tracking # (hyperlink via `TrackingNumbers._hyperlink` rf 1272), Carrier, Serial #, Asset Tag.**
|
|
48
|
+
- Default sort re-pointed to the line-number field.
|
|
49
|
+
|
|
50
|
+
Stable Core ids used: records 29 IFI, 30 IFIU, 31 Units, 15 SalesOrderItems, 14 SalesOrders,
|
|
51
|
+
28 ItemFulfillments, 21 Items, 319 IFIU-tracking bridge, 62 TrackingNumbers, 9 ShippingCarriers.
|
|
52
|
+
|
|
53
|
+
## Data model
|
|
54
|
+
|
|
55
|
+
Join keys (RecordField ids): 60 SOI.id / 368 IFI.salesOrderItemId; 360 IF.id / 367 IFI.itemFulfillmentId;
|
|
56
|
+
59 SO.id / 254 SOI.salesOrderId; 105 Item.id / 66 SOI.itemId; 374 IFIU.itemFulfillmentItemId / 365 IFI.id;
|
|
57
|
+
236 Unit.id / 375 IFIU.unitId; 2183 bridge.itemFulfillmentItemUnitId / 372 IFIU.id;
|
|
58
|
+
336 TN.id / 2184 bridge.trackingNumberId; 21 SC.id / 613 TN.shippingCarrierId.
|
|
32
59
|
|
|
33
60
|
## Gotchas / known issues
|
|
34
61
|
|
|
62
|
+
- **A Unit-rooted view returns 0 rows whenever the order has no unit-level breakdown.** Symptom
|
|
63
|
+
seen on SA132740 (salesOrderId 105826): 13 SalesOrderItems, 7 ItemFulfillmentItems, but **0
|
|
64
|
+
ItemFulfillmentItemUnits / 0 Units** → view 12 showed "0 records" while the re-rooted sibling
|
|
65
|
+
view 13 showed the items fine. Fix is structural (re-root + OUTER chain), independent of the
|
|
66
|
+
missing-unit data issue.
|
|
35
67
|
- Tracking is sourced through the bridge join (`ItemFulfillmentItemUnits_TrackingNumbers.trackingNumberId`),
|
|
36
|
-
NOT the dropped column. The bridge record/fields
|
|
37
|
-
|
|
38
|
-
- `TableViews.sortPrimaryTableViewFieldId` is a FK to `TableViewFields`; it
|
|
39
|
-
old fields
|
|
68
|
+
NOT the dropped `ItemFulfillmentItemUnits.trackingNumberId` column. The bridge record/fields
|
|
69
|
+
(319 / 2183 / 2184) come from the Core migration and must exist before these files run.
|
|
70
|
+
- `TableViews.sortPrimaryTableViewFieldId` is a FK to `TableViewFields`; set it NULL before deleting
|
|
71
|
+
the old fields, then re-point via a multi-table UPDATE (not a self-subquery) to avoid MySQL 1093.
|
|
40
72
|
- `TableViewFields` must be deleted before `TableViewJoins` (`tableViewJoinId` FK).
|
|
73
|
+
- With null `joinOnTableViewJoinId`, the engine resolves a join's parent table by the `recordId` of
|
|
74
|
+
`parentRecordFieldId` — this only works because each record appears once in the graph. Reusing a
|
|
75
|
+
record twice in one view would require an explicit `joinOnTableViewJoinId`.
|
|
41
76
|
|
|
42
77
|
## Client variations
|
|
43
|
-
|
|
78
|
+
Compass-only. The underlying bridge model is shared (see the _underscore feature doc).
|
|
79
|
+
|
|
80
|
+
## Change history
|
|
81
|
+
- 2026-06-11 — Re-rooted `item-fulfillments-for-sales-orders` (id 12) from Units to ItemFulfillmentItems with OUTER unit/tracking chain; fixes 0-records on orders lacking unit breakdown (e.g. SA132740). (jcardinal)
|
|
82
|
+
- 2026-06-10 — Re-rooted `item-fulfillments-for-sales-order-items` (id 13) and moved tracking to the bridge join. (jcardinal)
|
|
44
83
|
|
|
45
84
|
## Related docs
|
|
46
85
|
- 2.0 _underscore: Tracking-Number Bridge Migration.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compass MITS PO → SO Item Linking
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: _underscore
|
|
5
|
+
project: _Underscore
|
|
6
|
+
client: compass-usa
|
|
7
|
+
type: client-feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-11
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- _underscore/Model/Compass/PurchaseOrder.php
|
|
13
|
+
related:
|
|
14
|
+
- asn-to-item-fulfillment.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Summary
|
|
18
|
+
MITS sends Compass inbound Purchase Orders (`POST /v2/purchase-orders`) against a Sales Order
|
|
19
|
+
(`mitsSalesOrder`). `_Model_Compass_PurchaseOrder` links each `PurchaseOrderItem` to the
|
|
20
|
+
`SalesOrderItem` it fulfills via the `SalesOrderItems_PurchaseOrderItems` bridge. There are
|
|
21
|
+
**two distinct linking paths** depending on order type, and conflating them caused a
|
|
22
|
+
production data-integrity bug.
|
|
23
|
+
|
|
24
|
+
## Key files / entry points
|
|
25
|
+
- `_underscore/Model/Compass/PurchaseOrder.php` — `prePost` (SA path + MR via `handleMrOrder`)
|
|
26
|
+
and `postPost` (link creation).
|
|
27
|
+
- USA/Canada subclasses (`Model/Compass/Usa|Canada/PurchaseOrder.php`) are empty and inherit
|
|
28
|
+
this behavior — edit the parent.
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
- **SA orders (normal):** each inbound PO item carries `createdFromSalesOrderItem.lineNumber`
|
|
32
|
+
(the MITS line, which includes configuration-line offsets). `prePost` remaps it to the real
|
|
33
|
+
SO `lineNumber` via `$mapIncomingLineNumbersToOriginalLineNumbers` and builds
|
|
34
|
+
`salesOrderItemPurchaseOrderItems` on the payload, so the **correct** bridge rows are created
|
|
35
|
+
by the normal nested API write. This is the authoritative SA linkage.
|
|
36
|
+
- **MR orders (`mitsSalesOrder` starts with `MR`):** `prePost` calls `handleMrOrder` and
|
|
37
|
+
returns early. `handleMrOrder` creates/appends the SO from the PO items, **strips**
|
|
38
|
+
`createdFromSalesOrderItem`, and deliberately **aligns** SO and PO `lineNumber`s. It does
|
|
39
|
+
NOT build the item bridge — so the `postPost` lineNumber-match pass is the **only** (and
|
|
40
|
+
correct) MR linking mechanism.
|
|
41
|
+
|
|
42
|
+
## Data model
|
|
43
|
+
- `SalesOrderItems_PurchaseOrderItems` (`Client_Compass`): `uuid`, `salesOrderItemId`,
|
|
44
|
+
`purchaseOrderItemId`. One row per (SO item, PO item) the PO fulfills.
|
|
45
|
+
- A PO item's `lineNumber` is **PO-local (1..N per PO)** — NOT the SO line number.
|
|
46
|
+
|
|
47
|
+
## Client variations
|
|
48
|
+
USA and Canada share the parent handler unchanged.
|
|
49
|
+
|
|
50
|
+
## Gotchas / known issues
|
|
51
|
+
- **Spurious cross-part links from the `postPost` lineNumber join (fixed 2026-06-11).** The
|
|
52
|
+
`postPost` link pass matched `SalesOrderItems.lineNumber = PurchaseOrderItems.lineNumber`
|
|
53
|
+
for *all* orders. For SA orders that is wrong: PO line numbers are PO-local, so whenever an
|
|
54
|
+
SO is split across multiple POs, or carries non-PO lines (freight/tax/warranty) that shift
|
|
55
|
+
the SO line numbers, the join created extra links pointing PO items at the **wrong** SO line
|
|
56
|
+
(different part). The correct SA links already existed from `prePost`; the `postPost` pass
|
|
57
|
+
only added bogus duplicates. Detection: ~40% of recent SA orders had ≥1 link where the PO
|
|
58
|
+
item's part ≠ the SO item's part. **Fix:** guard the `postPost` link block with
|
|
59
|
+
`if (static::isMrOrder($api->httpPayload))` so it runs for MR only. A link whose PO-item
|
|
60
|
+
part ≠ SO-item part is always invalid (a PO line can only fulfill the same part) — that is
|
|
61
|
+
the safe cleanup predicate for remediating historical rows.
|
|
62
|
+
- **Downstream tracking-number misattribution (NOT yet fixed as of 2026-06-11).** Because
|
|
63
|
+
tracking propagation followed the (scrambled) SO↔PO linkage, tracking numbers landed on the
|
|
64
|
+
wrong IF granularity for affected SA orders. Tracking for Compass lives at
|
|
65
|
+
`ItemFulfillmentItemUnits_TrackingNumbers` and `ItemFulfillments_TrackingNumbers` (header),
|
|
66
|
+
NOT `ItemFulfillmentItems_TrackingNumbers`. Source of truth for "which tracking shipped which
|
|
67
|
+
part" is the ASN side: `AdvanceShippingNoticeItemUnits_TrackingNumbers` →
|
|
68
|
+
`AdvanceShippingNoticeItems.purchaseOrderItemId` → PO item → part. A correct remediation
|
|
69
|
+
re-derives every tracking→IF-unit attachment from that ASN truth rather than doing per-line
|
|
70
|
+
swaps (the scramble spans multiple lines, so a single swap just moves a different wrong
|
|
71
|
+
number onto the line). Example seen on SA132739: UPS `1Z8696XA0193326215` actually shipped
|
|
72
|
+
`C40QYUC-1` (SO line 4) but was attached to SO line 1 (`1000555`).
|
|
73
|
+
|
|
74
|
+
## Change history
|
|
75
|
+
- 2026-06-11 — Guarded `postPost` SO↔PO item linking to MR orders only; SA links come solely
|
|
76
|
+
from `prePost`'s `createdFromSalesOrderItem` remap. Fixes spurious cross-part links. (jcardinal)
|
|
77
|
+
|
|
78
|
+
## Related docs
|
|
79
|
+
- [Compass ASN → ItemFulfillment Auto-Creation](asn-to-item-fulfillment.md)
|
package/package.json
CHANGED