toga-ai 1.0.64 → 1.0.66
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/worker/INDEX.md +1 -0
- package/knowledge/1.0/apps/worker/features/send-shipments-for-the-day.md +65 -0
- package/knowledge/INDEX.md +1 -1
- package/knowledge/clients/compass-usa/INDEX.md +1 -0
- package/knowledge/clients/compass-usa/workflows/order-lifecycle-and-data-integrity.md +117 -0
- package/knowledge/clients/prudential/INDEX.md +1 -0
- package/knowledge/clients/prudential/features/dell-asn-units-interceptor.md +35 -4
- package/knowledge/clients/prudential/workflows/dell-asn-backfill-replay.md +70 -0
- package/package.json +1 -1
|
@@ -4,3 +4,4 @@
|
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [Worker (1.0 Framework) Architecture](architecture.md) | `worker` is the legacy (**1.0** `App_` framework) **background-job tier**. | worker/index.php, worker/_/app/framework.php, worker/crons/, worker/schedules/, worker/ebs/cron.worker.php, worker/.ebextensions/035_cron.worker.config |
|
|
6
6
|
| [Forecast2 ↔ NetSuite Reconciliation & Trueup Tooling](features/forecast2-netsuite-reconciliation.md) | CLI tools to **audit** and **repair** drift between the production `Forecast` DB (core2) and NetSuite. | test/@dave/reconcile_netsuite_totals.php, test/@dave/analyze_netsuite_forecast_diff.php, test/@dave/trueup_sales.php, test/@dave/trueup_open_orders.php, test/@dave/trueup_opportunities.php, test/@dave/probe_sales_gap_direct.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
7
|
+
| [Prudential: Send Shipments for the Day report (daily cron)](features/send-shipments-for-the-day.md) | Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all devices shipped that day, including tracking number, serial number, emp | worker/crons/notifications/reports/send_shipments_for_the_day.php |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Prudential: Send Shipments for the Day report (daily cron)"
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: worker
|
|
5
|
+
project: Worker
|
|
6
|
+
client: prudential
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-12
|
|
10
|
+
owners: ["rgirish"]
|
|
11
|
+
files:
|
|
12
|
+
- worker/crons/notifications/reports/send_shipments_for_the_day.php
|
|
13
|
+
related:
|
|
14
|
+
- ../../../clients/prudential/features/dell-asn-units-interceptor.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Summary
|
|
18
|
+
|
|
19
|
+
Daily cron (9:00 PM) that emails Prudential and Dell stakeholders an Excel report of all
|
|
20
|
+
devices shipped that day, including tracking number, serial number, employee name/XID, item
|
|
21
|
+
description, FedEx status, and vendor.
|
|
22
|
+
|
|
23
|
+
## Key files / entry points
|
|
24
|
+
|
|
25
|
+
- `crons/notifications/reports/send_shipments_for_the_day.php` — self-contained cron script.
|
|
26
|
+
Scheduled via `schedules/cron.worker.notification.json`.
|
|
27
|
+
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
1. Queries `Client_Prudential` DB joining `AdvanceShippingNotices` → items → units → tracking
|
|
31
|
+
bridge → `TrackingNumbers` → `Units` → `Items` → `Contacts`, filtered to `dateShipped = CURDATE()`.
|
|
32
|
+
2. For each unit, calls `App_Api_Carrier_FedExApi::getStatus()` to get live carrier status.
|
|
33
|
+
3. Builds an `.xlsx` workbook (PhpSpreadsheet) with 8 columns: Name, Employee XID, Device Serial
|
|
34
|
+
Number, Description, Tracking Number, Tracking Number Status, Shipping Carrier Updates, Vendor Name.
|
|
35
|
+
4. Emails the file to Prudential/Dell contacts + BCC to internal ops.
|
|
36
|
+
5. If no shipments found, sends a "No Shipments for the Day" notification instead.
|
|
37
|
+
|
|
38
|
+
## Data model (join chain)
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
AdvanceShippingNotices
|
|
42
|
+
→ AdvanceShippingNoticeItems (advanceShippingNoticeId)
|
|
43
|
+
→ PurchaseOrders (AdvanceShippingNotices.purchaseOrderId)
|
|
44
|
+
→ SalesOrders_PurchaseOrders (purchaseOrderId)
|
|
45
|
+
→ SalesOrders (salesOrderId)
|
|
46
|
+
→ Vendors (PurchaseOrders.vendorId)
|
|
47
|
+
→ AdvanceShippingNoticeItemUnits (advanceShippingNoticeItemId)
|
|
48
|
+
→ AdvanceShippingNoticeItemUnits_TrackingNumbers (advanceShippingNoticeItemUnitId)
|
|
49
|
+
→ TrackingNumbers (trackingNumberId)
|
|
50
|
+
→ Units (AdvanceShippingNoticeItemUnits.unitId)
|
|
51
|
+
→ Items (Units.itemId)
|
|
52
|
+
LEFT JOIN Contacts (SalesOrders.contactId)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Gotchas
|
|
56
|
+
- The join chain changed in Jun 2026 when `AdvanceShippingNoticeUnits` was renamed to
|
|
57
|
+
`AdvanceShippingNoticeItemUnits` and tracking was moved to the bridge table
|
|
58
|
+
`AdvanceShippingNoticeItemUnits_TrackingNumbers`. If the query returns no rows unexpectedly,
|
|
59
|
+
verify these two tables exist and have data — they are the migration point.
|
|
60
|
+
- `GROUP BY AdvanceShippingNotices.id` is intentional — one row per ASN even if multi-unit.
|
|
61
|
+
The report shows one tracking number per ASN row (the first joined); this is by design.
|
|
62
|
+
|
|
63
|
+
## Change history
|
|
64
|
+
- 2026-06-12 — Updated join chain: `AdvanceShippingNoticeUnits` → `AdvanceShippingNoticeItemUnits`
|
|
65
|
+
+ added `AdvanceShippingNoticeItemUnits_TrackingNumbers` bridge join after DB migration. (rgirish)
|
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)_ — 4 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
|
-
- **worker** (Worker) —
|
|
8
|
+
- **worker** (Worker) — 4 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
|
|
10
10
|
## 2.0 framework
|
|
11
11
|
|
|
@@ -6,3 +6,4 @@
|
|
|
6
6
|
| [Compass: Item-Fulfillment TableViews (for-sales-order-items & for-sales-orders, tracking via bridge)](features/item-fulfillment-tracking-tableview.md) | 2.0 | Two sibling Compass TableViews in `Client_Compass` display fulfilled items in toga2-supply, both driven by `TableViews` / `TableViewJoins` / `TableViewFields` c | dbchanges2/Client_Compass/2026-06-10 - ItemFulfillmentsForSalesOrderItemsTableView.sql, dbchanges2/Client_Compass/2026-06-11 - ItemFulfillmentsForSalesOrdersTableView.sql |
|
|
7
7
|
| [Compass MITS PO → SO Item Linking](features/mits-po-to-so-item-linking.md) | 2.0 | MITS sends Compass inbound Purchase Orders (`POST /v2/purchase-orders`) against a Sales Order (`mitsSalesOrder`). | _underscore/Model/Compass/PurchaseOrder.php |
|
|
8
8
|
| [Compass USA](profile.md) | 2.0 | Compass USA is a TOGA client running a multi-tier supply-chain commerce operation. | |
|
|
9
|
+
| [Compass Order Lifecycle & Data-Integrity Invariants](workflows/order-lifecycle-and-data-integrity.md) | 2.0 | End-to-end map of how a Compass order flows through the `Client_Compass` (2.0) database and the **expected raw-data shape** at each link/ASN/IF level. | |
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compass Order Lifecycle & Data-Integrity Invariants
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
project: _Underscore
|
|
5
|
+
client: compass-usa
|
|
6
|
+
type: workflow
|
|
7
|
+
status: active
|
|
8
|
+
updated: 2026-06-12
|
|
9
|
+
owners: ["jcardinal"]
|
|
10
|
+
files: []
|
|
11
|
+
related:
|
|
12
|
+
- clients/compass-usa/profile.md
|
|
13
|
+
- clients/compass-usa/features/asn-to-item-fulfillment.md
|
|
14
|
+
- clients/compass-usa/features/mits-po-to-so-item-linking.md
|
|
15
|
+
- clients/compass-usa/features/item-fulfillment-tracking-tableview.md
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
End-to-end map of how a Compass order flows through the `Client_Compass` (2.0) database and the
|
|
21
|
+
**expected raw-data shape** at each link/ASN/IF level. This is the reference for diagnosing and
|
|
22
|
+
retroactively repairing the order data, where 50+ historical bugs have left links, ASNs, and item
|
|
23
|
+
fulfillments out of the shape the workflow should produce. All facts below were verified against the
|
|
24
|
+
live `prod` / `Client_Compass` schema.
|
|
25
|
+
|
|
26
|
+
## The chain (supply direction, by customerId / vendorId)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
Compass customer SO (SalesOrders.customerId = 2, number SA/MA/MR)
|
|
30
|
+
--SalesOrders_PurchaseOrders--> MITS PO (PurchaseOrders.customerId = 2, vendorId IN (1,26,25))
|
|
31
|
+
--PurchaseOrders_SalesOrders--> Office Depot SO (customerId = 1)
|
|
32
|
+
--SalesOrders_PurchaseOrders--> Office Depot PO (vendorId = 1)
|
|
33
|
+
--PurchaseOrders_SalesOrders--> Agilant/NetSuite SO (customerId = 3)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **SA** orders are user-created in Compass then sent to MITS; **MR** orders are created
|
|
37
|
+
retroactively from the inbound MITS PO (they do not originate as Compass-entered SOs); MA exists too.
|
|
38
|
+
Structurally MR uses the same bridges as SA.
|
|
39
|
+
- One Compass SO item can split into multiple PO items (bundles / `c_isConfiguration`,
|
|
40
|
+
`parentSalesOrderItemId`, `bundleId`).
|
|
41
|
+
|
|
42
|
+
## Item-link bridges & the purity rule
|
|
43
|
+
|
|
44
|
+
- `SalesOrderItems_PurchaseOrderItems(salesOrderItemId, purchaseOrderItemId)` — a SO item → its PO item.
|
|
45
|
+
- `PurchaseOrderItems_SalesOrderItems(purchaseOrderItemId, salesOrderItemId)` — a PO item → its downstream SO item.
|
|
46
|
+
- Item identity: `PurchaseOrderItems.vendorItemId → VendorItems.itemId`. **`PurchaseOrderItems` has NO
|
|
47
|
+
`salesOrderItemId` column** — POI↔SOI is resolvable ONLY through these two bridges.
|
|
48
|
+
- **PURE link ⇔ `SalesOrderItems.itemId = linked POI's VendorItems.itemId`. SPURIOUS ⇔ they differ.**
|
|
49
|
+
Spurious links (the lineNumber-match bug, see mits-po-to-so-item-linking) cause phantom over-fulfillment.
|
|
50
|
+
- **Many-to-one is legitimate**, not spurious — several SOIs may link to one POI
|
|
51
|
+
(e.g. `PurchaseOrderItems_SalesOrderItems.purchaseOrderItemId = 174808` has 6 SOIs). Never treat
|
|
52
|
+
multiplicity as corruption; the only spuriousness test is the itemId mismatch.
|
|
53
|
+
|
|
54
|
+
## Two fulfillment flows (different expected IF shapes)
|
|
55
|
+
|
|
56
|
+
- **Flow A — direct ASN→IF** (MITS PO vendor in {25,26}, e.g. Strategic Systems; no Agilant leg):
|
|
57
|
+
an ASN against the MITS PO produces an ItemFulfillment on the Compass SO. Serialized units come
|
|
58
|
+
from the ASN units.
|
|
59
|
+
- **Flow B — Office Depot / NetSuite** (MITS PO vendor 1, with ODP SO/PO + Agilant SO): the
|
|
60
|
+
fulfillment **originates on the Agilant IF** (created by NetSuite sync; `c_netsuiteInternalItemFulfillmentId`
|
|
61
|
+
set) and **mirrors UP the chain**. Units come from NetSuite inventory assignment, NOT the ASN
|
|
62
|
+
(ODP ASN units are frequently tracking-only, `unitId` NULL).
|
|
63
|
+
|
|
64
|
+
### Upstream mirror direction (verified from real rows)
|
|
65
|
+
The **Compass-SO IF is the TOP** (`upstreamItemFulfillmentId = NULL`). The ODP IF's
|
|
66
|
+
`upstreamItemFulfillmentId` points to the Compass IF; the Agilant IF's points to the ODP IF. The
|
|
67
|
+
back-link chain climbs **Agilant → ODP → Compass**. Item back-links use
|
|
68
|
+
`ItemFulfillmentItems.upstreamItemFulfillmentItemId` the same direction and may be many-downstream →
|
|
69
|
+
one-upstream for bundles.
|
|
70
|
+
|
|
71
|
+
## Expected raw-data invariants (for detect-and-repair)
|
|
72
|
+
|
|
73
|
+
1. **Links:** every SOI that should be procured has exactly one PURE bridge to the matching POI on the
|
|
74
|
+
correct PO; spurious (itemId-mismatch) bridges should not exist; the full header chain
|
|
75
|
+
(SalesOrders_PurchaseOrders / PurchaseOrders_SalesOrders) should be intact at each present layer.
|
|
76
|
+
2. **Never over-fulfill:** `SUM(ItemFulfillmentItems.quantity)` per SOI must be `≤ SalesOrderItems.quantity`.
|
|
77
|
+
A shipped POI fanning out to many linked SOIs must not produce IF items totaling more than ordered.
|
|
78
|
+
3. **ASN/IF tracking is maintained at all three levels and rolls up:** a tracking number on a unit must
|
|
79
|
+
also be linked at the item level and the header level — on BOTH the ASN side
|
|
80
|
+
(`AdvanceShippingNoticeItemUnits_TrackingNumbers` → `AdvanceShippingNoticeItems_TrackingNumbers` →
|
|
81
|
+
`AdvanceShippingNotices_TrackingNumbers`) and the IF side
|
|
82
|
+
(`ItemFulfillmentItemUnits_TrackingNumbers` → `ItemFulfillmentItems_TrackingNumbers` →
|
|
83
|
+
`ItemFulfillments_TrackingNumbers`). Always link existing `TrackingNumbers`; never create them.
|
|
84
|
+
4. **Legacy stage:** a shipped IF (has items) with `itemFulfillmentStageId IS NULL` should be set to 3
|
|
85
|
+
("Shipped"). Stage 3 = Shipped; stages 1/2 are unused in prod.
|
|
86
|
+
5. **Mirror back-links:** every IF on a non-source SO (ODP/Agilant) should have
|
|
87
|
+
`upstreamItemFulfillmentId` set, and each of its items `upstreamItemFulfillmentItemId` set.
|
|
88
|
+
|
|
89
|
+
## Verified schema corrections (older code/scripts assume these wrongly)
|
|
90
|
+
- **`ItemFulfillmentPackages` does NOT exist** — header IF tracking is `ItemFulfillments_TrackingNumbers`.
|
|
91
|
+
- `ItemFulfillmentItemUnits` has **no `trackingNumberId`** — unit tracking is the bridge
|
|
92
|
+
`ItemFulfillmentItemUnits_TrackingNumbers`.
|
|
93
|
+
- ASN unit table is `AdvanceShippingNoticeItemUnits` (`unitId` nullable = tracking-only).
|
|
94
|
+
- `ItemFulfillments.number` is UNIQUE NOT NULL; `dateItemFulfillment` NOT NULL.
|
|
95
|
+
|
|
96
|
+
## Systems involved
|
|
97
|
+
`Client_Compass` (2.0) tables; the 1.0 worker crons under `worker/crons/toga2/compass/workflow/`
|
|
98
|
+
(transmit-to-MITS, transmit-to-vendors, ODP EDI import, Strategic Systems ASN import, NetSuite sync);
|
|
99
|
+
`api2` cXML ShipNotice handler; the `_underscore` recursive item-fulfillment engine.
|
|
100
|
+
|
|
101
|
+
## Retrofix tooling
|
|
102
|
+
A standalone repair script lives in the worker 1.0 test area (`test/@jeff/compass/retrofix.php`,
|
|
103
|
+
machine-local path tracked in dev memory). It sweeps Compass SOs newest-first, detects deviations from
|
|
104
|
+
the invariants above, and repairs via direct SQL on `db_prod2_compass`. Safety rules baked in: rehearsal
|
|
105
|
+
mode (logs intended writes, rolls back), per-phase gating, a hard block on any write to the
|
|
106
|
+
`TrackingNumbers` table, and the never-over-fulfill cap. It is a diagnostic/repair tool, not part of the
|
|
107
|
+
runtime workflow.
|
|
108
|
+
|
|
109
|
+
## Edge cases & escalation
|
|
110
|
+
- Incomplete orders (no PO/ASN/Agilant leg yet) are normal — repair only the layers that exist.
|
|
111
|
+
- Logs for confirming original payloads: `Logs_Compass.Api` (inbound MITS POs apiId=2; inbound cXML
|
|
112
|
+
ShipNotices), legacy `Logs.API` (outbound transmits), legacy `Logs.FileLog` (`ODP_EDI`, ~30-day retention).
|
|
113
|
+
- High-multiplier over-fulfillment (5×–20×) does not fit the split-PO spurious-link pattern — separate cause.
|
|
114
|
+
|
|
115
|
+
## Change history
|
|
116
|
+
- 2026-06-12 — Documented full lifecycle, both fulfillment flows, verified upstream-mirror direction,
|
|
117
|
+
the expected-shape invariants, and the retrofix tool (jcardinal)
|
|
@@ -4,3 +4,4 @@
|
|
|
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
6
|
| [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
|
+
| [Prudential: Dell ASN failed POST backfill replay](workflows/dell-asn-backfill-replay.md) | 2.0 | When Dell ASN POSTs fail in bulk (e.g. | |
|
|
@@ -5,8 +5,8 @@ project: _Underscore
|
|
|
5
5
|
client: prudential
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
9
|
-
owners: ["jcardinal"]
|
|
8
|
+
updated: 2026-06-12
|
|
9
|
+
owners: ["jcardinal", "rgirish"]
|
|
10
10
|
files:
|
|
11
11
|
- _underscore/Model/Prudential/AdvanceShippingNotice.php
|
|
12
12
|
- dbchanges2/Client_Prudential/2026-06-10 - AsnUnitsInterceptor.sql
|
|
@@ -28,7 +28,9 @@ interceptor translates it on the way in.
|
|
|
28
28
|
- **`Model/Prudential/AdvanceShippingNotice.php::prePost(&$api, &$payload)`** — for each
|
|
29
29
|
`$payload->advanceShippingNoticeItems[]`: renames the legacy `advanceShippingNoticeUnits` key to
|
|
30
30
|
`advanceShippingNoticeItemUnits`, and lifts each unit's flat `trackingNumber` / `returnTrackingNumber`
|
|
31
|
-
into a single `advanceShippingNoticeItemUnitTrackingNumbers` bridge-child row
|
|
31
|
+
into a single `advanceShippingNoticeItemUnitTrackingNumbers` bridge-child row using the FK field names
|
|
32
|
+
`trackingNumberId` / `returnTrackingNumberId` (not the plain field names — the engine resolves FK
|
|
33
|
+
children by field name ending in `Id`).
|
|
32
34
|
- **Registration** — `Client_Prudential.ApiPayloadInterceptors` row: `recordId = 55`
|
|
33
35
|
(advance-shipping-notices), `prePostProcessing = 'PRE'`, `httpMethod = 'POST'`, `apiId = 2` (Dell),
|
|
34
36
|
`isActive = 1`. The engine resolves `_Model_Client_AdvanceShippingNotice` → `_Model_Prudential_AdvanceShippingNotice`
|
|
@@ -40,12 +42,41 @@ advanceShippingNoticeItems: [ { quantity, advanceShippingNoticeUnits: [
|
|
|
40
42
|
{ trackingNumber:{number}, returnTrackingNumber:{number}, unit:{serialNumber} } ] } ]
|
|
41
43
|
```
|
|
42
44
|
The interceptor rewrites each item to `advanceShippingNoticeItemUnits` with the tracking moved into
|
|
43
|
-
`advanceShippingNoticeItemUnitTrackingNumbers`.
|
|
45
|
+
`advanceShippingNoticeItemUnitTrackingNumbers` as `{ trackingNumberId: {number:...}, returnTrackingNumberId: {number:...} }`.
|
|
46
|
+
|
|
47
|
+
## Required DB config (`Core.RecordFields`)
|
|
48
|
+
|
|
49
|
+
The bridge record's FK fields must have `childPolicy = MATCH_CREATE` — otherwise the engine throws
|
|
50
|
+
`EV-12` when the `TrackingNumbers` row doesn't exist yet (Dell always sends new tracking numbers):
|
|
51
|
+
|
|
52
|
+
```sql
|
|
53
|
+
-- trackingNumberId on advance-shipping-notice-item-unit-tracking-numbers (id=1437)
|
|
54
|
+
UPDATE Core.RecordFields SET childPolicy = 'MATCH_CREATE' WHERE id = 1437;
|
|
55
|
+
-- returnTrackingNumberId on same record (id=2198)
|
|
56
|
+
UPDATE Core.RecordFields SET childPolicy = 'MATCH_CREATE' WHERE id = 2198;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`MATCH_CREATE` = look up existing `TrackingNumbers` row by `number` (isIdentifier=1), create if not
|
|
60
|
+
found. `MATCH` (the default) errors when no row exists — that was the root cause of the Jun 2026
|
|
61
|
+
`EV-12` outage.
|
|
44
62
|
|
|
45
63
|
## Gotchas
|
|
46
64
|
- Scoped to `apiId = 2` so other (internal) Prudential callers — which already send the new shape —
|
|
47
65
|
are not double-transformed.
|
|
66
|
+
- The interceptor must use **`trackingNumberId` / `returnTrackingNumberId`** (FK field names) on the
|
|
67
|
+
bridge child row — NOT `trackingNumber` / `returnTrackingNumber`. Using the plain names causes `EV-12`
|
|
68
|
+
because the engine treats them as unknown field lookups against `TrackingNumbers.number` with `MATCH`
|
|
69
|
+
policy and errors when no row is found.
|
|
48
70
|
- DB change lives in `dbchanges2/Client_Prudential/`.
|
|
71
|
+
- If Dell ASN POSTs fail in bulk, replay them from `Logs_Prudential.Api` — see the Dell ASN backfill
|
|
72
|
+
replay workflow doc.
|
|
73
|
+
|
|
74
|
+
## Change history
|
|
75
|
+
- 2026-06-12 — Fixed interceptor bug: bridge row keys were `trackingNumber`/`returnTrackingNumber`
|
|
76
|
+
instead of `trackingNumberId`/`returnTrackingNumberId`, causing EV-12 on all Dell ASN POSTs. Also
|
|
77
|
+
set `Core.RecordFields childPolicy = MATCH_CREATE` on ids 1437 and 2198. Replayed 28 failed payloads
|
|
78
|
+
from `Logs_Prudential.Api`. (rgirish)
|
|
49
79
|
|
|
50
80
|
## Related docs
|
|
51
81
|
- 2.0 _underscore: Tracking-Number Bridge Migration.
|
|
82
|
+
- Prudential: Dell ASN backfill replay workflow.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Prudential: Dell ASN failed POST backfill replay"
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
project: API
|
|
5
|
+
client: prudential
|
|
6
|
+
type: workflow
|
|
7
|
+
status: active
|
|
8
|
+
updated: 2026-06-12
|
|
9
|
+
owners: ["rgirish"]
|
|
10
|
+
files: []
|
|
11
|
+
related:
|
|
12
|
+
- ../features/dell-asn-units-interceptor.md
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Summary
|
|
16
|
+
|
|
17
|
+
When Dell ASN POSTs fail in bulk (e.g. after a DB migration or interceptor bug), this workflow
|
|
18
|
+
replays the failed payloads from the `Logs_Prudential.Api` log table using a fresh auth token.
|
|
19
|
+
Used Jun 2026 after the `EV-12` tracking-number bug to backfill 28 missed shipments.
|
|
20
|
+
|
|
21
|
+
## Steps
|
|
22
|
+
|
|
23
|
+
1. **Confirm the root cause is fixed** before replaying — replaying into a broken system just
|
|
24
|
+
adds more failed log rows. Verify the interceptor fix and any `Core.RecordFields` DB changes
|
|
25
|
+
are applied to production.
|
|
26
|
+
|
|
27
|
+
2. **Pull failed payloads from logs:**
|
|
28
|
+
```sql
|
|
29
|
+
SELECT id, dtStamp, transactionId, responseCode, requestPayload
|
|
30
|
+
FROM Logs_Prudential.Api
|
|
31
|
+
WHERE route LIKE '%advance-shipping%'
|
|
32
|
+
AND method = 'POST'
|
|
33
|
+
AND responseCode != 200
|
|
34
|
+
ORDER BY id DESC
|
|
35
|
+
LIMIT 28;
|
|
36
|
+
```
|
|
37
|
+
Adjust `LIMIT` and add a `dtStamp >= '...'` filter to scope to the incident window.
|
|
38
|
+
|
|
39
|
+
3. **Get a fresh Dell API auth token** (the original `transactionId`s are already consumed —
|
|
40
|
+
each replay needs a new unique `transactionId`). The Dell API credentials (`client`, `api`,
|
|
41
|
+
`secret` UUIDs) are stored in `Client_Prudential.Apis` (id=2) — do not paste values here.
|
|
42
|
+
|
|
43
|
+
4. **Test with the first payload only** — confirm `isSuccess: true` and `status: 201` before
|
|
44
|
+
continuing with the rest.
|
|
45
|
+
|
|
46
|
+
5. **Replay all remaining payloads** using a script (Python recommended — shell array handling
|
|
47
|
+
breaks on multi-unit payloads with special characters). Generate a fresh UUID per request.
|
|
48
|
+
Log each result as `[N/total] OK` or `FAIL` with the error.
|
|
49
|
+
|
|
50
|
+
6. **Verify** by checking `Logs_Prudential.Api` — successful replays appear with `responseCode = 201`
|
|
51
|
+
and new `transactionId`s distinct from the original failed ones.
|
|
52
|
+
|
|
53
|
+
## Systems involved
|
|
54
|
+
|
|
55
|
+
- `Logs_Prudential.Api` — source of failed payloads
|
|
56
|
+
- `https://api.togahub.com/v2/advance-shipping-notices` — replay target
|
|
57
|
+
- `Core.RecordFields` — `childPolicy` config (must be `MATCH_CREATE` on ids 1437 and 2198)
|
|
58
|
+
- `_underscore/Model/Prudential/AdvanceShippingNotice.php` — PRE interceptor
|
|
59
|
+
|
|
60
|
+
## Edge cases & escalation
|
|
61
|
+
|
|
62
|
+
- **Token expires mid-run** (access token valid 1 hour): re-auth and resume from the first
|
|
63
|
+
failed item — already-created records are not duplicated.
|
|
64
|
+
- **`EV-5` duplicate transactionId**: payload was already successfully processed. Skip it.
|
|
65
|
+
- **`EV-12` still firing after fix**: `Core.RecordFields childPolicy` change may not have
|
|
66
|
+
cleared the config cache — wait a minute, then retry.
|
|
67
|
+
- **`Box` serial numbers**: valid — some multi-unit shipments use `serialNumber: "Box"`.
|
|
68
|
+
|
|
69
|
+
## Change history
|
|
70
|
+
- 2026-06-12 — Created after replaying 28 failed Dell ASN POSTs from Jun 11 2026 incident. (rgirish)
|
package/package.json
CHANGED