toga-ai 1.0.615 → 1.0.616
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/toga2-commerce/INDEX.md +2 -0
- package/knowledge/2.0/apps/toga2-commerce/features/cart-order-total-computation.md +57 -0
- package/knowledge/2.0/apps/toga2-commerce/features/expedited-shipping-gating.md +6 -2
- package/knowledge/2.0/apps/toga2-commerce/features/shipping-cost-waiver-gating.md +78 -0
- package/knowledge/INDEX.md +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
| [TOGa Commerce (toga2-commerce / commerce2-react) Architecture](architecture.md) | `toga2-commerce` (npm package name **`commerce2-react`**, product name **TOGa Commerce**) is the customer-facing **B2B commerce storefront** of the 2.0 platform | src/main.tsx, src/App.tsx, src/routes.tsx, src/contexts/AuthContext.tsx, src/contexts/helpers/getLoginSettings.ts, src/api/axiosInstance.ts, src/stores/, src/themeConfig/ThemeContext.tsx, src/fieldsConfig/index.ts, src/hooks/useAssignClientFields.ts, vite.config.ts, package.json |
|
|
6
6
|
| [Cart Bundle Submission & the bundleUuid Identity Contract](features/cart-bundle-submission-and-identity.md) | How cart **bundles** (kits) are turned into `SalesOrderItems` when a cart is submitted or an existing order is edited, and the **identity-field contract** every | src/api/syncSalesOrderItemsFromLocalStorageCartToApi.ts, src/utils/formatSalesOrderBundlesFromApi.ts, src/stores/useCartStoreZu.ts, src/pages/OrderDetails/helpers/formatSalesOrderDataFromLocalStorage.ts, src/pages/OrderDetails/view/components/OrderItems.tsx |
|
|
7
7
|
| [Cart Notification Emails — duplicate prevention](features/cart-notification-emails.md) | On the cart "Notifications" section a user can add CC email addresses to an order. | src/pages/Cart/CartPage.tsx, src/pages/Cart/view/cartForm/CartForm.tsx, src/stores/useEmailOptionsStore.ts, src/stores/useCartSalesQuoteZu.ts, src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts |
|
|
8
|
+
| [Cart Order-Total & Shipping Computation](features/cart-order-total-computation.md) | The Cart summary section (subtotal / shipping / tax / total) is **data-driven** from `cartData`. | toga2-commerce/src/pages/Cart/viewModel/useCartViewModel.ts, toga2-commerce/src/pages/Cart/CartPage.tsx, toga2-commerce/src/pages/Cart/view/cartForm/CartForm.tsx, toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts, toga2-commerce/src/pages/Cart/api/CartApi.ts |
|
|
8
9
|
| [Cart Page — config-driven form architecture (current state + planned refactor)](features/cart-page-config-architecture.md) | The Cart page (`src/pages/Cart/`) is the most config-heavy page in `toga2-commerce`. | src/pages/Cart/CartPage.tsx, src/pages/Cart/view/cartForm/CartForm.tsx, src/pages/Cart/view/cartForm/CartFormSection.tsx, src/pages/Cart/view/cartForm/CartFormRenderer.tsx, src/pages/Cart/view/EditCart.tsx, src/pages/Cart/view/EditOrder.tsx, src/pages/Cart/viewModel/useEditOrderOrEditCartViewModel.ts, src/pages/Cart/viewModel/FIELDS/*/*/*/CARTPAGE.ts, src/hooks/useAssignClientFields.ts |
|
|
9
10
|
| [Catalog cache freshness — the 24h persisted query cache, and how to opt a query out of it](features/catalog-cache-freshness.md) | TOGa Commerce runs a **single `QueryClient` with a 24-hour default `staleTime`**, and persists it to **`localStorage["commerce"]`** through `PersistQueryClientP | toga2-commerce/src/App.tsx, toga2-commerce/src/contexts/AuthContext.tsx, toga2-commerce/src/pages/ItemsView/viewModel/useItemDetailsViewModel.ts |
|
|
10
11
|
| [Category Tile Order (AssortmentItems.sortOrder) — merchandising a storefront category](features/category-tile-sort-order.md) | **"Move item X to the front of category Y" is a DATA change, not a code change.** The order of item tiles on a storefront category page is driven by exactly one | src/pages/Filter/api/FilterApi.ts, src/pages/Filter/viewModel/useFilterViewModel.ts, api2/Component/Api/V2/V2.php, toga2-supply/src/pages/Items/api/itemsApi.ts |
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
| [Inactive-item purchase gating (standalone lines only — kits are exempt by design)](features/inactive-item-purchase-gating.md) | An item with **`Items.isActive = 0`** must not be viewable, addable to a cart, or orderable **as a standalone line** on the storefront — but the **same flag is | toga2-commerce/src/utils/checkIsItemPurchasable.ts, toga2-commerce/src/api/fetchItemsActiveStatus.ts, toga2-commerce/src/hooks/useCartReconciliation.ts, toga2-commerce/src/stores/useCartStoreZu.ts, toga2-commerce/src/pages/ItemsView/api/ItemsApi.ts, toga2-commerce/src/pages/ItemsView/viewModel/useItemDetailsViewModel.ts, toga2-commerce/src/pages/ItemsView/ItemViewPage.tsx, toga2-commerce/src/components/AuthLayout/AuthLayout.tsx, toga2-commerce/src/pages/Cart/CartPage.tsx, toga2-commerce/src/pages/Cart/view/cartTable/CartTableBundleItem.tsx, toga2-commerce/src/api/syncSalesOrderFromApiToLocalStorage.ts, _underscore/Model/Compass/SalesOrder.php, dbchanges2/Client_Compass/2026-08-14a - AddSalesOrderInactiveStandaloneItemPreInterceptors.sql, dbchanges2/Client_CompassCanada/2026-08-14a - AddSalesOrderInactiveStandaloneItemPreInterceptors.sql |
|
|
15
16
|
| [Multi-Tenant Resolution & Theming](features/multi-tenant-theming.md) | `toga2-commerce` serves multiple clients from one codebase. | src/themeConfig/themes.json, src/themeConfig/ThemeContext.tsx, src/themeConfig/types.ts, src/components/ThemeSwitcher/ThemeSwitcher.tsx, src/components/AuthLayout/AuthLayout.tsx, src/api/axiosInstance.ts, src/contexts/AuthContext.tsx, tailwind.config.js |
|
|
16
17
|
| [Order-submit sync sequencing (useSubmitOrder) — why these calls must not run in parallel](features/order-submit-sync-sequencing.md) | Submitting an order from the cart fires **two independent sync routines** — one for the sales-order header (`syncSalesOrderData`) and one for the line items (`s | toga2-commerce/src/pages/OrderDetails/hooks/useSubmitOrder.ts, toga2-commerce/src/api/syncSalesOrdersDataFromLocalStorageCartToApi.ts, toga2-commerce/src/api/syncSalesOrderItemsFromLocalStorageCartToApi.ts |
|
|
18
|
+
| [Config-Driven Shipping Cost Waiver (Standard Ground free for computer kits)](features/shipping-cost-waiver-gating.md) | On the toga2-commerce **Cart** page, a shipping option's **cost** can be waived by config using the same `PrimaryItemShippingRule` vocabulary that drives expedi | toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts, toga2-commerce/src/pages/Cart/viewModel/FIELDS/shared/shippingOptionGates.ts, toga2-commerce/src/pages/Cart/CartPage.tsx |
|
|
17
19
|
| [AWS Amplify Build & Deploy (non-prod environments)](workflows/amplify-build-and-deploy.md) | How `toga2-commerce` (React + Vite, "commerce2-react") builds and deploys on **AWS Amplify**. | toga2-commerce/amplify.yml, toga2-commerce/.gitattributes, toga2-commerce/package.json, toga2-commerce/.github/workflows/sync-stage-environments.yml |
|
|
18
20
|
| [Cart e2e — Cypress conventions & harness (toga2-commerce)](workflows/cypress-testing.md) | The Cypress **e2e** convention set for `toga2-commerce`, and the first **active** e2e coverage for the **Cart** page (`cartV2.cy.ts`, slice 1 — 12 tests, verifi | toga2-commerce/cypress/e2e/cartPage/cartV2.cy.ts, toga2-commerce/cypress/fixtures/cart/fetchSingleUserAdmin.json, toga2-commerce/cypress/fixtures/cart/fetchLocations.json, toga2-commerce/cypress/fixtures/cart/fetchUserShippingMethods.json, toga2-commerce/cypress/support/commands.ts, toga2-commerce/cypress/support/e2e.ts, toga2-commerce/src/pages/Cart/CartPage.tsx, toga2-commerce/src/pages/Cart/view/cartForm/CartForm.tsx, toga2-commerce/src/pages/Cart/view/cartForm/CartFormSection.tsx, toga2-commerce/src/pages/Cart/view/cartTable/CartContentsTable.tsx, toga2-commerce/src/pages/Cart/view/cartTable/CartTableItem.tsx, toga2-commerce/src/components/Inputs/AdvancedInput.tsx, toga2-commerce/src/components/BaseButton/BaseButton.tsx |
|
|
19
21
|
| [Diagnosing ERR_HTTP2_PROTOCOL_ERROR (one client fails, everyone else is fine)](workflows/http2-protocol-error-diagnosis.md) | When a Chromium browser (Chrome / Edge) shows **`ERR_HTTP2_PROTOCOL_ERROR`** loading a `*.togacommerce.com` tenant for **one client/network but works for the TO | |
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cart Order-Total & Shipping Computation
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: toga2-commerce
|
|
5
|
+
project: TOGa Commerce
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-19
|
|
10
|
+
owners: [apeterson]
|
|
11
|
+
files:
|
|
12
|
+
- toga2-commerce/src/pages/Cart/viewModel/useCartViewModel.ts
|
|
13
|
+
- toga2-commerce/src/pages/Cart/CartPage.tsx
|
|
14
|
+
- toga2-commerce/src/pages/Cart/view/cartForm/CartForm.tsx
|
|
15
|
+
- toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts
|
|
16
|
+
- toga2-commerce/src/pages/Cart/api/CartApi.ts
|
|
17
|
+
related:
|
|
18
|
+
- 2.0/apps/toga2-commerce/features/shipping-cost-waiver-gating.md
|
|
19
|
+
- 2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
|
|
20
|
+
- 2.0/apps/toga2-commerce/features/cart-page-config-architecture.md
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
The Cart summary section (subtotal / shipping / tax / total) is **data-driven** from
|
|
25
|
+
`cartData`. `cartData.total` is computed in `useCartViewModel` as `subtotal + tax + shipping`,
|
|
26
|
+
where `shipping` is read from `salesOrder.shipping` in the zustand cart/sales-quote store —
|
|
27
|
+
**not** directly from the selected dropdown option. A `CartPage` effect is the bridge: it
|
|
28
|
+
watches the selected shipping method, looks up the matching fetched option, reads its `c_cost`,
|
|
29
|
+
applies waiver cost-gates, and calls `setShipping()` to write `salesOrder.shipping`.
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
1. `CartForm.tsx` renders the summary purely from `cartData` (subtotal/shipping/tax/total).
|
|
33
|
+
2. `useCartViewModel.ts` computes `cartData.total = subtotal + tax + shipping`, with `shipping`
|
|
34
|
+
derived from `salesOrder.shipping` (zustand store).
|
|
35
|
+
3. `CartPage.tsx` has an effect watching the selected `shippingMethod`: it finds the matching
|
|
36
|
+
fetched option, reads `c_cost`, applies waiver cost-gates (see
|
|
37
|
+
[shipping-cost-waiver-gating](shipping-cost-waiver-gating.md)), then `setShipping()` writes
|
|
38
|
+
`salesOrder.shipping`. So the dropdown never feeds the total directly — it flows through the
|
|
39
|
+
store.
|
|
40
|
+
|
|
41
|
+
## Gotchas
|
|
42
|
+
- **`c_cost` is ACL-gated per tenant, and a missing grant silently zeroes shipping.** Only the
|
|
43
|
+
**Compass USA** CARTPAGE configs request fields `["uuid","name","c_cost"]` in
|
|
44
|
+
`fetchShippingMethod`. **Compass Canada** and **Quad** request only `["uuid","name"]`, so
|
|
45
|
+
their fetched options carry no `c_cost`; `Number(undefined) → NaN → "0"`, and shipping falls
|
|
46
|
+
back to `"0"` with no error. This is a **latent gap** for those tenants — if they are meant to
|
|
47
|
+
charge shipping, their CARTPAGE `fetchShippingMethod` field list must include `c_cost`.
|
|
48
|
+
- **Shipping lives in the store, not the dropdown.** Reading the selected option's cost alone
|
|
49
|
+
will not tell you the order total — always trace through `setShipping()` →
|
|
50
|
+
`salesOrder.shipping` → `useCartViewModel`.
|
|
51
|
+
|
|
52
|
+
## Change history
|
|
53
|
+
- 2026-08-19 — Documented the previously-undocumented cart total/shipping computation path
|
|
54
|
+
while fixing the Compass USA Standard Ground waiver. Recorded the `c_cost` ACL-gating latent
|
|
55
|
+
gap for Compass Canada and Quad (their fetched options have no `c_cost`, so shipping silently
|
|
56
|
+
resolves to "0"). (apeterson)
|
|
57
|
+
</content>
|
|
@@ -6,8 +6,8 @@ project: TOGa Commerce
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: [tcox]
|
|
9
|
+
updated: 2026-08-19
|
|
10
|
+
owners: [tcox, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts
|
|
13
13
|
- toga2-commerce/src/pages/Cart/viewModel/FIELDS/shared/shippingOptionGates.ts
|
|
@@ -103,6 +103,10 @@ behavior is expressed in config, not in code branches.
|
|
|
103
103
|
on that doc's slice-2 work-list.
|
|
104
104
|
|
|
105
105
|
## Change history
|
|
106
|
+
- 2026-08-19 — No change to expedited visibility. Noted that the shared shipping-rule type
|
|
107
|
+
gained an optional `requireNoOtherItemsInKit` flag (+ `bundleHasOtherItems()` helper) used by
|
|
108
|
+
the separate Standard Ground cost waiver — see
|
|
109
|
+
[shipping-cost-waiver-gating](shipping-cost-waiver-gating.md). (apeterson)
|
|
106
110
|
- 2026-07-27 — No behavior change. Noted that a cart Cypress e2e harness now exists and a
|
|
107
111
|
gating + guardrail-modal spec is feasible (the `cart/fetchUserShippingMethods.json` fixture
|
|
108
112
|
already ships the gated names with no `c_cost`); it is on the slice-2 work-list. Linked
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Config-Driven Shipping Cost Waiver (Standard Ground free for computer kits)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: toga2-commerce
|
|
5
|
+
project: TOGa Commerce
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-19
|
|
10
|
+
owners: [apeterson]
|
|
11
|
+
files:
|
|
12
|
+
- toga2-commerce/src/pages/Cart/helpers/shippingOptionGates.ts
|
|
13
|
+
- toga2-commerce/src/pages/Cart/viewModel/FIELDS/shared/shippingOptionGates.ts
|
|
14
|
+
- toga2-commerce/src/pages/Cart/CartPage.tsx
|
|
15
|
+
related:
|
|
16
|
+
- 2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
|
|
17
|
+
- 2.0/apps/toga2-commerce/features/cart-order-total-computation.md
|
|
18
|
+
- ../../../../clients/compass-usa/profile.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
On the toga2-commerce **Cart** page, a shipping option's **cost** can be waived by config
|
|
23
|
+
using the same `PrimaryItemShippingRule` vocabulary that drives expedited-option visibility.
|
|
24
|
+
The **Compass USA** carts attach a cost gate `STANDARD_GROUND_FREE_FOR_COMPUTER_KITS` to the
|
|
25
|
+
*Shipping Method* field so that **Standard Ground** ships free for a bare computer kit. The
|
|
26
|
+
waiver is config-driven (no `if (clientSlug === ...)` branching) and is referenced only by the
|
|
27
|
+
four Compass USA role configs (USER/ADMIN/MANAGER/SUPERUSER).
|
|
28
|
+
|
|
29
|
+
## Key files / entry points
|
|
30
|
+
- `src/pages/Cart/helpers/shippingOptionGates.ts` — `PrimaryItemShippingRule` type,
|
|
31
|
+
`evaluateShippingOptionRule`, and the `bundleHasOtherItems()` helper.
|
|
32
|
+
- `src/pages/Cart/viewModel/FIELDS/shared/shippingOptionGates.ts` — the
|
|
33
|
+
`STANDARD_GROUND_FREE_FOR_COMPUTER_KITS` gate constant (primary item
|
|
34
|
+
`itemCategory.name === "COMPUTERS"`, with `requireNoOtherItemsInKit: true`).
|
|
35
|
+
- `src/pages/Cart/CartPage.tsx` — the effect that reads the selected option's `c_cost` and
|
|
36
|
+
applies waiver cost-gates before calling `setShipping()` (see
|
|
37
|
+
[cart-order-total-computation](cart-order-total-computation.md)).
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
1. A cost gate matches a bundle when its **primary item** (`bundleItemGroup.slug === "primary"`)
|
|
41
|
+
satisfies the `{ item, path, operator, value }` rule — here
|
|
42
|
+
`item.itemCategory.name === "COMPUTERS"`.
|
|
43
|
+
2. The **optional `requireNoOtherItemsInKit` flag** on `PrimaryItemShippingRule` narrows the
|
|
44
|
+
match: when set, the bundle qualifies only if the primary item matches **and** the kit has
|
|
45
|
+
no other items. `bundleHasOtherItems()` returns true when `bundleProgressContents` contains
|
|
46
|
+
any entry whose `bundleItemGroup.slug !== "primary"` (fees are already excluded from
|
|
47
|
+
`bundleProgressContents` upstream).
|
|
48
|
+
3. `evaluateShippingOptionRule` qualifies a bundle only when the primary item matches AND, if
|
|
49
|
+
`requireNoOtherItemsInKit` is set, the kit is bare. Existing cart-wide "any qualifying
|
|
50
|
+
bundle" semantics for multi-bundle carts are preserved.
|
|
51
|
+
4. When the selected method qualifies, the effect in `CartPage` waives its `c_cost` to 0 before
|
|
52
|
+
writing `salesOrder.shipping`.
|
|
53
|
+
|
|
54
|
+
Resulting Compass USA behavior: bare computer kit (primary computer only) → Standard Ground
|
|
55
|
+
free; computer kit **with** other items → charged $10; all non-computer kits → charged;
|
|
56
|
+
expedited methods unchanged (still priced).
|
|
57
|
+
|
|
58
|
+
## Gotchas
|
|
59
|
+
- **The waiver only means what the flag says.** Before this fix the gate had no
|
|
60
|
+
`requireNoOtherItemsInKit`, so Standard Ground (the default selection) was waived for **any**
|
|
61
|
+
cart whose primary bundle item was in `COMPUTERS` — computer kits loaded at $0 shipping and
|
|
62
|
+
stayed there regardless of what else was in the kit. Always set `requireNoOtherItemsInKit`
|
|
63
|
+
when a waiver is meant only for a bare kit.
|
|
64
|
+
- **`bundleProgressContents` is the source of truth for "other items"** — it already excludes
|
|
65
|
+
fees, so a fee line does not make a kit count as "having other items." If that upstream
|
|
66
|
+
exclusion ever changes, the waiver's narrowing changes with it.
|
|
67
|
+
- **Waiver correctness depends on `COMPUTERS` categorization**, same as the expedited gate —
|
|
68
|
+
a computer kit mis-categorized in the catalog will neither waive nor gate.
|
|
69
|
+
|
|
70
|
+
## Change history
|
|
71
|
+
- 2026-08-19 — Fixed an over-broad Standard Ground waiver for Compass USA computer-kit carts:
|
|
72
|
+
added the optional `requireNoOtherItemsInKit` flag on `PrimaryItemShippingRule` and the
|
|
73
|
+
`bundleHasOtherItems()` helper, and set the flag on
|
|
74
|
+
`STANDARD_GROUND_FREE_FOR_COMPUTER_KITS`. Bare computer kits now ship free; kits with other
|
|
75
|
+
items are charged. Config-driven, Compass USA only, no client branching. No test harness in
|
|
76
|
+
the repo (no vitest/jest); verified by review. (apeterson)
|
|
77
|
+
</content>
|
|
78
|
+
</invoke>
|
package/knowledge/INDEX.md
CHANGED
|
@@ -29,7 +29,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
29
29
|
- **talos** (TOGa IQ) — 7 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
|
|
30
30
|
- **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
|
|
31
31
|
- **ai-bdr** (AI-BDR) — 9 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
|
|
32
|
-
- **toga2-commerce** (TOGa Commerce) —
|
|
32
|
+
- **toga2-commerce** (TOGa Commerce) — 19 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
|
|
33
33
|
- **toga25-supply** (TOGa 2.5 Supply) — 11 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
|
|
34
34
|
- **toga-blox** (TOGa Blox) — 9 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
|
|
35
35
|
- **bdr** (BDR) — 0 doc(s) → [2.0/apps/bdr/INDEX.md](2.0/apps/bdr/INDEX.md)
|
package/package.json
CHANGED