toga-ai 1.0.199 → 1.0.200

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.
@@ -15,7 +15,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
15
15
 
16
16
  ## 2.0 framework
17
17
 
18
- - **_underscore** (_Underscore) _(framework core)_ — 14 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
18
+ - **_underscore** (_Underscore) _(framework core)_ — 15 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
19
19
  - **worker2** (Worker) — 15 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
20
20
  - **api2** (API) — 6 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
21
21
  - **dbchanges2** (Database Changes) _(framework core)_ — 2 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
@@ -3,6 +3,7 @@
3
3
  | Doc | Framework | Summary | Files |
4
4
  |-----|-----------|---------|-------|
5
5
  | [Rate Monthly Reconciliation Report](features/monthly-reconciliation-report.md) | 1.0 | A monthly cron that emails an Excel reconciliation report covering all Rate subscription sales orders and their linked PayPal payments for the prior calendar mo | worker/crons/notifications/reports/rate/send_monthly_rate_purchases_report.php, worker/schedules/cron.worker.notification.json |
6
+ | [Rate SalesOrder → NetSuite CashSale Export (postPost)](features/netsuite-cashsale-export.md) | 2.0 | Rate sells home-warranty / home-tech-support products. | _underscore/Model/Rate/SalesOrder.php, _underscore/Model/Rate/Item.php |
6
7
  | [Rate SAML SSO](features/saml-sso.md) | 2.0 | Rate uses Azure AD as its IdP (`login.rate.com`). | _underscore/Model/Rate/ClientAuthentication.php, saml/Controller/Index.php, toga2-view/src/hooks/useAuthenticationFlow.ts |
7
8
  | [Service Card Entitlement Display](features/service-card-entitlements.md) | 2.0 | Rate's home and services pages display one service card per purchased entitlement. | src/components/ServiceCard/ServiceCard.tsx, src/components/ServiceCard/index.ts, src/hooks/useBundleServices.ts, src/pages/Home/api/homeApi.ts, src/pages/Home/view/HomePage.tsx, src/pages/Home/viewModels/useHomePageViewModel.ts, src/pages/Services/view/ServicesPage.tsx, src/pages/Services/viewModels/useServicePageViewModel.ts |
8
9
  | [Rate](profile.md) | 2.0 | Rate is a mortgage/lending client. | |
