toga-ai 1.0.101 → 1.0.103

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.
@@ -5,7 +5,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
5
5
  ## 1.0 framework
6
6
 
7
7
  - **library** (Library) _(framework core)_ — 4 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
8
- - **worker** (Worker) — 5 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
8
+ - **worker** (Worker) — 6 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
9
9
  - **togadesk** (TOGa Desk) — 7 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
10
10
  - **togaview** (TOGa View) — 5 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
11
11
  - **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
@@ -14,7 +14,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
14
14
 
15
15
  ## 2.0 framework
16
16
 
17
- - **_underscore** (_Underscore) _(framework core)_ — 6 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
17
+ - **_underscore** (_Underscore) _(framework core)_ — 7 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
18
18
  - **worker2** (Worker) — 6 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
19
19
  - **api2** (API) — 1 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
20
20
  - **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
  | [Prudential: Dell ASN units PRE/POST interceptor (legacy key + flat tracking)](features/dell-asn-units-interceptor.md) | 2.0 | After the tracking-number bridge migration, the ASN unit route was renamed (`advance-shipping-notice-units` → `advance-shipping-notice-item-units`), so the inhe | _underscore/Model/Prudential/AdvanceShippingNotice.php, dbchanges2/Client_Prudential/2026-06-10 - AsnUnitsInterceptor.sql |
6
+ | [Prudential: Service Request Regional Address Validation](features/service-request-address-validation.md) | 2.0 | The `prePost` interceptor on `_Model_Prudential_ServiceRequest` validates `deliverToAddress` fields differently depending on which Prudential regional customer | _underscore/Model/Prudential/ServiceRequest.php |
6
7
  | [Prudential Financial](profile.md) | 2.0 | Prudential is a TOGA client whose device-fulfillment flow is driven by **Dell** via the Dell API (`Client_Prudential.Apis.id = 2`). | |
