toga-ai 1.0.115 → 1.0.116

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.
@@ -80,6 +80,14 @@ None — uniform (platform-wide Forecast2 sync).
80
80
  - **REST shape ≠ SOAP shape.** The cron reads the SOAP-shim shape; this handler reads the REST record
81
81
  (`status->refName`, line `quantityBilled`, `class->refName`, `entity->id`, `salesRep->id`,
82
82
  `shippingCost`). Verified against live orders via `test/@dave/probe_salesorder_rest_shape.php`.
83
+ - **REST OMITS `rate` for a $0 line — treat missing/non-numeric rate as `0`, don't skip the line.**
84
+ A $0-priced line comes through SOAP as `rate = 0` (numeric); the cron computes `revenue = 0`,
85
+ `profit = −qtyOpen × unitCost`, and — since profit ≠ 0 — **inserts** the row (tracking open *cost* at
86
+ zero revenue). REST instead **leaves `rate` out entirely**, so an early `if (!is_numeric($rate)) continue;`
87
+ silently drops the whole class of rows. **Prod has 575 such rows** (`revenue = 0`, profit ≠ 0), so this
88
+ was real data loss. Fix (2026-06-17): `$unitPrice = is_numeric($line->rate ?? null) ? (float)$line->rate : 0.0;`
89
+ — the genuine filter is the both-zero check (`revenue == 0 && profit == 0`), not rate presence. Caught
90
+ live by editing a $0 test SO (7163257 → revenue 0, profit −105).
83
91
  - **Three deliberate departures from the legacy cron (all intentional):**
84
92
  1. **No date-window gate.** The cron flips `isOrderOpen=false` for tranDate outside −365d/+90d
85
93
  (`common_import_…:1753`) to bound its windowed scan. Irrelevant to a single-id webhook — dropped.
@@ -99,6 +107,18 @@ None — uniform (platform-wide Forecast2 sync).
99
107
  before *every* action — keeping it would couple the REST import to SOAP config. The push methods
100
108
  (`Create`/`Update`/`Sync`) self-construct `NetSuiteService`, so push is unaffected and the Forecast
101
109
  DB is registered globally in `_.php`.
110
+ - **Local testing — the webhook path hides errors; run the action directly to see them.** A real NS
111
+ edit reaches the local worker via the legacy `{action,parameters}` envelope, and `_Worker_NetSuite::Webhook`
112
+ dispatches the per-record action through `_Worker::runTask()`, whose **debug-mode self-POST swallows the
113
+ sub-action result** (you get `Successfully Executed: ok` from the *router* even when the import threw).
114
+ To see the truth, POST the sub-action straight to the worker and read the response:
115
+ `curl -X POST http://worker2/ -d '{"action":"Netsuite/SalesOrder/PUT","parameters":{"internalId":<id>}}'`.
116
+ - **Local `Forecast.Items` is a partial/stale copy → the "unknown item" guard throws.** The importer
117
+ (correctly) throws `Forecast.Items has no row for NetSuite item <id>` when a line's item isn't local;
118
+ prod keeps Items current (hourly import) so it won't, but local testing of an arbitrary SO often hits
119
+ this. Pre-seed the missing item locally (copy the row from the prod reader) or test that SO against prod.
120
+ - **Local worker2 writes to the DB its config points at — not prod.** With `[database] hostname = localhost`,
121
+ rows land in **local** `Forecast.OpenOrderItems`; verify there, not on the prod reader.
102
122
 
103
123
  ## Related work
104
124
 
@@ -111,6 +131,11 @@ and are a candidate to extract into a shared `_Component_Forecast_Db` before the
111
131
 
112
132
  ## Change history
113
133
 
134
+ - 2026-06-17 — **Fixed dropped zero-revenue/open-cost lines.** REST omits `rate` for $0 lines, and the
135
+ `if (!is_numeric($rate)) continue;` guard was skipping them — but the cron inserts these (profit =
136
+ −qtyOpen × unitCost; 575 such rows in prod). Now defaults missing/non-numeric rate to 0 so the both-zero
137
+ filter alone decides. Verified e2e from a real NS edit: 7162297 → $3,698, 7163257 → revenue 0/profit −105.
138
+ Added local-testing gotchas (webhook debug-swallow; stale local Items guard; local-DB write target). (dfranks)
114
139
  - 2026-06-17 — Initial open-orders importer merged into `_Worker_Netsuite_SalesOrder` (TRUE-79142):
115
140
  REST-only, no date-window gate, no shipping line, cascade bug fixed. (dfranks)
116
141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.115",
3
+ "version": "1.0.116",
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",