@@ -0,0 +1,92 @@
1
+ ---
2
+ title: "Rate SalesOrder → NetSuite CashSale Export (postPost)"
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: rate
7
+ type: client-feature
8
+ status: active
9
+ updated: 2026-06-25
10
+ owners: ["rgirish"]
11
+ files:
12
+ - _underscore/Model/Rate/SalesOrder.php
13
+ - _underscore/Model/Rate/Item.php
14
+ related:
15
+ - 2.0/apps/_underscore/features/netsuite-rest-client.md
16
+ - clients/rate/profile.md
17
+ ---
18
+
19
+ ## Summary
20
+
21
+ Rate sells home-warranty / home-tech-support products. When a Rate SalesOrder is created,
22
+ the `_Model_Rate_SalesOrder::postPost` interceptor builds and writes a NetSuite **CashSale**
23
+ (not a SalesOrder). This doc covers two pieces of that export added 2026-06-25: passing the
24
+ order's ship-to (property) address onto the CashSale, and resolving each line item's NetSuite
25
+ item internalId from a dedicated column with a partNumber fallback.
26
+
27
+ This is Rate's override of the shared NetSuite write path documented in
28
+ `2.0/apps/_underscore/features/netsuite-rest-client.md`.
29
+
30
+ ## Key files / entry points
31
+
32
+ | File | Role |
33
+ |---|---|
34
+ | `_underscore/Model/Rate/SalesOrder.php` | `postPost` interceptor — builds the NetSuite CashSale (address + line items) |
35
+ | `_underscore/Model/Rate/Item.php` | `_Model_Rate_Item` — declares `c_netsuiteInternalItemId` so the column is API-exposed and UI-settable |
36
+
37
+ ## How it works
38
+
39
+ ### Ship-to address → CashSale `shippingAddress`
40
+ The `postPost` SQL query was expanded to `LEFT JOIN Addresses` (via
41
+ `SalesOrders.shipToAddressId`) and `States`, selecting `line1`, `line2`, `city`, the
42
+ state code, and `zip`. The address is captured from the first result row and set as a
43
+ top-level `shippingAddress` on the CashSale — an `Address` object with `override=true`
44
+ and `country='_unitedStates'`.
45
+
46
+ This fires for **every** order that has a `shipToAddressId` set — it is **not** restricted
47
+ to the Whole Home Warranty SKU (1429124), because `shippingAddress` is a top-level field on
48
+ the CashSale, not a per-line concern. (The business driver was Whole Home Warranty orders
49
+ needing the property address in NetSuite so ops / account teams can determine regional
50
+ pricing, but the field applies to all orders.)
51
+
52
+ ### Line item NetSuite internalId resolution
53
+ Each line item's NetSuite `RecordRef` internalId is now resolved as:
54
+
55
+ 1. `Items.c_netsuiteInternalItemId` when populated, else
56
+ 2. the hard-coded `partNumber` integer (1429122 / 1429123 / 1429124) as a fallback.
57
+
58
+ The query was updated to `SELECT Items.c_netsuiteInternalItemId` alongside `partNumber`.
59
+ The fallback exists because ops has not yet populated `c_netsuiteInternalItemId`.
60
+
61
+ ### `c_netsuiteInternalItemId` field declaration
62
+ `Client_Rate.Items` has a `c_netsuiteInternalItemId INT` column that was not declared in the
63
+ ORM. It is now declared as `FIELD_INTEGER` on `_Model_Rate_Item`, so the column is exposed
64
+ through the API and can be set via the UI.
65
+
66
+ ## Production data state (as of 2026-06-25)
67
+
68
+ - **All 39 Rate SalesOrders in `Client_Rate.SalesOrders` have `shipToAddressId = NULL`.**
69
+ The new code path only populates `shippingAddress` once the frontend starts setting
70
+ `shipToAddressId` on order creation. For the historical backfill export, the address was
71
+ pulled from the contact's `primaryContactAddressId → ContactAddresses → Addresses` join
72
+ instead — a one-off, not the going-forward path.
73
+ - **`Items.c_netsuiteInternalItemId` is NULL for all three Rate SKUs** (partNumbers
74
+ 1429122, 1429123, 1429124). Until ops populates it, the partNumber-integer fallback is the
75
+ active internalId path.
76
+
77
+ ## Gotchas / known issues
78
+
79
+ - **`shippingAddress` only flows when `shipToAddressId` is set.** No live order has it set
80
+ yet (all 39 are NULL), so the new address path is effectively dormant until the frontend
81
+ populates the field on creation. Don't assume the CashSale carries an address from current
82
+ prod data.
83
+ - **internalId fallback is partNumber, not the NS internalId.** Until ops backfills
84
+ `c_netsuiteInternalItemId`, CashSale lines reference the partNumber integer as the NS item
85
+ internalId. These happen to coincide for Rate today, but the clean path is the column.
86
+ - **Historical backfill used a different address source** (contact primary address), not
87
+ `shipToAddressId` — do not confuse the one-off backfill join with the going-forward order
88
+ path.
89
+
90
+ ## Change history
91
+
92
+ - 2026-06-25 — Added ship-to address (`LEFT JOIN Addresses`/`States`) to the CashSale as a top-level `shippingAddress` (override=true, US); resolved line-item NS internalId from `c_netsuiteInternalItemId` with partNumber fallback; declared `c_netsuiteInternalItemId` on `_Model_Rate_Item`. Confirmed all 39 prod orders have NULL `shipToAddressId` and all 3 SKUs have NULL `c_netsuiteInternalItemId` (rgirish)
@@ -10,12 +10,13 @@ project: SAML SSO Gateway
10
10
  client: rate
11
11
  type: profile
12
12
  status: active
13
- updated: 2026-06-24
13
+ updated: 2026-06-25
14
14
  owners: ["rgirish", "bala"]
15
15
  files: []
16
16
  related:
17
17
  - clients/rate/features/saml-sso.md
18
18
  - clients/rate/features/monthly-reconciliation-report.md
19
+ - clients/rate/features/netsuite-cashsale-export.md
19
20
  ---
20
21
 
21
22
  ## Summary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.199",
3
+ "version": "1.0.200",
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",