7
8
  | [Prudential: Dell ASN failed POST backfill replay](workflows/dell-asn-backfill-replay.md) | 2.0 | When Dell ASN POSTs fail in bulk (e.g. | |
@@ -0,0 +1,101 @@
1
+ ---
2
+ title: "Prudential: Service Request Regional Address Validation"
3
+ framework: "2.0"
4
+ repo: _underscore
5
+ project: _Underscore
6
+ client: prudential
7
+ type: client-feature
8
+ status: active
9
+ updated: 2026-06-16
10
+ owners: ["rgirish"]
11
+ files:
12
+ - _underscore/Model/Prudential/ServiceRequest.php
13
+ related:
14
+ - clients/prudential/profile.md
15
+ - clients/prudential/features/dell-asn-units-interceptor.md
16
+ ---
17
+
18
+ ## Summary
19
+
20
+ The `prePost` interceptor on `_Model_Prudential_ServiceRequest` validates `deliverToAddress`
21
+ fields differently depending on which Prudential regional customer is placing the request.
22
+ The region is determined at runtime by looking up `customer.uuid` (sent in the POST payload)
23
+ against the `Client_Prudential.Customers` table, whose `name` column holds the region label.
24
+ Three regions are supported: **USA**, **India**, **Ireland**. Unknown or absent UUIDs fall
25
+ back to USA rules.
26
+
27
+ ## Key files / entry points
28
+
29
+ - `_underscore/Model/Prudential/ServiceRequest.php` — `prePost` interceptor; private methods
30
+ `resolveRegion()`, `validateUsaAddress()`, `validateIndiaAddress()`, `validateIrelandAddress()`
31
+
32
+ ## How it works
33
+
34
+ 1. `prePost` fires before each POST to `/v2/service-requests` for the Prudential client.
35
+ 2. `resolveRegion()` reads `payload->customer->uuid`, escapes it, and queries
36
+ `Client_Prudential.Customers` for the matching `name`. Returns `'India'`, `'Ireland'`, or
37
+ `'USA'` (default for anything unrecognised or when uuid is null).
38
+ 3. A `match` expression dispatches to the correct validator.
39
+ 4. On any validation failure, an `Exception` is thrown with a semicolon-delimited list of all
40
+ errors — the API engine catches it and returns a 4xx to Dell.
41
+
42
+ ## Data model
43
+
44
+ `Client_Prudential.Customers` — the region lookup table:
45
+
46
+ | Column | Type | Notes |
47
+ |--------|-----------|----------------------------------------------------|
48
+ | `id` | int PK | |
49
+ | `uuid` | char(36) | Sent by Dell in `customer.uuid` on every POST |
50
+ | `name` | varchar | Region label: `'USA'`, `'India'`, or `'Ireland'` |
51
+
52
+ ## Validation rules by region
53
+
54
+ ### USA (default)
55
+ | Field | Rule |
56
+ |------------------------|-------------------------------------------|
57
+ | `line1` | Required, max 35 chars |
58
+ | `line2` | Optional, max 35 chars |
59
+ | `city` | Required |
60
+ | `zip` | Required (any characters) |
61
+ | `state.code` | Required, exactly 2 alphabetic characters |
62
+
63
+ ### India (Dell India primary field spec)
64
+ | Field | Rule |
65
+ |-------------------|-------------------------------------------------------|
66
+ | `line1` | Required, max 30 chars (Customer/Consignee Name) |
67
+ | `line2` | Optional, max 30 chars (Address Line 1) |
68
+ | `line3` | Optional, max 30 chars (Address Line 2) |
69
+ | `city` | Required, max 30 chars (Address Line 3 / city) |
70
+ | `zip` | Required, max 6 chars, strictly numeric (0–9) |
71
+ | `mobileNumber` | Optional, 10–15 chars, numeric |
72
+ | `telephoneNumber` | Optional, 6–15 chars, numeric |
73
+ | `customerCode` | Optional, max 6 chars, alphanumeric |
74
+ | `originAreaCode` | Optional, max 3 chars, alphabetic (A–Z) |
75
+
76
+ India optional fields (`mobileNumber`, `telephoneNumber`, `customerCode`, `originAreaCode`)
77
+ are silently skipped when absent — Prudential has not yet started sending them.
78
+
79
+ ### Ireland
80
+ Same as USA except `zip` accepts any characters — Irish Eircode format is alphanumeric
81
+ with a space (e.g. `F92 FP83`). No numeric restriction.
82
+
83
+ ## Gotchas / known issues
84
+
85
+ - **Null UUID = USA fallback.** All requests sent before Prudential added `customer.uuid` to
86
+ their payload lacked the field entirely; those are treated as USA and pass through unchanged.
87
+ This is intentional backward compatibility.
88
+ - **Region check is by `Customers.name` string, not by id.** If the customer name is ever
89
+ changed in the DB (e.g. `'USA'` → `'United States'`), the validator will silently fall
90
+ back to USA rules for all regions. The match arms are `'India'` and `'Ireland'` only;
91
+ everything else maps to USA.
92
+ - **India optional fields are forward-compatible.** The Dell India field spec includes
93
+ `mobileNumber`, `telephoneNumber`, `customerCode`, and `originAreaCode` but Prudential has
94
+ not started sending them yet. The validators already handle them — no code change needed
95
+ when Prudential starts including them.
96
+ - **`line3` is India-only.** USA and Ireland validators do not check `line3` (it is not in
97
+ their Dell spec). If Dell starts sending it for USA/Ireland it is silently ignored.
98
+
99
+ ## Change history
100
+ - 2026-06-16 — Created: regional address validation (USA/India/Ireland) replacing the single
101
+ USA-only `validateDeliverToAddress` method; region resolved from `customer.uuid` lookup (rgirish)
@@ -9,11 +9,12 @@ project: _Underscore
9
9
  client: prudential
10
10
  type: profile
11
11
  status: active
12
- updated: 2026-06-10
13
- owners: ["jcardinal"]
12
+ updated: 2026-06-16
13
+ owners: ["jcardinal", "rgirish"]
14
14
  files: []
15
15
  related:
16
16
  - features/dell-asn-units-interceptor.md
17
+ - features/service-request-address-validation.md
17
18
  ---
18
19
 
19
20
  ## Summary
@@ -24,7 +25,10 @@ return-tracking per unit) into the 2.0 platform (DB `Client_Prudential`); the 1.
24
25
  order-status transmissions.
