toga-ai 1.0.684 → 1.0.686
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/INDEX.md +1 -1
- package/knowledge/clients/nychh/INDEX.md +1 -1
- package/knowledge/clients/nychh/features/po-number-upstream-direction.md +10 -1
- package/knowledge/clients/nychh/profile.md +13 -1
- package/knowledge/clients/prudential/INDEX.md +2 -1
- package/knowledge/clients/prudential/features/order-email-pdf-attachments.md +141 -0
- package/knowledge/clients/prudential/features/transmit-ordershipped-email.md +30 -5
- package/knowledge/clients/prudential/profile.md +8 -1
- package/package.json +1 -1
package/knowledge/INDEX.md
CHANGED
|
@@ -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)_ — 20 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
|
-
- **worker** (Worker) —
|
|
8
|
+
- **worker** (Worker) — 30 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **dbchanges** (Database Changes) _(framework core)_ — 1 doc(s) → [1.0/apps/dbchanges/INDEX.md](1.0/apps/dbchanges/INDEX.md)
|
|
10
10
|
- **worker1.5** (Worker 1.5) — 0 doc(s) → [1.0/apps/worker1.5/INDEX.md](1.0/apps/worker1.5/INDEX.md)
|
|
11
11
|
- **togadesk** (TOGa Desk) — 13 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
| [NYCHH NetSuite → TransferOrders import (stocking-flag routing, PO bridges, origin location)](features/netsuite-transfer-order-import.md) | 1.0 | NYCHH's NetSuite **transfer orders are represented as NetSuite sales orders** (same as the GroWrk pattern), so the shared NetSuite → TOGa Supply importer (`App_ | library/app/api/toga2.php, library/app/api/netsuite/rest.php, library/app/netsuite.php, worker/crons/toga2/netsuite/sync_togasupply_hh.php, worker/crons/toga2/netsuite/common_sync_togasupply.php |
|
|
6
6
|
| [NYCHH PO links are UPSTREAM — the downstream SO→PO route returns empty](features/po-number-upstream-direction.md) | 2.0 | NYCHH's sales orders are created **from the customer's purchase order**, so their SO↔PO links live in the **upstream** table `PurchaseOrders_SalesOrders` (route | _underscore/Model/Client/SalesOrder.php, _underscore/Trait/Netsuite/SalesOrder.php, toga25-supply/src/pages/SalesOrders/view/SalesOrderRecordModalLayout/hooks/usePurchaseOrderDetails.ts, dbchanges2/Client/2026-08-11b - SalesOrderPurchaseOrdersField.sql, dbchanges2/Client/2026-08-25 - SalesOrderPurchaseOrdersFieldAllClients.sql |
|
|
7
7
|
| [NYCHH transfer-order 2.0 model — inventory quantities + V2 field enablement](features/transfer-order-inventory-quantities.md) | 2.0 | The 2.0 (`_underscore`) side of NYCHH transfer-order support: a **two-branch inventory quantity model** on the NYCHH `Item` override, plus the **client-override | _underscore/Model/Nychh/Item.php, _underscore/Model/Nychh/TransferOrder.php, _underscore/Model/Nychh/TransferOrderStage.php, _underscore/Model/Client/TransferOrder.php, dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql, dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql |
|
|
8
|
-
| [NYC Health & Hospitals](profile.md) | 2.0 | NYC Health & Hospitals (NYCHH) is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Nychh`. | dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql, dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql |
|
|
8
|
+
| [NYC Health & Hospitals](profile.md) | 2.0 | NYC Health & Hospitals (NYCHH) is a TOGA 2.0 client on the `_underscore` platform, prod schema `Client_Nychh`. | dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql, dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql, dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql, dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql, dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql, dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql |
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: nychh
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-08-
|
|
9
|
+
updated: 2026-08-28
|
|
10
10
|
owners: [apeterson, bala]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/SalesOrder.php
|
|
@@ -70,10 +70,19 @@ the **upstream** table.
|
|
|
70
70
|
safe **only** because NYCHH's upstream bridge is coincidentally 1:1 (823 rows / 823 distinct sales
|
|
71
71
|
orders). Copying that join into a shared single-record fetch breaks Compass (up to 6,440 POs on one
|
|
72
72
|
order), Compass Canada (empty upstream bridge) and Prudential (1,868 of 26,843 upstream).
|
|
73
|
+
- **The transfer-order items table inherits the same blank.** `TransferOrderItems` has no
|
|
74
|
+
line-level PO, so that column binds the **parent order's** `purchaseOrder.number` and repeats on
|
|
75
|
+
every row — and for NYCHH it resolves NULL, because their PO links are upstream and
|
|
76
|
+
`TransferOrders.purchaseOrderId` is not populated for this tenant. The column is deliberately left
|
|
77
|
+
visible in the Core surface (neutral default; other tenants do populate it). See
|
|
78
|
+
[Transfer Orders page](../../../2.0/apps/toga25-supply/features/transfer-orders-page.md).
|
|
73
79
|
- Do not "fix" this by adding downstream rows. The direction is correct for NYCHH's business model;
|
|
74
80
|
the shared field is what was incomplete.
|
|
75
81
|
|
|
76
82
|
## Change history
|
|
83
|
+
- 2026-08-28 — Noted that the new Transfer Orders items table shows the **order-level** PO
|
|
84
|
+
(`TransferOrderItems` has no line-level PO), so it repeats per row and resolves **NULL for NYCHH**
|
|
85
|
+
for the same upstream-direction reason — left visible in Core as the neutral default. (apeterson)
|
|
77
86
|
- 2026-08-26 — Closed the open `_purchaseOrders` gap: fixed in the **base** field as a
|
|
78
87
|
downstream-then-upstream `COALESCE` (not a NYCHH override), taking NYCHH from 64 to **819 of 819**
|
|
79
88
|
orders with a PO and changing no existing value; currently on `_beta`, not `_production`. Refined
|
|
@@ -15,13 +15,15 @@ project: _Underscore
|
|
|
15
15
|
client: nychh
|
|
16
16
|
type: profile
|
|
17
17
|
status: active
|
|
18
|
-
updated: 2026-08-
|
|
18
|
+
updated: 2026-08-28
|
|
19
19
|
owners: ["jcardinal", "apeterson", "bala"]
|
|
20
20
|
files:
|
|
21
21
|
- dbchanges2/Client_Nychh/2026-08-18 - InventoryUnitsItemColumns.sql
|
|
22
22
|
- dbchanges2/Client_Nychh/2026-08-24 - FixInventoryGroupingsUnitsTopologyOverrideIds.sql
|
|
23
23
|
- dbchanges2/Client_Nychh/2026-08-27a - TransferOrderCustomFieldWritePermission.sql
|
|
24
24
|
- dbchanges2/Client_Nychh/2026-08-27b - TransferOrderStageStatusIdentifier.sql
|
|
25
|
+
- dbchanges2/Client_Nychh/2026-08-28a - TransferOrdersTableView.sql
|
|
26
|
+
- dbchanges2/Client_Nychh/2026-08-28b - TransferOrdersNavigationEnable.sql
|
|
25
27
|
related:
|
|
26
28
|
- ../../2.0/apps/_underscore/features/tracking-number-bridges.md
|
|
27
29
|
- ../../2.0/apps/_underscore/features/tableview-joins.md
|
|
@@ -29,6 +31,7 @@ related:
|
|
|
29
31
|
- ./features/netsuite-transfer-order-import.md
|
|
30
32
|
- ./features/transfer-order-inventory-quantities.md
|
|
31
33
|
- ../../2.0/apps/_underscore/features/sales-order-purchase-order-bridge-direction.md
|
|
34
|
+
- ../../2.0/apps/toga25-supply/features/transfer-orders-page.md
|
|
32
35
|
---
|
|
33
36
|
|
|
34
37
|
## Summary
|
|
@@ -61,6 +64,15 @@ table views. Client-specific DB change-sets live in `dbchanges2/Client_Nychh/`.
|
|
|
61
64
|
arrive as sales orders; the 1.0 importer routes them by the `custbody_stocking_order` flag (not the
|
|
62
65
|
dollar amount), bridges the PO, and resolves origin/destination locations. See
|
|
63
66
|
[NYCHH NetSuite → TransferOrders import](./features/netsuite-transfer-order-import.md).
|
|
67
|
+
- **Transfer Orders is an NYCHH-only screen (2026-08-28, local only).** NYCHH is the first — and
|
|
68
|
+
today the only — tenant with a `transfer-orders` TableView (`Client_Nychh/2026-08-28a`, which also
|
|
69
|
+
seeds the ACL chain for record 351 that the Status column silently depends on) and the one
|
|
70
|
+
`SurfaceOverrides` row that reveals the nav item (`2026-08-28b`, client-wide, matching how this
|
|
71
|
+
tenant already grants Sales Orders and Inventory — NYCHH does not scope navigation by role). The
|
|
72
|
+
Core surfaces and the stage colour tokens are **shared/neutral**, hidden for every other client
|
|
73
|
+
until they opt in. Not yet run on sandbox-client or production; **beta is blocked** because it
|
|
74
|
+
lacks the `TransferOrderStages` table. See
|
|
75
|
+
[Transfer Orders page](../../2.0/apps/toga25-supply/features/transfer-orders-page.md).
|
|
64
76
|
- **Two-branch inventory quantities + TransferOrder V2 enablement** — NYCHH-only on-hand/available/
|
|
65
77
|
fulfilled/backordered model on `_Model_Nychh_Item`, plus the client-override models + ACL rows that
|
|
66
78
|
let a NetSuite TransferOrder POST succeed. See
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
| [Prudential: Dell LCH IOP transmissions (LCHRequestV2)](features/dell-lch-iop-transmissions.md) | 1.0 | Outbound order transmissions from the 1.0 worker tier to Dell's Lifecycle Hub (LCH) ITSM integration. | library/app/api/delllch.php, library/app/apitransaction.php, worker/crons/toga2/prudential/transmissions_to_dell_usa.php, worker/crons/toga2/prudential/transmissions_to_dell_ireland.php, worker/crons/toga2/prudential/transmissions_to_dell_india.php, worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php |
|
|
7
7
|
| [Prudential: Device information import + unit→contact linking (import_device_information.php)](features/device-information-import-and-contact-linking.md) | 1.0 | Prudential's **device-sync** cron (`worker/crons/toga2/prudential/import_device_information.php`) pulls device/asset records (from ServiceNow / the Dell CMDB fe | worker/crons/toga2/prudential/import_device_information.php, worker/crons/toga2/prudential/backfill_unit_contacts.php, dbchanges2/Client_Prudential/2026-07-07 - Contact Dedup Merge.sql |
|
|
8
8
|
| [Prudential: OneUptime order-pipeline backlog monitors (Monitor/Prudential/*)](features/oneuptime-order-pipeline-monitors.md) | 2.0 | Three worker2 OneUptime push monitors (TRUE-80587) that watch the Prudential/Dell order pipeline for **stalls**, which were previously invisible — a stuck pipel | worker2/Worker/Monitor/Prudential.php, worker2/Config/production.ini, dbchanges2/Core/2026-08-07a - Prudential AIG ServiceNow OneUptime monitor crons.sql, dbchanges2/Client_Prudential/2026-04-08 - Insert Customers.sql |
|
|
9
|
+
| [Prudential: order email PDF attachments (which guide goes on which email)](features/order-email-pdf-attachments.md) | 1.0 | Every customer-facing Prudential order email carries S3-hosted PDF guides, and **which** guide is attached is decided by the service request type. | worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php, worker/crons/toga2/prudential/transmissions_to_netsuite.php, worker/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php, worker/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php, worker/crons/toga2/prudential/test_new_hire_email.php |
|
|
9
10
|
| [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, _underscore/Test/Prudential/ServiceRequestTest.php |
|
|
10
11
|
| [Prudential: Service Request rejection alert email](features/service-request-rejection-alert-email.md) | 2.0 | When a Prudential ServiceNow→TOGa service-request submission (`POST /v2/service-requests`) is **rejected by validation**, TOGa now sends a real-time internal al | worker2/Worker/Client/Prudential/reports/ReqRejectionEmail.php, _underscore/Model/Prudential/ServiceRequest.php |
|
|
11
12
|
| [Prudential: Sales Orders CSV export (TOGa 2.5 Supply)](features/supply-orders-csv-export.md) | 2.0 | The **Export** button on the TOGa 2.5 Supply *Sales Orders* page is **Prudential-only**: it downloads a 22-column CSV (`prudential-orders-<YYYY-MM-DD>.csv`) cov | toga25-supply/src/pages/SalesOrders/viewModel/FIELDS/PRUDENTIAL/exportApiFields.json, toga25-supply/src/pages/SalesOrders/api/prudentialExportApi.ts, toga25-supply/src/pages/SalesOrders/hooks/usePrudentialOrdersExport.ts, toga25-supply/src/pages/SalesOrders/SalesOrders.tsx |
|
|
12
|
-
| [Prudential Order Shipped Email — transmit_ordershipped_updates_prudential.php](features/transmit-ordershipped-email.md) | 1.0 | Cron script that transmits "Order Shipped" updates to ServiceNow (RITM) and sends a shipped notification email to the end user. | worker/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php, worker/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php, worker/crons/toga2/prudential/transmit_rejected_cancelled_updates_prudential.php, worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php, worker/crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php, worker/crons/notifications/reports/prudential_exception_report.php |
|
|
13
|
+
| [Prudential Order Shipped Email — transmit_ordershipped_updates_prudential.php](features/transmit-ordershipped-email.md) | 1.0 | Cron script that transmits "Order Shipped" updates to ServiceNow (RITM) and sends a shipped notification email to the end user. | worker/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php, worker/crons/toga2/prudential/transmissions_to_netsuite.php, worker/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php, worker/crons/toga2/prudential/transmit_rejected_cancelled_updates_prudential.php, worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php, worker/crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php, worker/crons/notifications/reports/prudential_exception_report.php |
|
|
13
14
|
| [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`). | |
|
|
14
15
|
| [Prudential: Dell ASN failed POST backfill replay](workflows/dell-asn-backfill-replay.md) | 2.0 | When Dell ASN POSTs fail in bulk (e.g. | |
|
|
15
16
|
| [Prudential — HTTP/2 disabled on the Commerce ALB (proxy workaround) + open re-enable action](workflows/http2-alb-workaround.md) | 2.0 | Prudential users hit **`ERR_HTTP2_PROTOCOL_ERROR`** in Chrome and Edge (both Chromium) loading `https://prudential.togacommerce.com`, while the site worked fine | |
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Prudential: order email PDF attachments (which guide goes on which email)"
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: worker
|
|
5
|
+
project: Worker
|
|
6
|
+
client: prudential
|
|
7
|
+
type: client-feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-28
|
|
10
|
+
owners: ["bala"]
|
|
11
|
+
files:
|
|
12
|
+
- worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php
|
|
13
|
+
- worker/crons/toga2/prudential/transmissions_to_netsuite.php
|
|
14
|
+
- worker/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php
|
|
15
|
+
- worker/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php
|
|
16
|
+
- worker/crons/toga2/prudential/test_new_hire_email.php
|
|
17
|
+
related:
|
|
18
|
+
- transmit-ordershipped-email.md
|
|
19
|
+
- ../profile.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
Every customer-facing Prudential order email carries S3-hosted PDF guides, and **which** guide is
|
|
24
|
+
attached is decided by the service request type. The rule was inconsistent between stages — the
|
|
25
|
+
same request type received different documents depending on whether the email came from
|
|
26
|
+
order-created, shipped, or delivered — and a new hire was being sent the *return* instructions
|
|
27
|
+
instead of a setup guide. As of 2026-08-27 one rule applies at **every** stage:
|
|
28
|
+
|
|
29
|
+
> **New hire → getting-started guides only (Windows 11 + Mac).
|
|
30
|
+
> Reclaim, Breakfix, Swap, Label, Refresh → the return-instructions guide.**
|
|
31
|
+
|
|
32
|
+
Reported by the client (Gary Yerman) against the new-hire order-created email; the fix for that
|
|
33
|
+
specific branch shipped as **TRUE-81393**, and the consistency pass across the other stages
|
|
34
|
+
followed in the same session.
|
|
35
|
+
|
|
36
|
+
## The rule, by stage
|
|
37
|
+
|
|
38
|
+
| Service request type | Order created | Shipped | Delivered |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| New (1) | Win11 + Mac | Win11 + Mac | Win11 + Mac |
|
|
41
|
+
| Reclaim (5) | Return | Return | Return |
|
|
42
|
+
| Breakfix (2) | Win11 + Return | Win11 + Mac + Return | Win11 + Mac + Return |
|
|
43
|
+
| Swap (4) | Win11 + Return | Win11 + Mac + Return | Win11 + Mac + Return |
|
|
44
|
+
| Label (6) | Win11 + Return | Win11 + Mac + Return | Win11 + Mac + Return |
|
|
45
|
+
| Refresh (3) | Win11 + Mac + Return | Win11 + Mac + Return | Win11 + Mac + Return |
|
|
46
|
+
|
|
47
|
+
The load-bearing part is the **Return** column: no non-New type may go out without the return
|
|
48
|
+
guide, and New must never carry it.
|
|
49
|
+
|
|
50
|
+
## Which cron sends which email
|
|
51
|
+
|
|
52
|
+
All four are `active: 1` in `worker/schedules/cron.worker.sync.json`:
|
|
53
|
+
|
|
54
|
+
| Stage | Cron | Branches on |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| Order created | `generate_sales_and_purchase_orders_from_service_requests.php` | `serviceRequestTypeId` (`1`, `5`, `3`, `else`) |
|
|
57
|
+
| Shipped | `transmissions_to_netsuite.php` | type **name** (`$reqType == "New"`, `else`) |
|
|
58
|
+
| Shipped | `transmit_ordershipped_updates_prudential.php` | type **name** (`$reqType == "New"`, `else`) |
|
|
59
|
+
| Delivered | `transmit_closecomplete_updates_prudential.php` | type **name** (`$reqType == "New"`, `else`) |
|
|
60
|
+
|
|
61
|
+
**Two different crons send the shipped email** (`transmissions_to_netsuite.php` and
|
|
62
|
+
`transmit_ordershipped_updates_prudential.php` — both also stamp
|
|
63
|
+
`c_dtTransmittedOrderShippedUpdateToPrudential`). Any attachment change to the shipped email must
|
|
64
|
+
be made in **both**, or the two senders drift apart.
|
|
65
|
+
|
|
66
|
+
The order-created cron switches on the numeric `serviceRequestTypeId`, while the shipped and
|
|
67
|
+
delivered crons switch on the type **name string** read from
|
|
68
|
+
`serviceRequest.serviceRequestType.name` in the TOGa API response. The names match the enum
|
|
69
|
+
exactly (`New`, `Reclaim`), so the string comparisons are safe — but the two styles mean a newly
|
|
70
|
+
added request type lands in the `else` branch everywhere and is never matched by name.
|
|
71
|
+
|
|
72
|
+
## The PDF assets
|
|
73
|
+
|
|
74
|
+
All three live under `https://external-client-files.s3.us-west-2.amazonaws.com/prudential/` and
|
|
75
|
+
all three returned HTTP 200 (verified 2026-08-27). Two of them are **renamed on attach**:
|
|
76
|
+
|
|
77
|
+
| S3 object | Attached to the email as | Size |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `EquipMe-Win11-v1.pdf` | `Getting_Started_Guide_Windows11.pdf` | 773,591 B |
|
|
80
|
+
| `2026_Aug_PrudentialMacSetupGuide_ZCC.pdf` | `PrudentialMacSetupGuide.pdf` | 7,543,154 B |
|
|
81
|
+
| `Prudential_Instruction-2Page-V1.pdf` | (unchanged) | 100,224 B |
|
|
82
|
+
|
|
83
|
+
The Mac guide dominates: a new-hire email is roughly **11 MB** once base64-encoded. Grepping for
|
|
84
|
+
the attached-as filename will not find the S3 object — search the S3 basename.
|
|
85
|
+
|
|
86
|
+
## How to change an attachment safely
|
|
87
|
+
|
|
88
|
+
1. Every fetch goes through the file-scope `safeFetchPdf()` helper, never bare
|
|
89
|
+
`file_get_contents()`. Under the 1.0 framework's `E_ALL` + `App_Error::handleError`, a failed
|
|
90
|
+
S3 pull is converted to an `ErrorException` and **throws at the call site**, killing the cron
|
|
91
|
+
mid-batch before any `!== false` guard can run. Full root cause in
|
|
92
|
+
`transmit-ordershipped-email.md`. `transmissions_to_netsuite.php` was the last file still
|
|
93
|
+
fetching directly and calling `addAttachment()` unconditionally (which would also mail a
|
|
94
|
+
0-byte file under a real guide's name); it was converted 2026-08-27.
|
|
95
|
+
2. Each PDF gets its **own** `if ($pdfX !== false)` guard around the `file_put_contents` +
|
|
96
|
+
`addAttachment` pair — never a joint `&&`. One failed PDF must drop only itself; the email
|
|
97
|
+
always sends.
|
|
98
|
+
3. **Put the return-guide fetch *before* the `if ($reqType != 'Reclaim')` guard** in the shipped
|
|
99
|
+
and delivered crons. Everything inside that guard is skipped for Reclaim — and Reclaim is
|
|
100
|
+
precisely the type that most needs the return instructions. That guard is how Reclaim ended up
|
|
101
|
+
receiving zero attachments.
|
|
102
|
+
|
|
103
|
+
## Testing
|
|
104
|
+
|
|
105
|
+
`crons/toga2/prudential/test_new_hire_email.php` (local, untracked) rebuilds the new-hire email
|
|
106
|
+
verbatim — same subject, same HTML template, same S3 fetches — mails it to a hardcoded
|
|
107
|
+
`$testRecipients` list, and prints each PDF's attached/missing state and byte size before
|
|
108
|
+
sending. It **writes nothing**: no sales order, no purchase order, no api2 call, no SQL. It
|
|
109
|
+
deliberately calls only `App_Framework_Worker::initialize()` and **not**
|
|
110
|
+
`App_Framework::cronInitialization()`, because that INSERTs a `CronJobExecutions` row.
|
|
111
|
+
|
|
112
|
+
Run it from the worker repo's `crons/` directory with the `library` and `_underscore` repos on
|
|
113
|
+
the include path:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
php -d include_path=".;<library>;<_underscore>" toga2/prudential/test_new_hire_email.php
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Gotchas / known gaps
|
|
120
|
+
|
|
121
|
+
- **`prudential_beta/` does not match prod.**
|
|
122
|
+
`crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php` is
|
|
123
|
+
`active: 1` on the same schedule but points at the beta DB and still references the retired
|
|
124
|
+
`Prudential_Return_Instructions.pdf` (and the old `PrudentialMacSetupGuide.pdf`). **A beta test
|
|
125
|
+
will not reproduce prod attachment behavior.** Left as-is deliberately; the developer is aware.
|
|
126
|
+
- **Breakfix / Swap / Label get no Mac guide on the order-created email** (they do get it on
|
|
127
|
+
shipped and delivered). Known, and left alone on purpose — not a bug to "fix" unasked.
|
|
128
|
+
- The delivered cron (`transmit_closecomplete_updates_prudential.php`) already followed the rule
|
|
129
|
+
and was deliberately **not** touched.
|
|
130
|
+
|
|
131
|
+
## Change history
|
|
132
|
+
- 2026-08-27 — Client-reported: the new-hire order-created email attached the return-instructions
|
|
133
|
+
PDF and carried no Mac guide. Swapped it to Win11 + Mac
|
|
134
|
+
(`2026_Aug_PrudentialMacSetupGuide_ZCC.pdf` attached as `PrudentialMacSetupGuide.pdf`) and
|
|
135
|
+
dropped the return doc (TRUE-81393). Then made the rule consistent across every stage: added the
|
|
136
|
+
return guide to the order-created Reclaim branch (previously zero attachments) and to the
|
|
137
|
+
Breakfix/Swap/Label catch-all; added it for every non-New type in **both** shipped crons, placed
|
|
138
|
+
ahead of the `!= 'Reclaim'` guard so Reclaim actually receives it; and removed it from the
|
|
139
|
+
New-hire shipped email in both. Converted the last direct `file_get_contents` PDF fetches in
|
|
140
|
+
`transmissions_to_netsuite.php` to `safeFetchPdf()` with guarded write+attach. Added
|
|
141
|
+
`test_new_hire_email.php` as a write-free manual harness (bala)
|
|
@@ -6,16 +6,18 @@ project: Worker
|
|
|
6
6
|
client: prudential
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: ["rgirish"]
|
|
9
|
+
updated: 2026-08-28
|
|
10
|
+
owners: ["rgirish", "bala"]
|
|
11
11
|
files:
|
|
12
12
|
- worker/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php
|
|
13
|
+
- worker/crons/toga2/prudential/transmissions_to_netsuite.php
|
|
13
14
|
- worker/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php
|
|
14
15
|
- worker/crons/toga2/prudential/transmit_rejected_cancelled_updates_prudential.php
|
|
15
16
|
- worker/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php
|
|
16
17
|
- worker/crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php
|
|
17
18
|
- worker/crons/notifications/reports/prudential_exception_report.php
|
|
18
19
|
related:
|
|
20
|
+
- order-email-pdf-attachments.md
|
|
19
21
|
- ../profile.md
|
|
20
22
|
---
|
|
21
23
|
|
|
@@ -39,9 +41,13 @@ Iterates the same POs collected in Phase 1. For each:
|
|
|
39
41
|
1. Fetches PO details via TOGa API (`GET /purchase-orders/<uuid>`).
|
|
40
42
|
2. Fetches tracking number via TOGa API (`GET /tracking-numbers`).
|
|
41
43
|
3. Builds and sends the shipped email based on `serviceRequestType`:
|
|
42
|
-
- **New** — "Your new hire equipment has shipped"
|
|
43
|
-
- **
|
|
44
|
-
|
|
44
|
+
- **New** — "Your new hire equipment has shipped", Win11 + Mac setup guides.
|
|
45
|
+
- **Everything else** — "Your equipment has been shipped", return-instructions guide for
|
|
46
|
+
every type (including Reclaim), plus Win11 + Mac for the non-Reclaim types.
|
|
47
|
+
|
|
48
|
+
**The attachment set changed on 2026-08-27** — which guide goes on which email, at every
|
|
49
|
+
stage of the order, is now owned by `order-email-pdf-attachments.md`. Read that before
|
|
50
|
+
changing any attachment here.
|
|
45
51
|
4. Stamps `c_dtEmailSentOrderShipped = NOW()` on the PO.
|
|
46
52
|
|
|
47
53
|
## Data model
|
|
@@ -80,6 +86,18 @@ TrackingNumbers WHERE purchaseOrderId = PurchaseOrders.id AND TrackingNumbers.st
|
|
|
80
86
|
orders that genuinely qualified for a delivery email. Over 2026-07-01..07-09 this dropped 6 false
|
|
81
87
|
positives (25 → 19 flagged) while retaining all 19 genuine discrepancies.
|
|
82
88
|
|
|
89
|
+
## A second cron sends the same shipped email
|
|
90
|
+
|
|
91
|
+
`transmissions_to_netsuite.php` (also `active: 1`) builds and sends the **same** shipped email —
|
|
92
|
+
same subjects, same branch shape — and also stamps `c_dtTransmittedOrderShippedUpdateToPrudential`.
|
|
93
|
+
It is easy to miss: it is not named like the other `transmit_*` crons. Any change to the shipped
|
|
94
|
+
email's content or attachments must be applied to **both** files or the two senders drift.
|
|
95
|
+
|
|
96
|
+
It was also the last Prudential cron still calling `file_get_contents()` directly for its PDFs and
|
|
97
|
+
calling `addAttachment()` unconditionally — so a failed S3 pull threw and killed the batch, and a
|
|
98
|
+
false return would have mailed a 0-byte file under a real guide's name. Converted to
|
|
99
|
+
`safeFetchPdf()` with per-PDF guards on 2026-08-27.
|
|
100
|
+
|
|
83
101
|
## Sibling scripts sharing this pattern
|
|
84
102
|
The same two-phase (transmit-then-email) shape and the same PDF-fetch fragility exist in three
|
|
85
103
|
sibling crons, all fixed the same way this session (2026-07-06):
|
|
@@ -175,6 +193,13 @@ stamp (crash hits the next iteration). With multiple New-type POs, a crash on PO
|
|
|
175
193
|
all subsequent POs in the same run.
|
|
176
194
|
|
|
177
195
|
## Change history
|
|
196
|
+
- 2026-08-27 — Extended the `safeFetchPdf()` + per-PDF-guard pattern to
|
|
197
|
+
`transmissions_to_netsuite.php`, the last cron still fetching PDFs with bare
|
|
198
|
+
`file_get_contents()` and attaching unconditionally. Also recorded that this cron is a **second
|
|
199
|
+
sender of the shipped email** alongside `transmit_ordershipped_updates_prudential.php`. The
|
|
200
|
+
shipped email's attachment set was reworked the same day to match the new client-agreed rule
|
|
201
|
+
(New = setup guides only; every other type gets the return guide, Reclaim included) — see
|
|
202
|
+
order-email-pdf-attachments.md (bala)
|
|
178
203
|
- 2026-07-10 — Third regression of the "Order Shipped / Order Delivered Email Not Sent" symptom.
|
|
179
204
|
True trigger: `createAssetAndRetryPut()` called the nonexistent `App_Database::escapeString()`
|
|
180
205
|
(~line 158 in `transmit_ordershipped` + `transmit_closecomplete`) — a fatal `Error` under E_ALL
|
|
@@ -27,6 +27,7 @@ related:
|
|
|
27
27
|
- features/device-information-import-and-contact-linking.md
|
|
28
28
|
- workflows/http2-alb-workaround.md
|
|
29
29
|
- features/supply-orders-csv-export.md
|
|
30
|
+
- features/order-email-pdf-attachments.md
|
|
30
31
|
---
|
|
31
32
|
|
|
32
33
|
## Summary
|
|
@@ -63,7 +64,11 @@ order-status transmissions.
|
|
|
63
64
|
- PO lifecycle is tracked by `purchaseOrderStageId`. The `dtAcknowledged` column is **unused
|
|
64
65
|
(always NULL)** — do not key logic on it.
|
|
65
66
|
|
|
66
|
-
`ServiceRequests.serviceRequestTypeId
|
|
67
|
+
`ServiceRequests.serviceRequestTypeId` (full set, verified against prod `Client_Prudential`
|
|
68
|
+
2026-08-27): **1 = New, 2 = Breakfix, 3 = Refresh, 4 = Swap, 5 = Reclaim, 6 = Label**.
|
|
69
|
+
The order-created cron branches on this id; the shipped/delivered crons branch on the type
|
|
70
|
+
**name** string (`serviceRequest.serviceRequestType.name`), so 4 and 6 only ever reach an
|
|
71
|
+
`else` branch.
|
|
67
72
|
|
|
68
73
|
## Gotchas
|
|
69
74
|
- **Commerce (`prudential.togacommerce.com`):** Prudential's corporate TLS-inspection proxy
|
|
@@ -98,6 +103,8 @@ order-status transmissions.
|
|
|
98
103
|
- features/transmit-ordershipped-email.md
|
|
99
104
|
- features/device-information-import-and-contact-linking.md — device-sync cron, unit→contact
|
|
100
105
|
linking, the "null null" contact-export incident + dedup/backfill remediation.
|
|
106
|
+
- features/order-email-pdf-attachments.md — which PDF guide is attached to which customer
|
|
107
|
+
order email at which stage, the S3 asset list, and the four crons that send them.
|
|
101
108
|
- features/supply-orders-csv-export.md — the Prudential-only Sales Orders CSV export in TOGa 2.5
|
|
102
109
|
Supply (`toga25-supply`): its two queries, why contacts join `SalesOrders.contactId` (not
|
|
103
110
|
`Units.contactId`, NULL until Dell assigns the asset), and the `ServiceRequests_Units` fan-out.
|
package/package.json
CHANGED