toga-ai 1.0.355 → 1.0.356

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.
@@ -17,7 +17,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
17
17
 
18
18
  ## 2.0 framework
19
19
 
20
- - **_underscore** (_Underscore) _(framework core)_ — 32 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
20
+ - **_underscore** (_Underscore) _(framework core)_ — 33 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
21
21
  - **worker2** (Worker) — 30 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
22
22
  - **api2** (API) — 11 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
23
23
  - **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
@@ -14,11 +14,12 @@ project: _Underscore
14
14
  client: compass-canada
15
15
  type: profile
16
16
  status: active
17
- updated: 2026-06-30
17
+ updated: 2026-07-16
18
18
  owners: [jcardinal, bala, tcox, apeterson]
19
19
  files: []
20
20
  related:
21
21
  - ../compass-usa/profile.md
22
+ - ../compass-usa/features/approval-decision-flow.md
22
23
  - ../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
23
24
  - ../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
24
25
  - ../../2.0/apps/_underscore/features/surface-resolver.md
@@ -59,6 +60,12 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
59
60
  Compass USA's 1/3/4. See [Surface Resolver](../../2.0/apps/_underscore/features/surface-resolver.md).
60
61
  - Customer language preference: `UserGlobalSettings.settingId = 2` (`en` / `fr-CA`); customer-
61
62
  facing emails are sent in EN or FR accordingly.
63
+ - **Approval decisions use the shared Compass parent.** `_Model_Compass_Canada_ApprovalDecision`
64
+ is an empty subclass of `_Model_Compass_ApprovalDecision`; the entire approval/notification/
65
+ manager-reassignment/VIP-auto-approve flow lives in the parent and branches at runtime on
66
+ `clientIdentifier === 'Compass_Canada'` (email-template UUID + EN/FR localization). Fixes to the
67
+ parent cover Canada automatically — no per-tenant change. See
68
+ [Approval-Decision Flow](../compass-usa/features/approval-decision-flow.md).
62
69
  - Assortment (product-grouping) names are served in fr-CA via the `AssortmentTranslations` sidecar
63
70
  (16 rows seeded). French was extracted from the old bilingual `"English/French"` `Assortments.name`
64
71
  values, which were then cleaned to English-only. See
@@ -2,6 +2,7 @@
2
2
 
3
3
  | Doc | Framework | Summary | Files |
4
4
  |-----|-----------|---------|-------|