25
26
 
26
27
  ## Integrations
27
- - **Inbound:** Dell API → POST `/v2/advance-shipping-notices` (creates ASNs + units + tracking).
28
+ - **Inbound (ASNs):** Dell API → POST `/v2/advance-shipping-notices` (creates ASNs + units + tracking).
29
+ - **Inbound (Service Requests):** Dell API → POST `/v2/service-requests`. Payload includes
30
+ `customer.uuid` which maps to a regional customer record (`USA`, `India`, or `Ireland`) in
31
+ `Client_Prudential.Customers` — used to apply region-specific `deliverToAddress` validation.
28
32
  - **Outbound (worker crons):** `transmissions_to_netsuite.php`, `transmit_ordershipped_updates_prudential.php`,
29
33
  `transmit_closecomplete_updates_prudential.php`, `transmit_order_delivered_updates_from_fedex_toga2.php`,
30
34
  `update_tracking_number_from_netsuite_to_toga.php`, `manually_insert_ASN.php`.
@@ -32,6 +36,8 @@ order-status transmissions.
32
36
  ## Gotchas
33
37
  - Dell will not change their payload shape — see the Dell ASN units interceptor feature doc for the
34
38
  PRE/POST translation that keeps their feed working after the tracking-number bridge migration.
39
+ - Service request region is resolved from `Customers.name` string (`'USA'`/`'India'`/`'Ireland'`).
40
+ Renaming those customer records in the DB would silently break regional validation routing.
35
41
 
36
42
  ## Related docs
37
43
  - Dell ASN units interceptor.
@@ -2,5 +2,6 @@
2
2
 
3
3
  | Doc | Framework | Summary | Files |
