toga-ai 1.0.234 → 1.0.235
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.
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
| [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind TOGa Supply's Fulfill & Ship: buying a carrier label (UPS/FedEx), persisting it, and creating the NetSuite Item Fulfillment with tracki | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillments/TrackingNumber.php, _underscore/Component/Library/LabelPdf/LabelPdf.php, _underscore/Component/Library/Carriers/Ups/Ups.php, _underscore/Component/Library/Carriers/Fedex/Fedex.php, _underscore/Trait/Netsuite/ItemFulfillment.php, _underscore/Trait/Netsuite/SalesOrder.php, _underscore/Component/Library/NetSuite/NetSuite.php, _underscore/Model/Client/TrackingNumber.php, _underscore/Model/Client/ShippingMethod.php, _underscore/Model.php, _underscore/Cloud.php |
|
|
9
9
|
| [Client Email Template Sending](features/email-template-sending.md) | `_Model_Client_EmailTemplate` sends a stored, client-defined email template by UUID. | _underscore/Model/Client/EmailTemplate.php, _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php, _underscore/Email.php |
|
|
10
10
|
| [Record-Changed Event Publishing (_Event::publish to SQS)](features/event-publish-sqs.md) | `_Event::publish()` (in `_underscore/Event.php`) is the PHP side of the real-time event pipeline. | _underscore/Event.php |
|
|
11
|
-
| [Forecast.Sales NetSuite import engine (real-time webhook)](features/forecast-sale-import.md) | Real-time importer that takes a NetSuite **sale** record and writes its lines into `Forecast.Sales` (the Forecast2 revenue table). | _underscore/Component/Forecast/SaleImport/SaleImport.php, _underscore/Component/Forecast/Db/Db.php, _underscore/Component/Api/Netsuite/Netsuite.php, worker2/Worker/Netsuite/Invoice.php, worker2/Worker/Netsuite/CashSale.php, worker2/Worker/Netsuite/CreditMemo.php, worker2/Worker/Netsuite/CashRefund.php, worker2/Worker/Netsuite/JournalEntry.php, worker2/Worker/Netsuite/Opportunity.php, worker2/Worker/Netsuite/SalesOrder.php, dbchanges2/Forecast/2026-06-26a - Add journalEntry to Sales transaction type enum.sql, test/@dave/test_invoice_lifecycle.php, test/@dave/test_je_lifecycle.php, test/@dave/test_creditmemo_lifecycle.php, test/@dave/test_cashsale_lifecycle.php, test/@dave/test_cashrefund_lifecycle.php, test/@dave/test_fetchrecord_routes.php, test/@dave/verify_je_classification.php, test/@dave/probe_je_accounts.php, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/NetSuite/api-message-queue/dev_ue_api_msg_queue_enqueue.js |
|
|
11
|
+
| [Forecast.Sales NetSuite import engine (real-time webhook)](features/forecast-sale-import.md) | Real-time importer that takes a NetSuite **sale** record and writes its lines into `Forecast.Sales` (the Forecast2 revenue table). | _underscore/Component/Forecast/SaleImport/SaleImport.php, _underscore/Component/Forecast/Db/Db.php, _underscore/Component/Api/Netsuite/Netsuite.php, worker2/Worker/Netsuite/Invoice.php, worker2/Worker/Netsuite/CashSale.php, worker2/Worker/Netsuite/CreditMemo.php, worker2/Worker/Netsuite/CashRefund.php, worker2/Worker/Netsuite/JournalEntry.php, worker2/Worker/Netsuite/Opportunity.php, worker2/Worker/Netsuite/SalesOrder.php, dbchanges2/Forecast/2026-06-26a - Add journalEntry to Sales transaction type enum.sql, test/@dave/test_invoice_lifecycle.php, test/@dave/test_je_lifecycle.php, test/@dave/test_creditmemo_lifecycle.php, test/@dave/test_cashsale_lifecycle.php, test/@dave/test_cashrefund_lifecycle.php, test/@dave/test_fetchrecord_routes.php, test/@dave/verify_je_classification.php, test/@dave/probe_je_accounts.php, test/@dave/probe_je_shape.php, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/NetSuite/api-message-queue/dev_ue_api_msg_queue_enqueue.js |
|
|
12
12
|
| [_Model magic-field access (__get without __isset)](features/model-magic-field-access.md) | `_Model` exposes DB columns as "magic" properties via `__get()`, but it defines **no** `__isset()`. | _underscore/Model/Core/Model.php |
|
|
13
13
|
| [NetSuite REST Client (_Component_Api_Netsuite) — record writes & SuiteQL](features/netsuite-rest-client.md) | `_Component_Api_Netsuite` is the **2.0 `_underscore` NetSuite REST client** — the shared primitive every worker2/api2 NetSuite caller uses for record GETs, Suit | _underscore/Component/Api/Netsuite/Netsuite.php |
|
|
14
14
|
| [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php |
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-06-
|
|
9
|
+
updated: 2026-06-29
|
|
10
10
|
owners: [dfranks]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Component/Forecast/SaleImport/SaleImport.php
|
|
@@ -28,6 +28,7 @@ files:
|
|
|
28
28
|
- test/@dave/test_fetchrecord_routes.php
|
|
29
29
|
- test/@dave/verify_je_classification.php
|
|
30
30
|
- test/@dave/probe_je_accounts.php
|
|
31
|
+
- test/@dave/probe_je_shape.php
|
|
31
32
|
- test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js
|
|
32
33
|
- test/@dave/NetSuite/api-message-queue/dev_ue_api_msg_queue_enqueue.js
|
|
33
34
|
related:
|
|
@@ -161,11 +162,27 @@ location, memo). Handler `_Worker_Netsuite_JournalEntry`: `post`/`put` → `sync
|
|
|
161
162
|
item-line upsert/reconcile machinery (`syncLines`/`guardedInsert`/`deleteRows`).
|
|
162
163
|
|
|
163
164
|
**Mapping model (durable design):**
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`
|
|
168
|
-
|
|
165
|
+
- **Sales rep is now LIVE on JE lines** as the custom column **`custcol_sales_rep_line`**
|
|
166
|
+
(`JE_LINE_SALESREP_FIELD = 'custcol_sales_rep_line'`, wired 2026-06-29 after live Apr–May
|
|
167
|
+
2026 probing). The value is a NetSuite **employee REFERENCE object** `{links, id, refName}`;
|
|
168
|
+
`.id` is the employee internalId (a **string** in JSON). `journalLineLookup()` resolves it
|
|
169
|
+
via `lookupId('Employees','netsuiteInternalId', .id)` → local `salesRepEmployeeId`. The
|
|
170
|
+
per-run **account-number allowlist isolates exactly the lines that carry the rep** — offset/
|
|
171
|
+
balancing lines omit class/entity/`custcol_sales_rep_line`, so they group to null and are
|
|
172
|
+
dropped. No schema/migration (`salesRepEmployeeId` already on `Forecast.Sales`).
|
|
173
|
+
- **JE lines carry NO item field at all — item ingestion from NetSuite is not possible.**
|
|
174
|
+
Confirmed across multiple Apr–May 2026 JEs: the full union of line keys is
|
|
175
|
+
`{account, class, cleared, debit, credit, custcol_sales_rep_line, entity, line, memo, location}`.
|
|
176
|
+
There is **no native `item` and no custom item column**. `JE_LINE_ITEM_FIELD` stays **null
|
|
177
|
+
by design**; kept lines now group **per-salesRep with a null item**. The dimension that
|
|
178
|
+
exists *instead of* item is **`entity`** (the customer ref). Probe tool:
|
|
179
|
+
`test/@dave/probe_je_shape.php` (dumps line column shapes + custom columns).
|
|
180
|
+
- **No salesRep self-heal (unlike the item path).** `journalLineLookup()` for Employees has
|
|
181
|
+
**no `syncEmployee()` fallback** (the item path self-heals via
|
|
182
|
+
`_Worker_Netsuite_Item::syncItem()`). A rep missing from `Forecast.Employees` silently
|
|
183
|
+
resolves to **null** and re-aggregates under null. It relies on the **supporting-records
|
|
184
|
+
pull** keeping `Forecast.Employees` current. (Sample coverage was complete — rep IDs
|
|
185
|
+
482, 569, 685, 30954, 34877 all present in prod `Forecast.Employees`.)
|
|
169
186
|
- Lines hitting a **revenue** or **cost** GL account are grouped by **(salesRep, item)**:
|
|
170
187
|
`revenue = Σ(credit − debit)` over revenue lines, `cost = Σ(debit − credit)` over cost
|
|
171
188
|
lines, `profit = revenue − cost`.
|
|
@@ -411,6 +428,21 @@ record is deleted in NetSuite.)
|
|
|
411
428
|
- The cron's sign handling is not portable here — see Sign convention.
|
|
412
429
|
|
|
413
430
|
## Change history
|
|
431
|
+
- 2026-06-29 — **Wired JE sales-rep ingestion live** (TRUE-79862): set
|
|
432
|
+
`JE_LINE_SALESREP_FIELD = 'custcol_sales_rep_line'` after live Apr–May 2026 probing
|
|
433
|
+
confirmed the rep is now present on JE lines as that custom column — a NetSuite employee
|
|
434
|
+
**reference** object `{links,id,refName}` whose `.id` (string) resolves via
|
|
435
|
+
`lookupId('Employees','netsuiteInternalId',.id)`. Kept lines now group per-salesRep with a
|
|
436
|
+
null item. One-line change, no schema/migration (`salesRepEmployeeId` already exists).
|
|
437
|
+
**Confirmed JE lines carry NO item field** (native or custom) — line key union is
|
|
438
|
+
`{account,class,cleared,debit,credit,custcol_sales_rep_line,entity,line,memo,location}`; the
|
|
439
|
+
dimension *instead of* item is `entity` (customer ref), so `JE_LINE_ITEM_FIELD` stays null
|
|
440
|
+
by design (item ingestion from NetSuite is not possible). **Gotcha: JE salesRep lookup has
|
|
441
|
+
no self-heal** (the item path does via `syncItem()`) — a rep missing from
|
|
442
|
+
`Forecast.Employees` resolves to null and aggregates under null; relies on the
|
|
443
|
+
supporting-records pull. Still dormant in prod (JE webhook fires only once the AMQ enqueuer
|
|
444
|
+
deploys on the Journal Entry record type). Probe tool: `test/@dave/probe_je_shape.php`.
|
|
445
|
+
(dfranks)
|
|
414
446
|
- 2026-06-26 — **Changed JE revenue/cost classification from `accttype` buckets to an EXACT
|
|
415
447
|
account-NUMBER allowlist** (sales-team-defined): `JE_REVENUE_ACCOUNT_NUMBERS =
|
|
416
448
|
{41100,41300,41500}`, `JE_COST_ACCOUNT_NUMBERS = {51100,51200}`; everything else ignored.
|
package/knowledge/INDEX.md
CHANGED
|
@@ -16,7 +16,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
16
16
|
|
|
17
17
|
## 2.0 framework
|
|
18
18
|
|
|
19
|
-
- **_underscore** (_Underscore) _(framework core)_ —
|
|
19
|
+
- **_underscore** (_Underscore) _(framework core)_ — 19 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
20
20
|
- **worker2** (Worker) — 22 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
21
21
|
- **api2** (API) — 7 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
22
22
|
- **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
package/package.json
CHANGED