5
+ | [Compass Approval-Decision Flow (Notifications & Manager Reassignment)](features/approval-decision-flow.md) | 2.0 | Compass's sales-order approval flow — approval/notification email lists, **manager reassignment**, VIP auto-approve, and EN/FR localization — lives **entirely i | _underscore/Model/Compass/ApprovalDecision.php, _underscore/Model/Compass/Usa/ApprovalDecision.php, _underscore/Model/Compass/Canada/ApprovalDecision.php |
5
6
  | [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, _underscore/Model/Compass/PurchaseOrder.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql, dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql, dbchanges2/Client_Compass/2026-06-18a - CleanupSA132898DuplicateTracking.sql, dbchanges2/Client_Compass/2026-06-18b - CleanupSA132881DuplicateTracking.sql, dbchanges2/Client_Compass/2026-07-02a - FixSA133377TrackingSerialAndDuplicateIF.sql |
6
7
  | [Cost Centers — Unit Locations, numeric-only policy](features/cost-centers.md) | 2.0 | A Compass "cost center" — the value a user picks in commerce and that lands on an order — is **not** a `CostCenters` row. | toga2-commerce/src/pages/Cart/api/CartApi.ts, worker1.5/crons/toga2/compass/import_locations.php, _underscore/Model/Compass/SalesOrder.php, api2/Component/Api/V2/V2.php, dbchanges2/Client_Compass/2026-07-06 - RemoveNonNumericCostCenters.sql |
7
8
  | [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, dbchanges2/Client_Compass/2026-06-15a - FixItemFulfillmentTrackingNumberJoins.sql, dbchanges2/Client/2026-07-15a - ExcludeFeeItemsFromItemFulfillmentsForSalesOrdersView.sql |
@@ -0,0 +1,100 @@
1
+ ---
2
+ title: Compass Approval-Decision Flow (Notifications & Manager Reassignment)
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: compass-usa
7
+ type: client-feature
8
+ status: active
9
+ updated: 2026-07-16
10
+ owners: ["apeterson"]
11
+ files:
12
+ - _underscore/Model/Compass/ApprovalDecision.php
13
+ - _underscore/Model/Compass/Usa/ApprovalDecision.php
14
+ - _underscore/Model/Compass/Canada/ApprovalDecision.php
15
+ related:
16
+ - mr-ma-order-approval-and-status.md
17
+ - ../../compass-canada/profile.md
18
+ - ../../../2.0/apps/_underscore/features/email-template-sending.md
19
+ ---
20
+
21
+ ## Summary
22
+ Compass's sales-order approval flow — approval/notification email lists, **manager reassignment**,
23
+ VIP auto-approve, and EN/FR localization — lives **entirely in the shared parent
24
+ `_Model_Compass_ApprovalDecision`**. Both tenant subclasses,
25
+ `_Model_Compass_Usa_ApprovalDecision` and `_Model_Compass_Canada_ApprovalDecision`, are **empty**
26
+ (`extends _Model_Compass_ApprovalDecision {}`, no overrides). Client- and language-specific
27
+ behavior is **not** subclassed; it branches at runtime inside the parent on
28
+ `$api->client->clientIdentifier` (`Compass_Usa` vs `Compass_Canada`). Practical consequence: a fix
29
+ to a parent method applies to **both** Compass US and Compass Canada automatically — there is no
30
+ per-client code change to make.
31
+
32
+ This doc covers the **approval-decision / notification** half of Compass approvals. The separate
33
+ auto-approval + `_status` gating on the order itself is in
34
+ [Compass MR/MA Order Auto-Approval & Status Gate](mr-ma-order-approval-and-status.md).
35
+
36
+ ## Key files / entry points
37
+ - **`_underscore/Model/Compass/ApprovalDecision.php`** — the shared parent that owns the whole
38
+ flow (notification-list maintenance, `_swapManagerEmailAddress()`, VIP auto-approve, email-template
39
+ UUID resolution, localization).
40
+ - **`_underscore/Model/Compass/Usa/ApprovalDecision.php`** — empty subclass, no overrides.
41
+ - **`_underscore/Model/Compass/Canada/ApprovalDecision.php`** — empty subclass, no overrides.
42
+
43
+ ## How it works
44
+ ### One shared parent, runtime client branch (not subclass overrides)
45
+ Compass US and Compass Canada resolve to different model classes at request time
46
+ (`_Model_Compass_Usa_ApprovalDecision` / `_Model_Compass_Canada_ApprovalDecision`), but both are
47
+ empty shells extending `_Model_Compass_ApprovalDecision`. All behavior is inherited. Where the two
48
+ tenants differ, the **parent** branches on `$api->client->clientIdentifier === 'Compass_Canada'`:
49
+ - **Email-template resolution** — `resolveEmailTemplateUuid()` picks the tenant's template UUID.
50
+ - **EN/FR localization** — user language is read from `UserGlobalSettings` (`settingId = 2`;
51
+ `en` / `fr-CA`) so Canadian notifications go out in the recipient's language.
52
+
53
+ Because the divergence is a runtime branch and not an override, do **not** add per-client logic to
54
+ the empty subclasses — extend the shared parent and branch there if a genuine tenant difference is
55
+ needed.
56
+
57
+ ### Manager reassignment and the notification list
58
+ When a step-2 (Manager) approval decision is **reassigned** to a new manager,
59
+ `_swapManagerEmailAddress()` updates the order's CC/notification list in `SalesOrderEmailAddresses`:
60
+ it removes the outgoing manager's email and adds the incoming manager's. The one email that must
61
+ **never** be dropped is the **order requester's** — the person the order is for, resolved via
62
+ `SalesOrders.contactId → Users` (the requester's email is looked up with a parameterized
63
+ `SELECT Users.email FROM SalesOrders INNER JOIN Users ON Users.contactId = SalesOrders.contactId
64
+ WHERE SalesOrders.id = ?`). Before deleting the old-manager email, the method compares it against
65
+ both the new-manager email and the requester email and **skips the delete when it matches the
66
+ requester**. All of these comparisons are case-insensitive (`strcasecmp()`), matching
67
+ `getFilteredCcEmails()`.
68
+
69
+ ## Gotchas / known issues
70
+ - **Never drop the order requester from notifications on manager reassignment.** If the outgoing
71
+ manager happens to also be the order requester (same email), deleting the old-manager address
72
+ from `SalesOrderEmailAddresses` would silently remove the requester from all order notifications.
73
+ `_swapManagerEmailAddress()` guards against this by comparing the old-manager email to the
74
+ requester's email (looked up via `SalesOrders.contactId → Users`) and skipping the delete when
75
+ they match. This was a live bug (fixed 2026-07-16).
76
+ - **Email comparisons must be case-insensitive.** Use `strcasecmp()`, not `!==` — the notification
77
+ list can hold the same address in different casing, and `getFilteredCcEmails()` already compares
78
+ case-insensitively. A strict `!==` comparison here previously let a casing mismatch defeat the
79
+ requester/new-manager guards.
80
+ - **Don't put tenant behavior in the empty subclasses.** `Usa`/`Canada` `ApprovalDecision` are
81
+ intentionally empty; the tenant branch lives in the parent on `clientIdentifier`.
82
+
83
+ ## Change history
84
+ - 2026-07-16 — Fixed `_swapManagerEmailAddress()` dropping the order requester from the order's
85
+ notification list (`SalesOrderEmailAddresses`) when a step-2 manager was reassigned and the
86
+ outgoing manager's email also belonged to the requester: now looks up the requester email via
87
+ `SalesOrders.contactId → Users` and skips the delete when they match; also switched the
88
+ old-vs-new and old-vs-requester comparisons to case-insensitive `strcasecmp()` (was `!==`) to
89
+ match `getFilteredCcEmails()`. Documented that the flow is the shared parent
90
+ `_Model_Compass_ApprovalDecision` (empty `Usa`/`Canada` subclasses, runtime `clientIdentifier`
91
+ branch), so the fix covers Compass Canada automatically. Shipped on branch TRUE-80244 (pushed;
92
+ not yet merged to `_beta`). (apeterson)
93
+
94
+ ## Related docs
95
+ - [Compass MR/MA Order Auto-Approval & Status Gate](mr-ma-order-approval-and-status.md) — the
96
+ auto-approval + `_status` gating half of Compass approvals (on `_Model_Compass_SalesOrder`).
97
+ - [Compass Canada](../../compass-canada/profile.md) — uses this identical flow; the runtime
98
+ `Compass_Canada` branch drives its EN/FR notification localization.
99
+ - [Email Template Sending](../../../2.0/apps/_underscore/features/email-template-sending.md) — the
100
+ shared engine the resolved approval-notification templates are sent through.
@@ -15,12 +15,13 @@ project: _Underscore
15
15
  client: compass-usa
16
16
  type: profile
17
17
  status: active
18
- updated: 2026-07-15
18
+ updated: 2026-07-16
19
19
  owners: [jcardinal, bala, tcox, apeterson]
20
20
  files: []
21
21
  related:
22
22
  - features/asn-to-item-fulfillment.md
23
23
  - features/cost-centers.md
24
+ - features/approval-decision-flow.md
24
25
  - workflows/cross-kit-bundle-corruption.md
25
26
  - ../../2.0/apps/worker2/features/compass-vip-support-importer.md
26
27
  - ../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
@@ -75,6 +76,10 @@ separate, related client (see its own profile).
75
76
  - [VIP Support Importer (worker2)](../../2.0/apps/worker2/features/compass-vip-support-importer.md)
76
77
  — manual (Postman) worker2 action that reads Compass's quarterly VIP spreadsheet and sets
77
78
  `Users.c_supportedByUserId` (assigned support tech) per VIP.
79
+ - [Approval-Decision Flow (Notifications & Manager Reassignment)](features/approval-decision-flow.md) —
80
+ the shared `_Model_Compass_ApprovalDecision` parent (empty `Usa`/`Canada` subclasses; runtime
81
+ `clientIdentifier` branch) that owns approval notifications, manager reassignment, VIP
82
+ auto-approve, and EN/FR localization.
78
83
 
79
84
  ## Notes
80
85
  - **Order status is shipped-only (2026-06-30).** Compass imports all IF stages
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.355",
3
+ "version": "1.0.356",
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",