toga-ai 1.0.302 → 1.0.304
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/1.0/apps/togadesk/INDEX.md +1 -0
- package/knowledge/1.0/apps/togadesk/features/managed-service-order-create.md +109 -0
- package/knowledge/1.0/standards/backend-php.md +22 -2
- package/knowledge/INDEX.md +1 -1
- package/knowledge/clients/nycdoe/INDEX.md +1 -1
- package/knowledge/sessions/2026-07-09-true-80100-mso-create-fix-mhammontree.md +64 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
| [TOGa Desk Architecture](architecture.md) | TOGa Desk is the staff-facing support desk **and field-service platform** (analysts work at `/desk/`). | desk/index.php, desk/includes/loader.php, desk/config.php, desk/includes/controllers/actions.php, desk/includes/controllers/data.php, desk/includes/controllers/modals.php, desk/includes/classes/class.app.php, desk/includes/classes/class.ticket.php, desk/api/index.php, desk/api/resources/tickets.php, crons/tickets.php |
|
|
6
6
|
| [Email-to-Ticket Intake (crons/tickets.php)](features/email-to-ticket-intake.md) | TOGa Desk ingests support email into tickets through a cron-driven IMAP poller (`crons/tickets.php`) plus a postfix pipe variant (`crons/pipe.php`). | crons/tickets.php, crons/tickets_prod.php, crons/pipe.php, desk/includes/classes/class.ticket.php |
|
|
7
7
|
| [Field-Service Dispatch (central / repair orders)](features/field-service-dispatch.md) | The **central** subsystem is TOGa Desk's field-service dispatch domain: repair-order lifecycle, technician scheduling, onsite vs depot service, parts, and shipm | desk/includes/controllers/actions/central/, desk/includes/classes/class.repair.php, desk/includes/classes/class.repairhistory.php, desk/_/browser/datatable/central.php, desk/template/pages/central.php, desk/template/pages/central/view.php, desk/template/modals/central/addTracking.php, library/app/model/togadesk/repairorder.php, library/app/model/togadesk/repairordertracking.php, library/app/api/carrier/ups.php |
|
|
8
|
+
| [Managed Service Order Create Flow (New MSO modal → tickets/add)](features/managed-service-order-create.md) | The **Managed Service Order (MSO) create flow** is how a TOGa Desk user manually creates a managed service order: pick an End User (or a Client Location), choos | desk/includes/controllers/actions/tickets/add.php, desk/template/modals/tickets/addNew.php, desk/template/pages/managed.php, desk/template/pages/getinfo.php, desk/template/footer.php, library/app/model/togadesk/repairorder.php |
|
|
8
9
|
| [Ticket Email Notifications (notifications table)](features/notifications.md) | Which TOGa Desk emails fire for a given client is driven **entirely by data**, not code: the `TOGaDeskSupport.notifications` table holds one row per `(clientid, | desk/includes/classes/class.notification.php, crons/tickets.php, crons/tickets_prod.php |
|
|
9
10
|
| [REST API (RPC-over-POST) & API-Key Auth](features/rest-api.md) | TOGa Desk exposes a programmatic API at `desk/api/`. | desk/api/index.php, desk/api/resources/tickets.php, desk/api/resources/assets.php, desk/api/resources/authenticate.php, desk/includes/classes/class.apikey.php, desk/includes/functions.php |
|
|
10
11
|
| [SMB Contract Editing & the clientMspId Corruption Trap](features/smb-contract-editing.md) | The SMB contracts page (`/desk/?route=toga/smbcontracts&togaClientId=<id>`) edits `TOGA_*.SMBContracts` rows via a modal. | desk/template/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/modals/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/smbContract.php, desk/includes/controllers/actions/toga/smbcontracts/edit.php |
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Managed Service Order Create Flow (New MSO modal → tickets/add)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: togadesk
|
|
5
|
+
project: TOGa Desk
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-07-09
|
|
10
|
+
owners: ["mhammontree"]
|
|
11
|
+
files:
|
|
12
|
+
- desk/includes/controllers/actions/tickets/add.php
|
|
13
|
+
- desk/template/modals/tickets/addNew.php
|
|
14
|
+
- desk/template/pages/managed.php
|
|
15
|
+
- desk/template/pages/getinfo.php
|
|
16
|
+
- desk/template/footer.php
|
|
17
|
+
- library/app/model/togadesk/repairorder.php
|
|
18
|
+
related:
|
|
19
|
+
- 1.0/apps/togadesk/architecture.md
|
|
20
|
+
- 1.0/apps/togadesk/features/field-service-dispatch.md
|
|
21
|
+
- 1.0/apps/togadesk/features/ticket-lifecycle.md
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Summary
|
|
25
|
+
The **Managed Service Order (MSO) create flow** is how a TOGa Desk user manually creates a
|
|
26
|
+
managed service order: pick an End User (or a Client Location), choose a Contract, add one or
|
|
27
|
+
more assets, and submit. The server builds a `ManagedServiceOrder`, creates its assets, then
|
|
28
|
+
one `App_Model_TogaDesk_RepairOrder` per asset. This is the **entry/creation** side; the
|
|
29
|
+
downstream repair-order lifecycle (dispatch, scheduling, status) lives in
|
|
30
|
+
[Field-Service Dispatch](./field-service-dispatch.md).
|
|
31
|
+
|
|
32
|
+
## Key files / entry points
|
|
33
|
+
- **Entry link:** `desk/template/pages/managed.php` — the "NEW MANAGED SERVICE ORDER" link opens
|
|
34
|
+
modal `tickets/addNew`.
|
|
35
|
+
- **Modal:** `desk/template/modals/tickets/addNew.php` — the New MSO form. It has **no own
|
|
36
|
+
`<form>` tag**; it relies on the global `#formModal` wrapper (rendered in
|
|
37
|
+
`desk/template/footer.php`) and `$("form").submit()`. Contains the Summary field, an optional
|
|
38
|
+
inline **new End User** sub-form (name/email/phone + a `#new-user-password` field), an inline
|
|
39
|
+
**new address** sub-form, and select2 dropdowns `#enduser`, `#userlocation`, `#location`.
|
|
40
|
+
- **Server action:** `desk/includes/controllers/actions/tickets/add.php` — builds the
|
|
41
|
+
`ManagedServiceOrder`, creates assets, then a `RepairOrder` per asset. `ticketType`
|
|
42
|
+
`INSTALLATION` maps the repair order to `App_Model_TogaDesk_RepairOrder::TYPE_ONSITESERVICE`.
|
|
43
|
+
- **Address AJAX:** `desk/template/pages/getinfo.php` — populates the End User Address dropdown.
|
|
44
|
+
|
|
45
|
+
## How it works
|
|
46
|
+
1. `managed.php` opens the `tickets/addNew` modal into the global `#formModal`.
|
|
47
|
+
2. The user selects an existing End User (`#enduser` → `userid`) or creates a new one inline;
|
|
48
|
+
selects an End User Address (`#userlocation`) or a Client Location (`#location`); picks a
|
|
49
|
+
Contract; and adds assets.
|
|
50
|
+
3. Submit runs the modal's client-side validator, then POSTs `?action=…` to `add.php`.
|
|
51
|
+
4. `add.php` builds the `ManagedServiceOrder`, creates each asset, and for each asset builds a
|
|
52
|
+
`RepairOrder`. In the `TYPE_ONSITESERVICE` branch it reads optional per-asset fields
|
|
53
|
+
(`installation`, `access-instructions`) — see the getVar gotcha below.
|
|
54
|
+
|
|
55
|
+
### Address sourcing — per-person vs. client location (important)
|
|
56
|
+
There are **two** address sources, and they come from different tables:
|
|
57
|
+
- **End User Address dropdown (`#userlocation`)** is per **person**. `getinfo.php` (uid branch,
|
|
58
|
+
~L152–171) runs `SELECT … FROM people_addresses INNER JOIN addresses ON addresses.id =
|
|
59
|
+
people_addresses.addressid WHERE people_addresses.peopleid = <uid>`. Addresses are stored
|
|
60
|
+
**per person** in the `addresses` table + `people_addresses` junction (`peopleid` → `addressid`)
|
|
61
|
+
in the togadesk DB (`TOGaDeskSupport` / `db_togadesk`).
|
|
62
|
+
- **An empty End User Address dropdown is a legitimate data state**, not a bug — it just means
|
|
63
|
+
that person has no `people_addresses` row. The **designed fallback** is the modal's inline
|
|
64
|
+
"add new address" form (`addNewAddress()` sets the `#newAddressCount` hidden field), which
|
|
65
|
+
`add.php` (~L119–148) fully supports creating.
|
|
66
|
+
- **Client Location (`#location`)** is the alternative: client/site addresses live in the
|
|
67
|
+
`locations` table keyed by `clientid`, reachable via the modal's "Select either End User or
|
|
68
|
+
Client Location" toggle (`#checkbox` → `#servicelocation`/`#location`), enabled once a Contract
|
|
69
|
+
is chosen.
|
|
70
|
+
|
|
71
|
+
History: the per-person-only End User query dates to a **2021-12-06** schema migration
|
|
72
|
+
(`repair_order_addresses`/`primaryaddress` → `addresses`/`isprimary`, commit `bf1abaa06`, Jeff).
|
|
73
|
+
The older query — still commented in `getinfo.php` ~L95–148 — UNIONed client `locations` into the
|
|
74
|
+
End User dropdown. Dropping that UNION is **long-standing, not a recent regression**.
|
|
75
|
+
|
|
76
|
+
## Gotchas / known issues
|
|
77
|
+
- **`App_Page::getVar($var)` THROWS when the request var is absent** — it is **not** a
|
|
78
|
+
null-returning getter. In the `TYPE_ONSITESERVICE` branch, `add.php` (~L353–354) read the
|
|
79
|
+
optional `installation` and `access-instructions` fields; the manual MSO form doesn't post
|
|
80
|
+
`installation`, so the whole create aborted with a Sentry exception. **Fix:** use
|
|
81
|
+
`App_Page::getVarIfSet($var)` (returns `null`) — or guard with `App_Page::varIsSet()` — for any
|
|
82
|
+
**optional** request field. This is a framework-wide 1.0 `App_` gotcha, not togadesk-specific
|
|
83
|
+
(`library/app/page.php` — `getVar` L354 throws, `getVarIfSet` L382 returns null,
|
|
84
|
+
`varIsSet` L404).
|
|
85
|
+
- **Chrome autofill silently breaks the modal.** The modal nests a new-user sub-form (including a
|
|
86
|
+
password field) inside `#formModal`, which had no `autocomplete` attribute. Chrome's
|
|
87
|
+
password/profile autofill then filled Summary + address fields **without firing jQuery
|
|
88
|
+
change/input events and without syncing the select2 widgets**, so validation saw empty values
|
|
89
|
+
(e.g. "Please select an address" on a field that looked filled). Manual typing worked because it
|
|
90
|
+
fires the events. **Fix:** `autocomplete="off"` on `#formModal` (and the new-user/new-address/
|
|
91
|
+
Summary/select2 fields) plus `autocomplete="new-password"` on the password field (Chrome ignores
|
|
92
|
+
form-level `off` for password fields).
|
|
93
|
+
- **No-saved-address submit deadlock.** When an existing End User (`userid != 0`) had no saved
|
|
94
|
+
address, the validator required `#userlocation != 0` ("Please select an address."), but the
|
|
95
|
+
dropdown was empty and the modal auto-opened the inline add-address form — an unresolvable
|
|
96
|
+
deadlock. **Fix:** the validator now also reads `newAddressCount = parseInt($('#newAddressCount')
|
|
97
|
+
.val())||0` and only blocks when `selectedValue == 0 AND newAddressCount == 0`, since the server
|
|
98
|
+
already supports the inline address.
|
|
99
|
+
- The addNew modal has **no `<form>` tag of its own** — it depends entirely on the global
|
|
100
|
+
`#formModal` in `footer.php` and `$("form").submit()`. Anything that alters that global wrapper
|
|
101
|
+
(attributes, nesting) affects this flow.
|
|
102
|
+
|
|
103
|
+
## Change history
|
|
104
|
+
- 2026-07-09 — TRUE-80100: documented the MSO create flow (entry, server action, per-person vs.
|
|
105
|
+
client-location address sourcing) and folded in three fixes: `getVar` → `getVarIfSet` for
|
|
106
|
+
optional request vars in the `TYPE_ONSITESERVICE` branch (server crash); `autocomplete` on
|
|
107
|
+
`#formModal` + password field to stop Chrome autofill bypassing select2/events; and the
|
|
108
|
+
validator now honors `#newAddressCount` so a no-address End User can submit an inline address.
|
|
109
|
+
(mhammontree)
|
|
@@ -5,8 +5,8 @@ project: Library
|
|
|
5
5
|
client: shared
|
|
6
6
|
type: standard
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-07-
|
|
9
|
-
owners: [jcardinal, rgirish]
|
|
8
|
+
updated: 2026-07-09
|
|
9
|
+
owners: [jcardinal, rgirish, mhammontree]
|
|
10
10
|
files: []
|
|
11
11
|
related:
|
|
12
12
|
- ../apps/library/architecture.md
|
|
@@ -429,6 +429,26 @@ gracefully instead of dropping unrelated work or crashing the loop.
|
|
|
429
429
|
|
|
430
430
|
* Validate and sanitize all user input (see SQL Injection Prevention and HTML escaping above).
|
|
431
431
|
|
|
432
|
+
### Request variable access — `getVar` throws, `getVarIfSet` returns null
|
|
433
|
+
|
|
434
|
+
`App_Page::getVar($var)` is **not** a null-returning getter — it **throws**
|
|
435
|
+
`Exception("Variable '$var' does not exist in the request headers.")` when the request var is
|
|
436
|
+
absent (`library/app/page.php` L354). Use it only for fields you *know* are always posted.
|
|
437
|
+
|
|
438
|
+
For any **optional** request field, use `App_Page::getVarIfSet($var)` (returns `null` when
|
|
439
|
+
missing, L382) or guard first with `App_Page::varIsSet($var)` (L404). Reading an optional field
|
|
440
|
+
with `getVar()` aborts the whole request with an uncaught exception — this is a recurring 1.0
|
|
441
|
+
crash class (e.g. TRUE-80100: an unconditional `getVar('installation')` in a create action
|
|
442
|
+
crashed every submit that omitted the field).
|
|
443
|
+
|
|
444
|
+
```php
|
|
445
|
+
// WRONG — throws when 'installation' isn't posted
|
|
446
|
+
$order->location = App_Page::getVar('installation');
|
|
447
|
+
|
|
448
|
+
// CORRECT — optional field
|
|
449
|
+
$order->location = App_Page::getVarIfSet('installation');
|
|
450
|
+
```
|
|
451
|
+
|
|
432
452
|
### Secure Communication
|
|
433
453
|
|
|
434
454
|
* Always use HTTPS to encrypt data in transit.
|
package/knowledge/INDEX.md
CHANGED
|
@@ -7,7 +7,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
7
7
|
- **library** (Library) _(framework core)_ — 11 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
8
|
- **worker** (Worker) — 14 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **worker1.5** (Worker 1.5) — 0 doc(s) → [1.0/apps/worker1.5/INDEX.md](1.0/apps/worker1.5/INDEX.md)
|
|
10
|
-
- **togadesk** (TOGa Desk) —
|
|
10
|
+
- **togadesk** (TOGa Desk) — 9 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
11
11
|
- **togaview** (TOGa View) — 6 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
|
|
12
12
|
- **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
|
|
13
13
|
- **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
| Doc | Framework | Summary | Files |
|
|
4
4
|
|-----|-----------|---------|-------|
|
|
5
5
|
| [NYCDOE Ticket Hold-Status Sync (ServiceNow ⇄ TOGaDesk)](features/hold-status-sync.md) | 1.0 | DOE ticket **hold** status must round-trip between ServiceNow (SNOW) and TOGaDesk and **stay held** — holds are SLA-bearing in both systems. | worker/crons/sync/nycdoe/send_ticket_updates.php, worker/crons/sync/nycdoe/process_tickets.php, worker/crons/sync/nycdoe/send_request_item_updates.php, library/app/model/togadesk/repairorder.php, library/app/api/nycdoev2.php, togadesk/desk/includes/classes/class.repair.php |
|
|
6
|
-
| [NYCDOE ServiceNow / ASN Integration](features/servicenow-integration.md) | 1.0 | The NYCDOE/ServiceNow integration mirrors DOE's ServiceNow tickets (Incidents + RITMs) into local tables, turns vendor shipment notices into NetSuite Sales Orde | worker/crons/sync/nycdoe/import_asn.php, worker/crons/sync/nycdoe/import_inc.php, worker/crons/sync/nycdoe/legacy_import_asn.php, worker/crons/sync/nycdoe/legacy_process_asn_queue.php, worker/crons/sync/nycdoe/process_tickets.php, worker/crons/sync/nycdoe/1_send_asn_to_netsuite.php, worker/crons/sync/nycdoe/2_send_serials_to_netsuite.php, worker/crons/sync/nycdoe/3_create_installation_ticket.php, worker/crons/sync/nycdoe/send_ticket_updates.php, worker/crons/sync/nycdoe/send_request_item_updates.php, worker/crons/sync/nycdoe/send_nycdoe_proof_of_delivery.php, worker/crons/sync/nycdoe/sync_nycdoe_locations.php, worker/crons/sync/nycdoe/receive_edi_purchase_orders.php, worker/crons/sync/nycdoe/send_edi_open_invoices.php, worker/crons/notifications/nycdoe/, worker/schedules/cron.worker.sync.json, worker/schedules/cron.worker.notification.json, library/app/api/nycdoe.php, library/app/api/nycdoev2.php, library/app/asnprocessor/manufacturer.php, library/app/asnprocessor/apple.php, library/app/asnprocessor/lenovo.php, library/app/asnprocessor/lexmark.php, library/app/asnprocessor/acer.php, library/app/edi.php |
|
|
6
|
+
| [NYCDOE ServiceNow / ASN Integration](features/servicenow-integration.md) | 1.0 | The NYCDOE/ServiceNow integration mirrors DOE's ServiceNow tickets (Incidents + RITMs) into local tables, turns vendor shipment notices into NetSuite Sales Orde | worker/crons/sync/nycdoe/import_asn.php, worker/crons/sync/nycdoe/import_inc.php, worker/crons/sync/nycdoe/legacy_import_asn.php, worker/crons/sync/nycdoe/legacy_process_asn_queue.php, worker/crons/sync/nycdoe/process_tickets.php, worker/crons/sync/nycdoe/1_send_asn_to_netsuite.php, worker/crons/sync/nycdoe/2_send_serials_to_netsuite.php, worker/crons/sync/nycdoe/3_create_installation_ticket.php, worker/crons/sync/nycdoe/test_multi_po_receipt_resolution.php, worker/crons/sync/nycdoe/send_ticket_updates.php, worker/crons/sync/nycdoe/send_request_item_updates.php, worker/crons/sync/nycdoe/send_nycdoe_proof_of_delivery.php, worker/crons/sync/nycdoe/sync_nycdoe_locations.php, worker/crons/sync/nycdoe/receive_edi_purchase_orders.php, worker/crons/sync/nycdoe/send_edi_open_invoices.php, worker/crons/notifications/nycdoe/, worker/schedules/cron.worker.sync.json, worker/schedules/cron.worker.notification.json, library/app/api/nycdoe.php, library/app/api/nycdoev2.php, library/app/asnprocessor/manufacturer.php, library/app/asnprocessor/apple.php, library/app/asnprocessor/lenovo.php, library/app/asnprocessor/lexmark.php, library/app/asnprocessor/acer.php, library/app/edi.php, library/app/netsuite.php |
|
|
7
7
|
| [New York City Department of Education](profile.md) | 1.0 | NYC DOE (New York City Department of Education) is a TOGA client whose entire integration runs in the **1.0 worker tier** (~30 cron scripts under `worker/crons/ | |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: session
|
|
3
|
+
slug: true-80100-mso-create-fix
|
|
4
|
+
title: Fix errors creating a manual managed service order (togadesk)
|
|
5
|
+
author: mhammontree
|
|
6
|
+
repos: [togadesk]
|
|
7
|
+
framework: "1.0"
|
|
8
|
+
client: shared
|
|
9
|
+
status: active
|
|
10
|
+
created: 2026-07-09
|
|
11
|
+
updated: 2026-07-09
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Session: true-80100-mso-create-fix
|
|
15
|
+
**Date:** 2026-07-09
|
|
16
|
+
**Project/Repo:** togadesk (1.0)
|
|
17
|
+
**Task:** Fix TRUE-80100 — errors creating a manual managed service order (MSO) in togadesk; reported against the Northwell Health client but the defects are general to the shared MSO create flow.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What WORKED
|
|
22
|
+
<!-- Include specific file paths and evidence -->
|
|
23
|
+
- **Server crash fix** — `desk/includes/controllers/actions/tickets/add.php:353-354`: changed `App_Page::getVar('installation')` and `getVar('access-instructions')` to `App_Page::getVarIfSet(...)`. Root cause: `App_Page::getVar()` (library/app/page.php:354) THROWS `Exception("Variable 'X' does not exist in the request headers.")` when the var is absent; the manual MSO form omits `installation`, so the onsite-service (TYPE_ONSITESERVICE) branch crashed. `getVarIfSet()` (page.php:382) returns null instead. Evidence: matched the original Sentry trace (getVar → add.php:353 → require chain); after fix, **Test 1** (user WITH an address) created the MSO successfully with no exception.
|
|
24
|
+
- **Submit-validation deadlock fix** — `desk/template/modals/tickets/addNew.php` submit handler (~line 3284): validator now reads `newAddressCount = parseInt($('#newAddressCount').val())||0` and only blocks when `selectedValue==0 && newAddressCount==0`. Root cause: an existing End User with no saved address got an empty `#userlocation` dropdown + an auto-opened inline add-address form, but the validator required a non-zero dropdown pick and ignored the inline address — unresolvable deadlock. Evidence: **Test 2** (user with NO address → filled inline add-address form) created the MSO successfully.
|
|
25
|
+
- **Chrome autofill hardening** — added `autocomplete` attributes: `autocomplete="off"` on `#formModal` (`desk/template/footer.php:9`); `autocomplete="new-password"` on `#new-user-password`; `autocomplete="off"` on the new-user fields, new-address fields (address1/2, city, state, zip), Summary (`#subject`), and the select2 dropdowns (`#enduser`, `#userlocation`, `#location`) in `addNew.php`. Root cause: the password field made Chrome autofill Summary/address fields (blue highlight) without firing change/input events or syncing select2, so validation saw empty values. Defensive — cannot regress the create flow. Not independently re-tested (users filled fields manually in both tests).
|
|
26
|
+
- **Address data model confirmed** — the End User Address dropdown is sourced per-person from `people_addresses INNER JOIN addresses ON addresses.id = people_addresses.addressid WHERE people_addresses.peopleid = <uid>` (`desk/template/pages/getinfo.php:152-171`, db_togadesk / TOGaDeskSupport). Confirmed live: a user WITH a `people_addresses` row populates the dropdown and selects fine. Empty dropdown = that person has no `people_addresses` row (legitimate data state), not a bug.
|
|
27
|
+
- **Knowledge captured & pushed** — `/capture` published to `_main`: new feature doc `1.0/apps/togadesk/features/managed-service-order-create.md` and an elevated update to `1.0/standards/backend-php.md` (getVar-throws rule). validate OK (28 repos), index 233 docs.
|
|
28
|
+
- **Code pushed** — all three fixes committed and pushed to branch `TRUE-80100` in the togadesk repo; local togadesk is checked out on `TRUE-80100`.
|
|
29
|
+
|
|
30
|
+
## What did NOT work — DO NOT RETRY THESE
|
|
31
|
+
<!-- Exact failure reasons — do not vague-ify -->
|
|
32
|
+
- **Do NOT restore the commented-out `locations` UNION in getinfo.php** (getinfo.php:95-148) as a "fix" for the empty End User Address dropdown. The empty dropdown is NOT a regression: git blame shows the per-person-only query dates to the 2021-12-06 schema migration `repair_order_addresses/primaryaddress` → `addresses/isprimary` (commit bf1abaa06, Jeff). Client/site addresses intentionally live in the `locations` table and are reached via the modal's "Select either End User or Client Location" toggle (`#checkbox` → `#servicelocation`/`#location`), enabled once a Contract is chosen. Empty per-person dropdown is expected; inline add-address is the designed fallback.
|
|
33
|
+
- **Do NOT fix only add.php:353 and leave :354.** Line 354 (`access-instructions`) is the identical unguarded `getVar` on the next line and would throw immediately after 353 is fixed — both must use `getVarIfSet`.
|
|
34
|
+
|
|
35
|
+
## Not tried yet (candidates for next session)
|
|
36
|
+
- Independently verify the autofill fix in an incognito Chrome window (both create tests were done with manual field entry, so fix #2 was never actually exercised against live autofill).
|
|
37
|
+
- Optional pre-merge hygiene: `php -l` on the 3 changed files and a `php-reviewer` pass (never run this session).
|
|
38
|
+
- Sweep the rest of the MSO create block in add.php for OTHER unconditional `getVar()` reads that could throw the same way (departmentid, priority, deliveryc, warrentyStartDate, deviceAge, etc.) — deferred per developer ("just the reported crash"). Only revisit if a NEXT-field crash surfaces.
|
|
39
|
+
- PR review/merge of branch `TRUE-80100` (not started).
|
|
40
|
+
|
|
41
|
+
## Current file state
|
|
42
|
+
| File | Status | Notes |
|
|
43
|
+
|------|--------|-------|
|
|
44
|
+
| desk/includes/controllers/actions/tickets/add.php | Modified, committed on TRUE-80100 | Lines 353-354 `getVar`→`getVarIfSet` |
|
|
45
|
+
| desk/template/footer.php | Modified, committed on TRUE-80100 | `autocomplete="off"` on `#formModal` (line 9) |
|
|
46
|
+
| desk/template/modals/tickets/addNew.php | Modified, committed on TRUE-80100 | Validator deadlock fix (~3284) + `autocomplete` attrs on new-user/new-address/Summary/select2 fields |
|
|
47
|
+
| desk/template/pages/getinfo.php | Read-only (no change) | Investigated only — confirmed per-person address query is correct/by-design |
|
|
48
|
+
| knowledge/1.0/apps/togadesk/features/managed-service-order-create.md | Created, pushed to _main | New feature doc (MSO create flow + 3 fix gotchas) |
|
|
49
|
+
| knowledge/1.0/standards/backend-php.md | Modified, pushed to _main | Added getVar-throws rule (elevated, approved) |
|
|
50
|
+
|
|
51
|
+
## Decisions made
|
|
52
|
+
- **Guard the read in add.php rather than fix the form to always post `installation`** (developer choice). Rationale: immediate, minimal, matches the surrounding guarded pattern; `location` becomes null when absent, which is acceptable for onsite-service. Rejected: form-side fix (larger surface) and "both".
|
|
53
|
+
- **Empty End User Address dropdown is by-design, not a code bug.** Rationale: confirmed via git blame (2021 per-person migration) + live test (a user with an address works); client locations are a separate intentional path via the toggle. Rejected: restoring the `locations` UNION.
|
|
54
|
+
- **Promote the getVar-throws rule to the elevated 1.0 backend-php standard** (developer approved). Rationale: `getVar` throwing vs `getVarIfSet` returning null is App_-framework-wide, not togadesk-specific; it's a recurring 1.0 crash class.
|
|
55
|
+
- **No client doc for Northwell.** Rationale: Northwell was only the reporting client; the defects and knowledge are shared/internal to the togadesk MSO flow.
|
|
56
|
+
|
|
57
|
+
## Blockers
|
|
58
|
+
none — all three fixes verified for the two create paths and pushed; knowledge published.
|
|
59
|
+
|
|
60
|
+
## Exact next step
|
|
61
|
+
> This task is essentially complete. If anything remains: open branch `TRUE-80100` for PR review/merge, and optionally verify the autofill fix (#2) in an incognito Chrome window since both create tests used manual field entry (autofill was never exercised).
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
_Saved by /session-save on 2026-07-09_
|
package/package.json
CHANGED