toga-ai 1.0.60 → 1.0.61

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.
@@ -25,4 +25,5 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
25
25
  - **New York City Department of Education** (`nycdoe`) → [clients/nycdoe/INDEX.md](clients/nycdoe/INDEX.md)
26
26
  - **Prudential Financial** (`prudential`) → [clients/prudential/INDEX.md](clients/prudential/INDEX.md)
27
27
  - **Rate** (`rate`) → [clients/rate/INDEX.md](clients/rate/INDEX.md)
28
+ - **Tow Foundation** (`tow-foundation`) → [clients/tow-foundation/INDEX.md](clients/tow-foundation/INDEX.md)
28
29
 
@@ -0,0 +1,6 @@
1
+ # Client: Tow Foundation `tow-foundation`
2
+
3
+ | Doc | Framework | Summary | Files |
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 |
6
+ | [Tow Foundation](profile.md) | 2.0 | Tow Foundation is a nonprofit client. | |
@@ -0,0 +1,130 @@
1
+ ---
2
+ title: "Credit Card Receipt Processing"
3
+ framework: "2.0"
4
+ project: Worker
5
+ client: tow-foundation
6
+ type: client-feature
7
+ status: active
8
+ updated: 2026-06-11
9
+ owners: ["rgirish"]
10
+ files:
11
+ - worker2/Worker/Client/TowFoundation.php
12
+ - worker2/Worker/Client/TowFoundation/ProcessReceipts.php
13
+ related:
14
+ - clients/tow-foundation/profile.md
15
+ ---
16
+
17
+ ## Summary
18
+
19
+ Automated processing of credit card receipts uploaded to SharePoint. Downloads each
20
+ receipt, extracts structured data via Talos AI, cross-verifies against billing-cycle
21
+ statements, renames the file, archives it per cardholder, generates a QuickBooks-ready
22
+ Excel file per person, uploads it to SharePoint, and sends a summary email.
23
+
24
+ Invocation: `{"action": "Client/TowFoundation/ProcessReceipts/Run", "parameters": {}}`
25
+
26
+ Optional filter parameters: `limit` (int), `year` (string e.g. `"2026"`), `person` (string e.g. `"Brent Peterkin"`).
27
+
28
+ ## Key files / entry points
29
+
30
+ - `TowFoundation.php` — base class; holds all email constants and `initialize()` (empty — no client DB)
31
+ - `ProcessReceipts.php` — all logic; abstract class extending `_Worker_Client_TowFoundation`
32
+
33
+ ## How it works
34
+
35
+ ### SharePoint folder structure
36
+ ```
37
+ Credit Card Receipts/
38
+ {Person}/
39
+ {Year}/
40
+ {BillingCycleFolder}/ ← receipt files live here (e.g. "Amex ending in 06-03-2026")
41
+ {Person} reports/ ← .xlsx billing statements for cross-verification
42
+ Archive/
43
+ {Person}/ ← successfully processed receipts land here (renamed)
44
+ exception/
45
+ {Person}/ ← failed receipts land here (original name preserved)
46
+ 3. QB Excel/ ← generated Excel files uploaded here after each run
47
+ ```
48
+
49
+ ### Processing flow
50
+
51
+ 1. **Auth** — OAuth2 client-credentials token from Microsoft Graph
52
+ 2. **Walk** — `walkReceiptsFolder()` enumerates all receipt files and statement Excels
53
+ 3. **Filter** — optional `$year` / `$person` / `$limit` applied to the receipt list
54
+ 4. **Pre-load statements** — all billing-cycle `.xlsx` files under `reports/` are downloaded
55
+ and parsed upfront via PhpSpreadsheet (auto-detect header row by scanning for
56
+ description/amount keywords)
57
+ 5. **Pass 1 — Extract** — for each receipt:
58
+ - Enforce size limit (4 MB images, 10 MB documents)
59
+ - Download file bytes from SharePoint
60
+ - POST to Talos AI `/api/ai/generate` → structured `{vendor_name, invoice_date, total, payment_memo, category, ...}`
61
+ - Cross-verify amount ± $0.01 against parsed statement; if matched, override `payment_memo` with statement description
62
+ - Build base filename (no suffix yet) and store in `$pendingRenames`
63
+ - On extract failure → move to `Archive/exception/{Person}/` immediately
64
+ 6. **Collision detection** — count base name occurrences across all pending renames
65
+ 7. **Pass 2 — Move** — for each pending rename:
66
+ - If base name appears more than once, assign `_a`, `_b`, `_c`... suffix to **all** colliding files (including the first)
67
+ - PATCH SharePoint to rename + move to `Archive/{Person}/`
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.
69
+ 9. **SharePoint upload** — each Excel uploaded to `{Person}/{Year}/3. QB Excel/` via Graph API PUT
70
+ 10. **Summary email** — sent with Excel files attached; To: Jheanelle, CC: Magdalena, BCC: devteam@togatech.com
71
+
72
+ ### Renamed file format
73
+ ```
74
+ YYYY.MM.DD Name of Cardholder_VendorName_Amount[_a].ext
75
+ ```
76
+ - Vendor name: special chars stripped, spaces → underscores
77
+ - Amount: two decimal places (e.g. `42.50`)
78
+ - Suffix `_a`, `_b`... added when date + person + vendor + amount are all identical (e.g. multiple train tickets same day)
79
+
80
+ ### Ref No. (QuickBooks)
81
+ Amex billing cycle runs 3rd-to-3rd. `computeRefNo()` returns the cycle-end date as `MMDDYYYY`.
82
+ - Charge on or before the 3rd → cycle ends on the 3rd of the same month
83
+ - Charge after the 3rd → cycle ends on the 3rd of the next month
84
+
85
+ ### Per-person constants
86
+ `CLASS_MAP` and `PAYMENT_ACCOUNT_MAP` in `ProcessReceipts.php` map each cardholder's name
87
+ to their QuickBooks Class and Payment Account strings. Ryan Farrell uses Bank of America
88
+ Mastercard; all others use AMEX Open Credit Card.
89
+
90
+ ## Email routing
91
+
92
+ Defined as constants in `TowFoundation.php`:
93
+
94
+ | Constant | Value | Role |
95
+ |---|---|---|
96
+ | `NOTIFY_EMAIL_CLIENT` | `Jheanelle@towfoundation.org` | To |
97
+ | `NOTIFY_EMAIL_CC` | `['Magdalena@towfoundation.org']` | CC |
98
+ | `NOTIFY_EMAIL_BCC` | `['devteam@togatech.com']` | BCC |
99
+ | `NOTIFY_EMAIL_DEV` | `devteam@goagilant.com` | To (always) |
100
+ | `NOTIFY_EMAIL_EXTRA` | jcardinal, ajean, bmorton @goagilant.com | To |
101
+
102
+ Fatal errors send only to `NOTIFY_EMAIL_DEV` (no CC/BCC).
103
+
104
+ ## Gotchas / known issues
105
+
106
+ - **`$year` variable shadowing** — `Run()` uses `$year` as both a filter parameter and a
107
+ loop variable (line ~159: `$year = $receipt['year']`). After the loop `$year` holds the
108
+ last receipt's year, not the original filter value. Harmless now but fragile if the loop
109
+ is restructured.
110
+ - **Two-pass rename is required** — collision detection must see ALL base names before any
111
+ file is moved. A single-pass approach would retroactively need to rename the first file
112
+ after discovering a duplicate, which is not possible once it's already on SharePoint.
113
+ - **`_Loader::setThrowExceptionInAutoloaderIfClassNotFound(false)`** — must wrap all
114
+ PhpSpreadsheet calls. ZipStream is a Composer dependency that triggers the autoloader;
115
+ without this flag, it throws on missing class and aborts Excel generation.
116
+ - **Graph API item-ID move** — `renameAndMoveToArchive()` resolves the target folder to an
117
+ item ID before PATCHing. Using path-based `parentReference` causes HTTP 400 on folder
118
+ names with special characters (spaces, dots). Always resolve to ID first.
119
+ - **`ensureFolderPath()` for "3. QB Excel"** — the folder name contains a dot and space;
120
+ `ensureFolderPath` handles this correctly via `rawurlencode` on each path segment.
121
+ - **Statement matching tolerance** — `matchStatementRow()` uses `abs($row['amount'] - $amount) < 0.01`
122
+ for amount matching, then date tie-break for multiple same-amount rows. Returns first
123
+ candidate if date tie-break also ambiguous.
124
+ - **No client DB** — there is no audit trail in MySQL. All state lives in SharePoint folder
125
+ structure and email. If a run is interrupted mid-way, some receipts may be archived
126
+ without a corresponding Excel row.
127
+
128
+ ## Change history
129
+
130
+ - 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)
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: "Tow Foundation"
3
+ framework: "2.0"
4
+ project: Worker
5
+ client: tow-foundation
6
+ type: profile
7
+ status: active
8
+ updated: 2026-06-11
9
+ owners: ["rgirish"]
10
+ files: []
11
+ related:
12
+ - clients/tow-foundation/features/receipt-processing.md
13
+ ---
14
+
15
+ ## Summary
16
+
17
+ Tow Foundation is a nonprofit client. Their integration automates credit card receipt
18
+ processing: receipts uploaded to SharePoint by cardholders are downloaded, extracted via
19
+ Talos AI, cross-verified against Amex/Mastercard billing statements, renamed, archived,
20
+ and exported as QuickBooks-ready Excel files.
21
+
22
+ No client database is used (no persistence beyond SharePoint and email).
23
+
24
+ ## Contacts
25
+
26
+ - **Jheanelle Gordon** — primary contact; receives the processing completion email
27
+ - **Magdalena Minta** — CC on completion email
28
+ - devteam@togatech.com — BCC on all emails
29
+
30
+ ## Key integration points
31
+
32
+ - Microsoft SharePoint (Microsoft Graph API) — receipt file storage
33
+ - Talos AI (`/api/ai/generate`) — structured receipt data extraction
34
+ - PhpSpreadsheet — Excel generation and statement parsing
35
+ - `_Email` — completion summary + fatal error notifications
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
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",