toga-ai 1.0.119 → 1.0.120
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.
|
@@ -57,6 +57,9 @@ the window's upper bound after each successful section.
|
|
|
57
57
|
|
|
58
58
|
### Adding a new client (the full recipe)
|
|
59
59
|
|
|
60
|
+
A wrapper + schedule alone is **not enough** — the client must also be provisioned in three
|
|
61
|
+
places or the sync runs but imports nothing (or 403s). All five steps are required:
|
|
62
|
+
|
|
60
63
|
1. **Wrapper** — copy `sync_togasupply_canon.php` to `sync_togasupply_<client>.php`; set
|
|
61
64
|
`CLIENT_CONFIGURATION` (literal UUIDs, or `App_Api_Toga2::*` consts if defined). Keep the
|
|
62
65
|
rest identical.
|
|
@@ -64,8 +67,35 @@ the window's upper bound after each successful section.
|
|
|
64
67
|
`"cron": "toga2/netsuite/sync_togasupply_<client>.php"`). Deploys regenerate the crontab.
|
|
65
68
|
3. **Seed Parameters** — add `dbchanges2/Client_<Id>/<date> - NetsuiteSyncParameters.sql`
|
|
66
69
|
inserting the 12 keys. **Without this the sync 404s on the first `/parameters` GET and the
|
|
67
|
-
run aborts.**
|
|
70
|
+
run aborts.** Seed start date = the canonical **`2026-03-04`** (from
|
|
71
|
+
`_modules/netsuite/2026-04-01 - Parameters.sql`) unless backfilling earlier history for that
|
|
72
|
+
client. `Client_<Id>` directory selects the DB — no `USE` statement (dbchanges2 rule).
|
|
68
73
|
`lint`: `C:\xampp7\php\php.exe -l` (prod worker is PHP 7.2).
|
|
74
|
+
4. **Client→NetSuite customer link** (`Core.Clients.netsuiteCustomerInternalId`) — **MUST be
|
|
75
|
+
set** to the client's NetSuite customer internal id. The lookup phase calls
|
|
76
|
+
`listChildCustomers((int)$client->netsuiteCustomerInternalId)`; if it's `NULL` the walk
|
|
77
|
+
seeds off `0`, the customer→client map is empty, and **no order ever matches → silent
|
|
78
|
+
zero-import** (the sync "runs" and even advances windows, but writes nothing). Find the id
|
|
79
|
+
with a SuiteQL `customer` lookup (`test/@dave/find_aig_netsuite_customer.php` is a template);
|
|
80
|
+
set it via a `dbchanges2/Core/` migration. Verify the client *has* supply transactions on
|
|
81
|
+
that customer before bothering (see the AIG gotcha).
|
|
82
|
+
5. **Per-client custom fields on the synced records** — the shared engine hardcodes a fixed set
|
|
83
|
+
of `c_netsuite*` field names it reads/writes (see *Custom field contract* below). Each must
|
|
84
|
+
exist on the client's records as **column + `CustomRecordFields` row + `AclCustomFieldPermissions`
|
|
85
|
+
grant** (custom fields are per-client — see the 2.0 `_underscore` per-client-database doc). A
|
|
86
|
+
missing one → **403 EZ-2** ("not authorized to read the specified fields") aborting the run.
|
|
87
|
+
The most commonly-missing one is `c_netsuiteInternalCustomerId` on the **Customers** record
|
|
88
|
+
(`recordId 113`, `isIdentifier=1`).
|
|
89
|
+
|
|
90
|
+
### Custom field contract (hardcoded in `common_sync_togasupply.php`)
|
|
91
|
+
|
|
92
|
+
The engine requests these `c_` fields by literal name per route — every synced client must have
|
|
93
|
+
them provisioned: `/customers`→`c_netsuiteInternalCustomerId`; `/countries`→`c_netsuiteCountry`;
|
|
94
|
+
`/locations`→`c_netsuiteInternalCustomerId` + `c_netsuiteInternalLocationId` + the
|
|
95
|
+
`c_dtNetsuiteLast*Integration` timestamps; `/subsidiaries`→`c_netsuiteInternalSubsidiaryId`;
|
|
96
|
+
`/vendors`→`c_netsuiteInternalVendorId`; `/payment-terms`→`c_netsuiteInternalTermsId`;
|
|
97
|
+
`/shipping-methods`→`c_netsuiteInternalShipMethodId`. The names are a **convention**, not
|
|
98
|
+
discovered per-client.
|
|
69
99
|
|
|
70
100
|
## Data model
|
|
71
101
|
|
|
@@ -74,7 +104,8 @@ Per-client `Parameters` table (2.0 client DB, e.g. `Client_Canon.Parameters`; co
|
|
|
74
104
|
`/parameters`:
|
|
75
105
|
|
|
76
106
|
- `NETSUITE_LAST_SYNC_DATETIME_{SALES_ORDERS,PURCHASE_ORDERS,INVOICES,ITEM_RECEIPTS,ITEM_FULFILLMENTS,INVENTORY_ADJUSTMENTS}`
|
|
77
|
-
— seed `'
|
|
107
|
+
— seed `'2026-03-04 00:00:00'` (the canonical start; use an earlier date only to backfill a
|
|
108
|
+
client whose history predates it — e.g. AIG seeded `2023-01-01` to reach its 2023/2025 records).
|
|
78
109
|
- `NETSUITE_EXECUTION_MODE_{...same six...}` — seed `'864000-IDLE'`.
|
|
79
110
|
|
|
80
111
|
Parameters are stored **per client DB** but accessed **through the TOGa2 API**, not direct SQL.
|
|
@@ -102,13 +133,28 @@ Parameters are stored **per client DB** but accessed **through the TOGa2 API**,
|
|
|
102
133
|
`Client_<Id>.Parameters`: a healthy client advances to ~now every 5 min. As of 2026-06-17,
|
|
103
134
|
Quad was seeded but frozen at 2025-04/05 (not advancing) while the other 12 deployed clients
|
|
104
135
|
were current.
|
|
136
|
+
- **Silent zero-import = missing `netsuiteCustomerInternalId`.** If a client "runs" (sections
|
|
137
|
+
flip RUNNING→IDLE, windows advance) but imports nothing, check
|
|
138
|
+
`Core.Clients.netsuiteCustomerInternalId` — a NULL there empties the customer map so no order
|
|
139
|
+
matches. Distinct from the EZ-2 *abort* caused by a missing `c_netsuite*` field.
|
|
140
|
+
- **"Listed ≠ functioning" — the AIG case (2026-06-17).** AIG was in the original combined
|
|
141
|
+
array but had **never** imported anything in prod (0 SalesOrders/POs/Invoices/Locations/Customers)
|
|
142
|
+
and *couldn't* have: its `netsuiteCustomerInternalId` was NULL and its Customers record lacked
|
|
143
|
+
`c_netsuiteInternalCustomerId`. After provisioning all three (custom field, Parameters, customer
|
|
144
|
+
link → NetSuite customer **34902**), it still imports ~nothing because AIG's entire NetSuite
|
|
145
|
+
supply footprint is **1 sales order (2025-09-11) + 15 opportunities** — it's an
|
|
146
|
+
opportunity/entitlement account, not a procurement/supply customer. Lesson: before onboarding a
|
|
147
|
+
client, confirm it actually transacts supply orders in NetSuite (SuiteQL the `customer`'s
|
|
148
|
+
transaction history) — being in the array doesn't mean it belongs on this engine.
|
|
105
149
|
|
|
106
150
|
## Change history
|
|
107
151
|
|
|
108
|
-
- 2026-06-17 —
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
152
|
+
- 2026-06-17 — Documented the full onboarding prerequisites (client→NetSuite customer link +
|
|
153
|
+
per-client `c_netsuite*` custom fields) after AIG ran but imported nothing. Added AIG + Growrk
|
|
154
|
+
thin wrappers, schedule entries, and dbchanges2 Parameters seeds; built AIG's
|
|
155
|
+
`c_netsuiteInternalCustomerId` field migration + `Core.Clients` customer-link migration (id
|
|
156
|
+
34902). Confirmed AIG is not a real supply client; Growrk ships, AIG held. Canonical seed start
|
|
157
|
+
is `2026-03-04` (not `2025-01-01`). (dfranks)
|
|
112
158
|
|
|
113
159
|
## Related docs
|
|
114
160
|
|
package/package.json
CHANGED