toga-ai 1.0.129 → 1.0.131
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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Doc | Framework | Summary | Files |
|
|
4
4
|
|-----|-----------|---------|-------|
|
|
5
|
-
| [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Model/Compass/PurchaseOrder.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql, dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql |
|
|
5
|
+
| [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Model/Compass/PurchaseOrder.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql, dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql, dbchanges2/Client_Compass/2026-06-18a - CleanupSA132898DuplicateTracking.sql |
|
|
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, dbchanges2/Client_Compass/2026-06-15a - FixItemFulfillmentTrackingNumberJoins.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, worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php |
|
|
8
8
|
| [Compass USA](profile.md) | 2.0 | Compass USA is a TOGA client running a multi-tier supply-chain commerce operation. | |
|
|
@@ -5,7 +5,7 @@ project: _Underscore
|
|
|
5
5
|
client: compass-usa
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
8
|
+
updated: 2026-06-18
|
|
9
9
|
owners: [jcardinal]
|
|
10
10
|
files:
|
|
11
11
|
- _underscore/Model/Compass/AdvanceShippingNotice.php
|
|
@@ -16,6 +16,7 @@ files:
|
|
|
16
16
|
- dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql
|
|
17
17
|
- dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql
|
|
18
18
|
- dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql
|
|
19
|
+
- dbchanges2/Client_Compass/2026-06-18a - CleanupSA132898DuplicateTracking.sql
|
|
19
20
|
related:
|
|
20
21
|
- ../../../2.0/apps/_underscore/features/recursive-item-fulfillments.md
|
|
21
22
|
---
|
|
@@ -54,6 +55,11 @@ the gotcha about already-fulfilled orders). Flow:
|
|
|
54
55
|
- **`remaining <= 0`** (reconcile path, new): the tracking targets are the **existing IFIs**
|
|
55
56
|
for that SOI (resolved via `ItemFulfillmentItems.salesOrderItemId` → their `itemFulfillmentId`),
|
|
56
57
|
**not** an SO-number lookup — NetSuite/toga2-supply IFs are `F`-numbered, not SO-numbered.
|
|
58
|
+
As of **2026-06-18** an existing IFI that **already carries item-level tracking is skipped**
|
|
59
|
+
here (`itemFulfillmentItemHasTracking()`): reconcile only attaches onto untracked
|
|
60
|
+
out-of-band IFIs. An already-tracked, fully-fulfilled line revisited by a later ASN is a
|
|
61
|
+
vendor re-transmission and must not gain a second tracking number (see the duplicate-tracking
|
|
62
|
+
gotcha).
|
|
57
63
|
4. Copy the ASN item's tracking (`AdvanceShippingNoticeItems_TrackingNumbers`) onto each target
|
|
58
64
|
IFI via `POST /item-fulfillment-item-tracking-numbers` → `ItemFulfillmentItems_TrackingNumbers`
|
|
59
65
|
— **idempotent** (skipped if the bridge row already exists; ASNs get re-POSTed).
|
|
@@ -176,8 +182,29 @@ Compass Canada (`Model/Compass/Canada/`) is a separate sub-client. The Compass c
|
|
|
176
182
|
`NOT EXISTS`. ~116 PO items across other Compass orders share the off-by-one fingerprint and
|
|
177
183
|
are not yet repaired — a broader reviewed backfill is still outstanding.
|
|
178
184
|
|
|
185
|
+
- **Duplicate tracking from vendor ASN re-transmission (root cause, fixed forward 2026-06-18)
|
|
186
|
+
— DISTINCT from the cross-line contamination above.** Compass vendors (Office Depot, Strategic
|
|
187
|
+
Systems) re-send the **same** shipment ASN file for several days; one PO can receive many ASNs
|
|
188
|
+
(e.g. SA132898 / PO `50305272-1` got 6). The first ASN takes the create path and attaches its
|
|
189
|
+
tracking; a later ASN re-listing the same, now fully-fulfilled line takes the **reconcile path**
|
|
190
|
+
and — pre-fix — attached its *different* tracking number onto the existing IFI. On a qty-1 line
|
|
191
|
+
this yields two item-level tracking rows (plus a propagated package row). Unlike the cross-line
|
|
192
|
+
bug, **both** tracking numbers here map cleanly to the correct line via their own valid ASN
|
|
193
|
+
items, so the `NOT EXISTS (ASN item with matching VendorItems.itemId)` cleanup guard does **not**
|
|
194
|
+
catch it — diagnose instead by an IFI carrying more item-level tracking numbers than its
|
|
195
|
+
fulfilled quantity. Fix: the reconcile path now skips any IFI that already has item-level
|
|
196
|
+
tracking (`itemFulfillmentItemHasTracking()`), so only untracked out-of-band IFIs receive ASN
|
|
197
|
+
tracking. The legitimate out-of-band case (IFI has no tracking, one ASN arrives) is preserved.
|
|
198
|
+
Forward-only; SA132898 repaired by `2026-06-18a` (delete the later tracking + orphaned package
|
|
199
|
+
row, keep the original; no backfill needed since the correct number is already present).
|
|
200
|
+
|
|
179
201
|
## Change history
|
|
180
202
|
Dated one-liners, newest first.
|
|
203
|
+
- 2026-06-18 — Reconcile path now skips IFIs that already carry item-level tracking
|
|
204
|
+
(`itemFulfillmentItemHasTracking()`), stopping duplicate/different tracking numbers from
|
|
205
|
+
vendor ASN re-transmissions piling onto fully-fulfilled lines (qty-1 SA132898 / USB31CC1 had
|
|
206
|
+
2). Distinct root cause from the 2026-06-16 cross-line contamination. SA132898 repaired by
|
|
207
|
+
`2026-06-18a` (cleanup-only; original tracking already correct). (jcardinal)
|
|
181
208
|
- 2026-06-16 — Identified cross-line tracking contamination root cause: bad
|
|
182
209
|
`SalesOrderItems_PurchaseOrderItems` rows (PO-local lineNumber collision in
|
|
183
210
|
`_Model_Compass_PurchaseOrder`, fixed forward 2026-06-11 `ec935478`; and the worker ODP-PO
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
| Doc | Framework | Summary | Files |
|
|
4
4
|
|-----|-----------|---------|-------|
|
|
5
|
-
| [Credit Card Receipt Processing](features/receipt-processing.md) | 2.0 | Automated processing of credit card receipts uploaded to SharePoint. | worker2/Worker/Client/TowFoundation.php, worker2/Worker/Client/TowFoundation/ProcessReceipts.php |
|
|
5
|
+
| [Credit Card Receipt Processing](features/receipt-processing.md) | 2.0 | Automated processing of credit card receipts uploaded to SharePoint. | worker2/Worker/Client/TowFoundation.php, worker2/Worker/Client/TowFoundation/ProcessReceipts.php, worker2/Worker/Client/TowFoundation/TowFoundationVendors.php |
|
|
6
6
|
| [Tow Foundation](profile.md) | 2.0 | Tow Foundation is a nonprofit client. | |
|
|
@@ -5,11 +5,12 @@ project: Worker
|
|
|
5
5
|
client: tow-foundation
|
|
6
6
|
type: client-feature
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-06-
|
|
8
|
+
updated: 2026-06-18
|
|
9
9
|
owners: ["rgirish"]
|
|
10
10
|
files:
|
|
11
11
|
- worker2/Worker/Client/TowFoundation.php
|
|
12
12
|
- worker2/Worker/Client/TowFoundation/ProcessReceipts.php
|
|
13
|
+
- worker2/Worker/Client/TowFoundation/TowFoundationVendors.php
|
|
13
14
|
related:
|
|
14
15
|
- clients/tow-foundation/profile.md
|
|
15
16
|
---
|
|
@@ -23,7 +24,7 @@ Excel file per person, uploads it to SharePoint, and sends a summary email.
|
|
|
23
24
|
|
|
24
25
|
Invocation: `{"action": "Client/TowFoundation/ProcessReceipts/Run", "parameters": {}}`
|
|
25
26
|
|
|
26
|
-
Optional filter parameters: `limit` (int), `year` (string e.g. `"2026"`), `person` (string e.g. `"Brent Peterkin"`).
|
|
27
|
+
Optional filter parameters: `limit` (int), `year` (string e.g. `"2026"`), `person` (string e.g. `"Brent Peterkin"`), `billingCycle` (string — matches the **end** of the billing-cycle folder name, e.g. `"06-03-2026"` matches `"Amex ending in 06-03-2026"`, `"Mastercard ending in 06-03-2026"`, etc.).
|
|
27
28
|
|
|
28
29
|
## Key files / entry points
|
|
29
30
|
|
|
@@ -48,7 +49,7 @@ Credit Card Receipts/
|
|
|
48
49
|
|
|
49
50
|
1. **Auth** — OAuth2 client-credentials token from Microsoft Graph
|
|
50
51
|
2. **Walk** — `walkReceiptsFolder()` enumerates all receipt files and statement Excels
|
|
51
|
-
3. **Filter** — optional `$year` / `$person` / `$limit` applied to the receipt list
|
|
52
|
+
3. **Filter** — optional `$year` / `$person` / `$billingCycle` / `$limit` applied to the receipt list. `$billingCycle` uses `str_ends_with()` so passing just the date (e.g. `"06-03-2026"`) matches any card type. Person folders named `"Brent Peterkin CC receipts"` are normalized to `"Brent Peterkin"` via regex strip of ` CC receipts` suffix before any map lookups.
|
|
52
53
|
4. **Pre-load statements** — all billing-cycle `.xlsx` files under `reports/` are downloaded
|
|
53
54
|
and parsed upfront via PhpSpreadsheet (auto-detect header row by scanning for
|
|
54
55
|
description/amount keywords)
|
|
@@ -59,8 +60,9 @@ Credit Card Receipts/
|
|
|
59
60
|
- Cross-verify amount ± $0.01 against parsed statement; if matched, override `payment_memo` with statement description
|
|
60
61
|
- Build base filename (no suffix yet) and store in `$pendingRenames`
|
|
61
62
|
- On extract failure → move to `Archive/exception/` immediately
|
|
62
|
-
6. **
|
|
63
|
-
7. **
|
|
63
|
+
6. **Deduplication** — after Pass 1, receipts sharing identical `(personName, invoice_date, vendor_name, total)` are deduplicated; only the first is kept, the rest are logged as `DUPLICATE skipped` and dropped. This catches the same receipt uploaded twice to SharePoint.
|
|
64
|
+
7. **Collision detection** — count base name occurrences across remaining pending renames
|
|
65
|
+
8. **Pass 2 — Move** — for each pending rename:
|
|
64
66
|
- If base name appears more than once, assign `_a`, `_b`, `_c`... suffix to **all** colliding files (including the first)
|
|
65
67
|
- PATCH SharePoint to rename + move to `Archive/` (flat — no person subfolder)
|
|
66
68
|
8. **Excel generation** — one `.xlsx` per person (PhpSpreadsheet); columns: Row #, Account Name, QB Vendor, Payment Amount, Date, Payment Method, Payment Memo, QB Description, Class, Category, Payment Account, Ref No.
|
|
@@ -80,6 +82,25 @@ Amex billing cycle runs 3rd-to-3rd. `computeRefNo()` returns the cycle-end date
|
|
|
80
82
|
- Charge on or before the 3rd → cycle ends on the 3rd of the same month
|
|
81
83
|
- Charge after the 3rd → cycle ends on the 3rd of the next month
|
|
82
84
|
|
|
85
|
+
### QB vendor matching
|
|
86
|
+
`TowFoundationVendors.php` holds 2,994 vendor names exported verbatim from Tow Foundation's
|
|
87
|
+
QuickBooks vendor list (June 2026). `matchQbVendor()` runs three passes against this list:
|
|
88
|
+
1. Exact match (case-insensitive)
|
|
89
|
+
2. Substring match — QB name contains extracted name or vice versa (min 4 chars); picks shortest match on multiple hits
|
|
90
|
+
3. `similar_text()` similarity ≥ 80% — picks highest scorer
|
|
91
|
+
|
|
92
|
+
Returns the exact QB vendor string or `''` if no confident match. The AI only extracts
|
|
93
|
+
`vendor_name`; QB matching is done entirely in PHP — no tokens spent per receipt on the list.
|
|
94
|
+
|
|
95
|
+
To update the vendor list: re-export from QuickBooks → run the extraction script →
|
|
96
|
+
replace `TowFoundationVendors.php`. The matching logic is in `matchQbVendor()` and needs no changes.
|
|
97
|
+
|
|
98
|
+
### AI category values
|
|
99
|
+
The AI is prompted to return **specific expense types** — e.g. `"Dining"`, `"Travel"`,
|
|
100
|
+
`"Accommodation"`, `"Transportation"`, `"Office Supplies"`, `"Entertainment"`,
|
|
101
|
+
`"Professional Services"`, `"Subscriptions"`. It must not use broad accounting labels
|
|
102
|
+
like `"Administrative Expenses"`.
|
|
103
|
+
|
|
83
104
|
### Per-person constants
|
|
84
105
|
`CLASS_MAP` and `PAYMENT_ACCOUNT_MAP` in `ProcessReceipts.php` map each cardholder's name
|
|
85
106
|
to their QuickBooks Class and Payment Account strings. Ryan Farrell uses Bank of America
|
|
@@ -133,7 +154,13 @@ Fatal errors send only to `NOTIFY_EMAIL_DEV` (no CC/BCC).
|
|
|
133
154
|
`Credit Card Receipts/3. QB Excel/` (not inside each person's subfolder). This folder
|
|
134
155
|
exists at the root of `Credit Card Receipts/` alongside the person folders.
|
|
135
156
|
|
|
157
|
+
- **Person folder name normalization** — SharePoint folders are named `"Brent Peterkin CC receipts"` but `CLASS_MAP` / `PAYMENT_ACCOUNT_MAP` keys are just `"Brent Peterkin"`. The ` CC receipts` suffix is stripped via regex in `walkReceiptsFolder()`. Without this, Class and Payment Account columns are blank for those persons.
|
|
158
|
+
- **`billingCycle` filter is suffix-match, not exact** — always pass just the date portion (`"06-03-2026"`), not the full folder name. Passing the full name (`"Amex ending in 06-03-2026"`) also works but would miss Mastercard folders.
|
|
159
|
+
- **Ole Mole not in QB vendor list** — as of June 2026 this vendor is not in Tow Foundation's QuickBooks, so `qb_vendor` will be blank for Ole Mole charges until they add it to QB and the vendor list is refreshed.
|
|
160
|
+
- **Duplicate detection is within-run only** — if the same receipt was processed in a prior run and archived, it won't be caught. The dedup only covers receipts present in the current run's `$pendingRenames`.
|
|
161
|
+
|
|
136
162
|
## Change history
|
|
137
163
|
|
|
164
|
+
- 2026-06-18 — QB vendor matching via local fuzzy match against `TowFoundationVendors.php` (2,994 vendors); AI category prompt updated to return specific types (Dining, Travel, etc.); duplicate receipt detection added (person+date+vendor+amount dedup); `billingCycle` filter parameter added (suffix-match — card-type agnostic); person folder ` CC receipts` suffix stripped so CLASS_MAP/PAYMENT_ACCOUNT_MAP resolve correctly (rgirish)
|
|
138
165
|
- 2026-06-12 — QB Excel upload moved to root-level `3. QB Excel/`; Archive/exception folders flattened (no person subfolder); unsupported mime types (`application/octet-stream`) now throw ReceiptProcessingException instead of being silently skipped (rgirish)
|
|
139
166
|
- 2026-06-11 — Added CC (Magdalena), BCC (devteam@togatech.com), per-cardholder Archive subfolders, Excel upload to "3. QB Excel" SharePoint folder, two-pass rename with alphabetical duplicate suffix, rename format changed to `YYYY.MM.DD Full Name_Vendor_Amount` (rgirish)
|
package/package.json
CHANGED