4
4
  |-----|-----------|---------|-------|
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 |
5
6
  | [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 |
6
7
  | [Rate](profile.md) | 2.0 | Rate is a mortgage/lending client. | |
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Rate Monthly Reconciliation Report
3
+ framework: "1.0"
4
+ repo: worker
5
+ project: Worker
6
+ client: rate
7
+ type: client-feature
8
+ status: active
9
+ updated: 2026-06-16
10
+ owners: ["rgirish"]
11
+ files:
12
+ - worker/crons/notifications/reports/rate/send_monthly_rate_purchases_report.php
13
+ - worker/schedules/cron.worker.notification.json
14
+ related:
15
+ - clients/rate/features/saml-sso.md
16
+ - clients/rate/profile.md
17
+ ---
18
+
19
+ ## Summary
20
+
21
+ A monthly cron that emails an Excel reconciliation report covering all Rate subscription
22
+ sales orders and their linked PayPal payments for the prior calendar month. Used by AIG
23
+ (for contract reconciliation) and the TOGA accounts team (for billing verification).
24
+
25
+ ## How it works
26
+
27
+ 1. Runs on the 1st of each month via `cron.worker.notification.json`.
28
+ 2. Queries `Client_Rate` for all `SalesOrders` whose `dateOrder` falls within the prior
29
+ month, joined through `Entitlements_SalesOrders` → `Entitlements` → `Subscriptions`.
30
+ Filtered to `Subscriptions.token LIKE 'I-%'` (PayPal recurring subscription tokens only).
31
+ 3. Also joins `SalesOrders_Payments` → `Payments` for transaction-level detail.
32
+ 4. Builds a 16-column Excel sheet ("Monthly Reconciliation") using PhpSpreadsheet.
33
+ 5. Emails the `.xlsx` as an attachment. If no orders found, sends a plain no-data notice.
34
+
35
+ ## Report columns
36
+
37
+ | # | Column | Source |
38
+ |---|---|---|
39
+ | 1 | Customer Name | `Customers.name` |
40
+ | 2 | Email | `ContactEmailAddresses.emailAddress` |
41
+ | 3 | Address | `Addresses` (line1, line2, city, state, zip via `CONCAT_WS`) |
42
+ | 4 | Entitlement # | `Entitlements.number` |
43
+ | 5 | AIG Contract # | `Entitlements.c_aigContractNumber` |
44
+ | 6 | Sales Order # | `SalesOrders.number` |
45
+ | 7 | Description | `SalesOrders.description` |
46
+ | 8 | Order Date | `SalesOrders.dateOrder` |
47
+ | 9 | Subscription Token | `Subscriptions.token` |
48
+ | 10 | Active | `Subscriptions.isActive` (Yes/No) |
49
+ | 11 | Date Cancelled | `Subscriptions.dateCancelled` |
50
+ | 12 | Date End | `Subscriptions.dateEnd` |
51
+ | 13 | Transaction ID | `Payments.transactionIdentifier` |
52
+ | 14 | Amount | `Payments.amount` |
53
+ | 15 | Payment Date | `Payments.dtStamp` |
54
+ | 16 | Payment Note | `Payments.note` |
55
+
56
+ ## Key design decisions
57
+
58
+ - **Filtered by `SalesOrders.dateOrder`**, not `Entitlements.dtCreated` — catches recurring
59
+ monthly payments, not just the original purchase date.
60
+ - **`Subscriptions.token LIKE 'I-%'`** — restricts to PayPal recurring billing agreement
61
+ tokens; excludes any one-off or non-PayPal orders.
62
+ - **LEFT JOIN on Payments** — a sales order with no payment record still appears in the
63
+ report (payment columns will be blank). This surfaces orders missing payment data.
64
+ - Ordered by `Subscriptions.id ASC, SalesOrders.dateOrder ASC` — groups all orders per
65
+ subscriber chronologically.
66
+
67
+ ## Recipients
68
+
69
+ Currently `$emailTo` in the script. Update there to add AIG or additional recipients.
70
+
71
+ ## Gotchas / known issues
72
+
73
+ - **`c_aigContractNumber`** is the display string from AIG (e.g. `1000045859462`). The
74
+ companion `c_aigContractId` (Int32) is used by the AIG cancel API but is not included
75
+ in this report — add it if AIG requests it for matching.
76
+ - **To run manually for testing**, comment out the `WHERE` date filter. Restore it before
77
+ leaving the script — the cron runs on the 1st and will pull all-time data otherwise.
78
+ - The script file is named `send_monthly_rate_purchases_report.php` (historical name) but
79
+ the report it generates is now the reconciliation report — the filename was not renamed.
80
+
81
+ ## Change history
82
+
83
+ - 2026-06-16 — Rebuilt from a new-purchases report into a full reconciliation report: query
84
+ now drives off `SalesOrders.dateOrder` (not `Entitlements.dtCreated`), adds Payments join,
85
+ 16-column sheet replacing the old 11-column sheet, filtered to PayPal tokens (rgirish)
@@ -5,15 +5,17 @@ apps:
5
5
  - _underscore
6
6
  - saml
7
7
  - toga2-view
8
+ - worker
8
9
  project: SAML SSO Gateway
9
10
  client: rate
10
11
  type: profile
11
12
  status: active
12
- updated: 2026-06-11
13
+ updated: 2026-06-16
13
14
  owners: ["rgirish"]
14
15
  files: []
15
16
  related:
16
17
  - clients/rate/features/saml-sso.md
18
+ - clients/rate/features/monthly-reconciliation-report.md
17
19
  ---
18
20
 
19
21
  ## Summary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.101",
3
+ "version": "1.0.103",
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",