toga-ai 1.0.86 → 1.0.88

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.
@@ -0,0 +1,5 @@
1
+ # walmarttechservices (Walmart Tech Services) — 1.0 knowledge
2
+
3
+ | Doc | Summary | Files |
4
+ |-----|---------|-------|
5
+ | [Walmart Tech Services Architecture](architecture.md) | Small public-facing PHP marketing + warranty-registration site for **Walmart Tech Services**, the consumer tech-support / device-repair program. | index.php, _.php, app/template.php, app/menu.php, app/content/home.php, app/content/warrantyregistrations/view.php, app/content/warrantyregistrations/iframe.php, app/content/warrantyregistrations/action.php, config.prod.ini, composer.json, .ebextensions/, ebs/git.json |
@@ -0,0 +1,141 @@
1
+ ---
2
+ title: Walmart Tech Services Architecture
3
+ framework: "1.0"
4
+ repo: walmarttechservices
5
+ project: Walmart Tech Services
6
+ client: shared
7
+ type: architecture
8
+ status: active
9
+ updated: 2026-06-15
10
+ owners: [mhammontree]
11
+ files:
12
+ - index.php
13
+ - _.php
14
+ - app/template.php
15
+ - app/menu.php
16
+ - app/content/home.php
17
+ - app/content/warrantyregistrations/view.php
18
+ - app/content/warrantyregistrations/iframe.php
19
+ - app/content/warrantyregistrations/action.php
20
+ - config.prod.ini
21
+ - composer.json
22
+ - .ebextensions/
23
+ - ebs/git.json
24
+ related: []
25
+ ---
26
+
27
+ # Walmart Tech Services Architecture
28
+
29
+ Small public-facing PHP marketing + warranty-registration site for **Walmart Tech
30
+ Services**, the consumer tech-support / device-repair program. The site is operated under
31
+ the **True Network Solutions (TNS)** brand (an Agilant business) and is co-branded with
32
+ Walmart. It is **Framework 1.0** (`App_` classes) running on the **TOGa Commerce 1.0**
33
+ platform and deployed to **AWS Elastic Beanstalk**; it leans on the shared `library` core
34
+ and the back-office **ASI / Vision** platform (`vision.asisystem.com`) for its data.
35
+
36
+ - Repo: `github.com/agilantsolutions/walmarttechservices`. Composer package name is
37
+ `agilantsolutions/togacommerce1` ("TOGa Commerce 1.0").
38
+ - Local path on dev machines is tracked in Claude memory (`repo-path-walmarttechservices`).
39
+ - Public URL: `https://www.walmarttechservices.com/`.
40
+
41
+ ## Purpose / what the site does
42
+
43
+ 1. **Marketing landing page** — describes the tech-support offerings (Tech Support, Device
44
+ Repair, Device Setup, In-Home), a "Premium Tech Support & Security" plan ($89/yr,
45
+ bundles McAfee Total Protection), testimonials, and contact info. Support phone is
46
+ `(888) 725-4544`; contact emails are `InHomeSupport@TrueNetworkSolutions.com` and
47
+ `WalmartSupport@TrueNetworkSolutions.com`. Content lives in `app/menu.php`.
48
+ 2. **Warranty / service registration** — a customer who purchased a service registers it
49
+ via a form (first/last name, email, phone, date of purchase, receipt number, and a
50
+ receipt file upload). On submit it confirms the customer's existing `ServiceRequest`
51
+ and emails a branded confirmation. This is the only interactive feature.
52
+
53
+ ## Stack
54
+
55
+ - **PHP 7.2.33** (pinned in `composer.json` `config.platform`).
56
+ - **Framework 1.0** — uses `App_`-prefixed classes from the `library` core (`App_Page`,
57
+ `App_Registry`, `App_Model_ServiceRequest`, `App_Model_Toga_Contact`, `App_Database`,
58
+ `App_String`, `App_Client_Walmart`, `App_Email_WalmartB2C`, `Browser_Form` and its
59
+ `Browser_Form_Input_*` elements, `Browser_Form_Validator`).
60
+ - **Sentry** (`sentry/sentry ^4.9`) for error tracking.
61
+ - Server-rendered HTML (table-based templates); no SPA/JS framework. Assets in `assets/`.
62
+
63
+ ## Application bootstrap & routing
64
+
65
+ `index.php` → `require('_.php')` (bootstrap/autoloader, wires the `library` core) →
66
+ `App_Framework_WalmartTechServices::initialize()` then `::renderIndex()`.
67
+
68
+ - `app/template.php` is the page chrome. It branches **mobile vs. desktop**
69
+ (`App_Page::isOnMobileDevice()`) and renders a content file chosen by the `content`
70
+ request var: `app/content/<content>.php` (underscores in the var map to directory
71
+ separators, e.g. `warrantyregistrations_iframe` → `warrantyregistrations/iframe.php`).
72
+ Unknown `content` throws `Invalid content destination`.
73
+ - Default content is `home` (`app/content/home.php`), which just requires
74
+ `warrantyregistrations/view.php`.
75
+
76
+ ## Warranty-registration flow
77
+
78
+ - **Form** (`app/content/warrantyregistrations/iframe.php`) — a `Browser_Form` posting to
79
+ the `warrantyregistrations_action` content via an iframe target. Fields: `firstName`,
80
+ `lastName`, `emailAddress` (email-validated), `primaryPhone` (phone-validated),
81
+ `dateOfPurchase` (datepicker), `receiptNumber` (numeric, 5–10 chars), `fileReceipt`
82
+ (file upload). A success state shows a "Thank You" message.
83
+ - **Handler** (`app/content/warrantyregistrations/action.php`, `MODE_NEW`) —
84
+ 1. Sanitizes input (`App_Page::htmlProtect`, `App_String::filterCharactersAlphaOnly`,
85
+ `cleanPhoneNumber`, `cleanEmailAddress`).
86
+ 2. Decrypts an `id` request var (`App_String::decrypt`) into a `serviceRequestId`.
87
+ 3. Loads the linked `App_Model_Toga_Contact`, updates name/phone/email, saves.
88
+ 4. Marks the `App_Model_ServiceRequest` `confirmed = true`.
89
+ 5. Looks up the service(s) on the request and sends a branded confirmation email
90
+ (`App_Email_WalmartB2C`). Two variants by `Services.requiresAgentDownload`: an
91
+ "agent download" email (link built from `App_Client_Walmart::AGENTDOWNLOADURLPREFIX`
92
+ + the contact email) or a "call us" email.
93
+
94
+ ## Data / back-office
95
+
96
+ Configured per-environment in `config.<env>.ini` (`[database_*]`), pointing at the ASI
97
+ Vision RDS cluster (`*.cluster-clwbyqvxdm4q.us-west-2.rds.amazonaws.com`). Logical DBs:
98
+ `Vision` (main), `Logs`, `Vision_Log`, `TOGA` (`db_toga` — `ServiceRequest*`, `Services`,
99
+ `Contact`), `Common`. The site is essentially a thin consumer front-end over service
100
+ requests created elsewhere in the Vision platform.
101
+
102
+ ## External integrations
103
+
104
+ Set in `config.<env>.ini`:
105
+
106
+ - **AWS SES** SMTP (`[email]`) for outbound mail; from-name branded "Office Depot" on some
107
+ envs. Confirmation-email HTML is built with a Stripo template.
108
+ - **OptimumDesk / Easeedesk** (`[optimumdesk]`) — `promo_support_order/create` endpoint.
109
+ - **HP PQWS** (`[hp_pqws]`) — HPE/HPI warranty product/serial lookup web services (mutual
110
+ TLS client certs).
111
+ - **Vision portal / ITAD portal / punchout** (`[portal]`, `[punchout]`) URLs.
112
+
113
+ ## Build, environments & deploy
114
+
115
+ - **AWS Elastic Beanstalk** (PHP platform). `.ebextensions/` configures: HTTP→HTTPS
116
+ redirect, export/cache folders, custom `php.ini`, **Redis sessions**, request-timeout
117
+ fix, **Composer install**, **git-based pull of the `library` core** (`020_setup_git_libraries.config`
118
+ + `ebs/git.json`), and **registration to a shared Application Load Balancer**.
119
+ - Many environments: `config.alpha|beta|demo|stage|test|hotfix|prod.ini` plus per-dev
120
+ `config.dev-*.ini`.
121
+ - Recent work (2025): Sentry integration, composer.json added, EB shared-ALB + name
122
+ truncation, alpha RDS endpoint fix.
123
+
124
+ ## Gotchas / known issues
125
+
126
+ - **`config.*.ini` are committed to git** (`.gitignore` only excludes `.DS_Store`), and
127
+ they contain live credentials (RDS, AWS SES SMTP keys, OptimumDesk, HP cert passwords).
128
+ Treat them as committed secrets — see the constant/section names in `config.prod.ini`
129
+ for *where* a credential lives; never copy values out. If the repo is/was public, rotate.
130
+ - The warranty form's datepicker is hard-coded to a **2017-07-23 → 2018-12-31** purchase
131
+ window (`iframe.php`) — a leftover from the original promo that makes the live form look
132
+ stale; revisit if the form is reused.
133
+ - The desktop footer in `app/template.php` embeds a verbatim copy of Walmart.com's global
134
+ footer markup (Walmart CSS classes, nav links, `© Walmart. All Rights Reserved.`). It is
135
+ decorative/co-branding, not a live Walmart integration.
136
+ - `library` is **not** vendored — it is pulled at deploy via `ebs/git.json`. Local dev
137
+ needs the `library` core checked out alongside.
138
+
139
+ ## Change history
140
+
141
+ - 2026-06-15 — Initial architecture doc; repo onboarded to registry (1.0 app, dependsOn library) (mhammontree)
@@ -57,9 +57,11 @@ Its output depends entirely on the trigger **context** (because it reads field v
57
57
  changed field on `context.newRecord` → `tranid`/entity/title read empty → 2493 falls back to
58
58
  `name = "OPP " + record.id` with empty descriptive/custom fields → the degenerate stub.
59
59
 
60
- The degenerate trigger is **scheduled script 2412 "Update Opp Status / % to Close / Presales Lead"**
60
+ The degenerate trigger was **scheduled script 2412 "Update Opp Status / % to Close / Presales Lead"**
61
61
  (deployment `customdeploy_update_opp_status_morning`, status SCHEDULED). It auto-assigns the Presales
62
- Lead via `submitFields` (NetSuite context `SCH`, user `-System-`), which fires 2493 in `xedit` → stub.
62
+ Lead (NetSuite context `SCH`, user `-System-`) — originally via `submitFields`, which fired 2493 in
63
+ `xedit` → stub. **Fixed 2026-06-15:** 2412 now does a full `record.load()`/`setValue()`/`save()`, so
64
+ the assignment fires 2493 in `edit` (full-record) context → proper name (see Gotchas → Fix).
63
65
 
64
66
  ## Data model
65
67
  - ClickUp Opportunities list `901111987449`; custom-item id `1009`.
@@ -85,17 +87,25 @@ None — single internal Agilant/True integration.
85
87
  June 1 edit added the Presales-Lead auto-assignment. **Precise failure condition:** only the
86
88
  *empty→set* transition fires it — a scheduled set to an already-present lead is a no-op (confirmed
87
89
  on opp 5483750, where a 07:02 `SCH` set produced no stub because the lead was already present).
88
- - **Fix options (NetSuite-side, in script 2493):**
89
- - *Preferred* `record.load({type, id: context.newRecord.id})` (or `search.lookupFields` for
90
- `tranid`/entity/title) before building `name`. Works for **every** trigger context; produces
91
- correct names instead of stubs-or-nothing.
92
- - *Alternative* skip on `xedit` (`if (context.type === context.UserEventType.XEDIT) return;`).
93
- Suppresses the stubs but **also drops** legitimate task creation from inline-grid edits, mass
94
- updates, and any other `submitFields` automation. Does **not** affect full-form saves, creates,
95
- or REST/SOAP edits (incl. the touch tool, which is `RWS`/full-edit). Trades a visible bug for a
96
- silent one only acceptable if presales leads are never set inline/in bulk.
97
- - *TOGA backstop (optional)* in `createTask()`, if `name` is empty or matches `^OPP \d+$`, look
98
- the opp up by internal id and rebuild the name before POSTing.
90
+ - **Fix applied in NetSuite prod 2026-06-15 (deployed; pending verification on next scheduled
91
+ run).** In scheduled script **2412**, the presales-lead assignment was changed from
92
+ `record.submitFields({type, id, values:{custbody_ctc_solution_architect: employeeId}, ...})` to a
93
+ full `record.load()` `setValue('custbody_ctc_solution_architect', employeeId)` →
94
+ `record.save({ignoreMandatoryFields:true})`. A full `save()` fires 2493 with `context.type='edit'`
95
+ and the **complete** `newRecord`, so it reads `tranid`/entity/title and builds a proper name; the
96
+ empty→set guard still works (`oldRecord` reflects the pre-save state). **Verify** by watching the
97
+ next `SCH` empty→set run for a properly-named task (not `OPP <id>`) not yet observed against a
98
+ live scheduled run as of the fix.
99
+ - **Residual exposure:** 2493 still reads off `context.newRecord`, so *other* `xedit`-context
100
+ presales-lead sets (inline-grid edit, Mass Update, any other script's `submitFields`) would still
101
+ stub. The 2412 fix closes the actual regression, not the latent 2493 hole. Belt-and-suspenders =
102
+ add a `record.load()`/`lookupFields` fallback **inside 2493** too (not done).
103
+ - **Watch-outs from the full save:** governance per opp rose ~2.5× (`load` ~5 + `save` ~20 units vs
104
+ `submitFields` ~10) — guard batch runs against the governance ceiling (yield/reschedule); and a
105
+ full `save()` re-fires **all** `edit`-context UserEvents/workflows on the opp (Quosal, LSA, etc.),
106
+ not just 2493.
107
+ - **TOGA backstop (optional, not done):** in `createTask()`, if `name` is empty or matches
108
+ `^OPP \d+$`, look the opp up by internal id and rebuild the name before POSTing.
99
109
  - **No inbound logging.** `Webhook_NetSuite::post()` has a `// Log payload to file` comment but does
100
110
  **nothing** — the raw NetSuite payload is persisted nowhere, which is why this was hard to trace.
101
111
  Adding real request logging here would make recurrences diagnosable immediately.
@@ -118,9 +128,13 @@ It blanks then restores `custbody_ctc_solution_architect` via REST (`RWS`/full-e
118
128
  with the full record → proper `<tranid> — <custNum> <customer> — <title>` task ~1–2s later.
119
129
  **Leaves the original stub** — delete the `OPP <id>` task in ClickUp afterward.
120
130
  Done 2026-06-15 for opps 7147699/7147698/7147472/6382879 → 4 proper tasks created; the 4 stubs
121
- (task ids `868k0tr41`, `868k0tr16`, `868k0rwtp`, `868k0h44m`) were left for deletion.
131
+ (task ids `868k0tr41`, `868k0tr16`, `868k0rwtp`, `868k0h44m`) were archived in ClickUp afterward.
122
132
 
123
133
  ## Change history
134
+ - 2026-06-15 — **Fix deployed in NetSuite prod:** scheduled script 2412's presales-lead assignment
135
+ switched from `submitFields` to full `load`/`setValue`/`save` → fires 2493 in `edit` (full-record)
136
+ context → proper names. Residual: 2493 still latently `xedit`-vulnerable to other triggers; watch
137
+ governance (~2.5×) and other UserEvents re-firing on the full save. Pending live-run verification. (dfranks)
124
138
  - 2026-06-15 — Identified the exact NetSuite culprits (scheduled **2412** `submitFields`→`xedit`→
125
139
  UserEvent **2493**), regression date (script 2412 modified 2026-06-01; no stubs before Jun 12),
126
140
  and `systemnote`/`SCH` confirmation; added remediation-via-touch procedure and fix-option
@@ -9,6 +9,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
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)
12
+ - **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
12
13
 
13
14
  ## 2.0 framework
14
15
 
@@ -12,5 +12,6 @@
12
12
  { "repo": "togaview", "project": "TOGa View", "framework": "1.0", "role": "app", "dependsOn": [] },
13
13
  { "repo": "toga2-hub", "project": "TOGa Hub", "framework": "2.0", "role": "app", "dependsOn": ["api2"] },
14
14
  { "repo": "togatech", "project": "TOGA Technology Website", "framework": "standalone", "role": "app", "dependsOn": [] },
15
- { "repo": "webhook", "project": "Webhook", "framework": "1.0", "role": "app", "dependsOn": ["library"] }
15
+ { "repo": "webhook", "project": "Webhook", "framework": "1.0", "role": "app", "dependsOn": ["library"] },
16
+ { "repo": "walmarttechservices", "project": "Walmart Tech Services", "framework": "1.0", "role": "app", "dependsOn": ["library"] }
16
17
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.86",
3
+ "version": "1.0.88",
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",