neuronix-node 0.2.0 → 0.6.0

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.
@@ -5,11 +5,18 @@ const index_js_1 = require("../parsers/index.js");
5
5
  const chart_js_1 = require("./chart.js");
6
6
  const expense_js_1 = require("./expense.js");
7
7
  const pnl_js_1 = require("./pnl.js");
8
- const invoice_js_1 = require("./invoice.js");
8
+ const ar_aging_js_1 = require("./ar-aging.js");
9
+ const ap_aging_js_1 = require("./ap-aging.js");
10
+ const bank_reconciliation_js_1 = require("./bank-reconciliation.js");
11
+ const budget_vs_actuals_js_1 = require("./budget-vs-actuals.js");
12
+ const payroll_js_1 = require("./payroll.js");
13
+ const sales_tax_js_1 = require("./sales-tax.js");
14
+ const depreciation_js_1 = require("./depreciation.js");
15
+ const department_spending_js_1 = require("./department-spending.js");
9
16
  /**
10
17
  * File processor handler.
11
- * Receives a file's content, parses it, determines what to do,
12
- * then routes to the appropriate specialized handler.
18
+ * Receives a file's content, parses it, determines the best handler,
19
+ * converts CSV data into the right format, and routes it.
13
20
  */
14
21
  async function handleFileProcess(task) {
15
22
  const start = Date.now();
@@ -17,141 +24,358 @@ async function handleFileProcess(task) {
17
24
  const fileName = payload.file_name || "unknown";
18
25
  const fileType = payload.file_type || "unknown";
19
26
  const content = payload.file_content || "";
20
- // Parse the file
27
+ // Parse the file and detect type
21
28
  const parsed = (0, index_js_1.parseFile)(fileName, fileType, content);
22
- // If there are suggested actions, auto-execute the best one
23
- if (parsed.suggestedActions.length > 0) {
24
- const bestAction = parsed.suggestedActions[0];
25
- // Build input from parsed data
26
- if (bestAction === "expense_report" && parsed.type === "csv") {
27
- const csvData = parsed.data;
28
- const expenses = csvToExpenses(csvData);
29
- if (expenses.length > 0) {
30
- const result = await (0, expense_js_1.handleExpenseReport)({
29
+ if (parsed.suggestedActions.length === 0 || parsed.type !== "csv") {
30
+ return {
31
+ text: `Parsed "${fileName}" (${fileType}). Could not determine the appropriate handler.\n\n${JSON.stringify(parsed.data, null, 2)}`,
32
+ parsed_file: parsed,
33
+ duration_ms: Date.now() - start,
34
+ };
35
+ }
36
+ const bestAction = parsed.suggestedActions[0];
37
+ const csvData = parsed.data;
38
+ const headers = csvData.headers.map(h => h.toLowerCase());
39
+ try {
40
+ let result;
41
+ switch (bestAction) {
42
+ case "expense_report": {
43
+ const expenses = csvToExpenses(csvData);
44
+ if (expenses.length === 0)
45
+ break;
46
+ result = await (0, expense_js_1.handleExpenseReport)({
31
47
  type: "expense_report",
32
- input_payload: { expenses },
48
+ input_payload: { expenses, merged_from: payload.merged_from },
33
49
  });
34
- return {
35
- ...result,
36
- parsed_file: { type: parsed.type, rows: csvData.rowCount, columns: csvData.headers.length },
37
- auto_action: bestAction,
38
- duration_ms: Date.now() - start,
39
- };
50
+ return withMeta(result, parsed, bestAction, start);
40
51
  }
41
- }
42
- if (bestAction === "chart" && parsed.type === "csv") {
43
- const csvData = parsed.data;
44
- const chartInput = csvToChart(csvData, fileName);
45
- if (chartInput) {
46
- const result = await (0, chart_js_1.handleChart)({
47
- type: "chart",
48
- input_payload: chartInput,
52
+ case "ar_aging": {
53
+ const invoices = csvToInvoices(csvData);
54
+ if (invoices.length === 0)
55
+ break;
56
+ result = await (0, ar_aging_js_1.handleARAging)({
57
+ type: "ar_aging",
58
+ input_payload: { invoices },
49
59
  });
50
- return {
51
- ...result,
52
- parsed_file: { type: parsed.type, rows: csvData.rowCount, columns: csvData.headers.length },
53
- auto_action: bestAction,
54
- duration_ms: Date.now() - start,
55
- };
60
+ return withMeta(result, parsed, bestAction, start);
56
61
  }
57
- }
58
- if (bestAction === "pnl" && parsed.type === "csv") {
59
- const csvData = parsed.data;
60
- const pnlInput = csvToPnl(csvData);
61
- if (pnlInput) {
62
- const result = await (0, pnl_js_1.handlePnl)({
62
+ case "ap_aging": {
63
+ const bills = csvToBills(csvData);
64
+ if (bills.length === 0)
65
+ break;
66
+ result = await (0, ap_aging_js_1.handleAPAging)({
67
+ type: "ap_aging",
68
+ input_payload: { bills },
69
+ });
70
+ return withMeta(result, parsed, bestAction, start);
71
+ }
72
+ case "bank_reconciliation": {
73
+ const bankTxns = csvToBankTransactions(csvData);
74
+ if (bankTxns.length === 0)
75
+ break;
76
+ result = await (0, bank_reconciliation_js_1.handleBankReconciliation)({
77
+ type: "bank_reconciliation",
78
+ input_payload: { bank_transactions: bankTxns },
79
+ });
80
+ return withMeta(result, parsed, bestAction, start);
81
+ }
82
+ case "budget_vs_actuals": {
83
+ const lines = csvToBudget(csvData);
84
+ if (lines.length === 0)
85
+ break;
86
+ result = await (0, budget_vs_actuals_js_1.handleBudgetVsActuals)({
87
+ type: "budget_vs_actuals",
88
+ input_payload: { lines },
89
+ });
90
+ return withMeta(result, parsed, bestAction, start);
91
+ }
92
+ case "payroll": {
93
+ const employees = csvToPayroll(csvData);
94
+ if (employees.length === 0)
95
+ break;
96
+ result = await (0, payroll_js_1.handlePayroll)({
97
+ type: "payroll",
98
+ input_payload: { employees },
99
+ });
100
+ return withMeta(result, parsed, bestAction, start);
101
+ }
102
+ case "sales_tax": {
103
+ const transactions = csvToSalesTax(csvData);
104
+ if (transactions.length === 0)
105
+ break;
106
+ result = await (0, sales_tax_js_1.handleSalesTax)({
107
+ type: "sales_tax",
108
+ input_payload: { transactions },
109
+ });
110
+ return withMeta(result, parsed, bestAction, start);
111
+ }
112
+ case "depreciation": {
113
+ const assets = csvToAssets(csvData);
114
+ if (assets.length === 0)
115
+ break;
116
+ result = await (0, depreciation_js_1.handleDepreciation)({
117
+ type: "depreciation",
118
+ input_payload: { assets },
119
+ });
120
+ return withMeta(result, parsed, bestAction, start);
121
+ }
122
+ case "department_spending": {
123
+ const expenses = csvToDeptExpenses(csvData);
124
+ if (expenses.length === 0)
125
+ break;
126
+ result = await (0, department_spending_js_1.handleDepartmentSpending)({
127
+ type: "department_spending",
128
+ input_payload: { expenses },
129
+ });
130
+ return withMeta(result, parsed, bestAction, start);
131
+ }
132
+ case "pnl": {
133
+ const pnlInput = csvToPnl(csvData);
134
+ if (!pnlInput)
135
+ break;
136
+ result = await (0, pnl_js_1.handlePnl)({
63
137
  type: "pnl",
64
138
  input_payload: pnlInput,
65
139
  });
66
- return {
67
- ...result,
68
- parsed_file: { type: parsed.type, rows: csvData.rowCount, columns: csvData.headers.length },
69
- auto_action: bestAction,
70
- duration_ms: Date.now() - start,
71
- };
140
+ return withMeta(result, parsed, bestAction, start);
72
141
  }
73
- }
74
- if (bestAction === "invoice") {
75
- const result = await (0, invoice_js_1.handleInvoice)({
76
- type: "invoice",
77
- input_payload: {},
78
- });
79
- return {
80
- ...result,
81
- parsed_file: { type: parsed.type },
82
- auto_action: bestAction,
83
- duration_ms: Date.now() - start,
84
- };
142
+ case "chart": {
143
+ const chartInput = csvToChart(csvData, fileName);
144
+ if (!chartInput)
145
+ break;
146
+ result = await (0, chart_js_1.handleChart)({
147
+ type: "chart",
148
+ input_payload: chartInput,
149
+ });
150
+ return withMeta(result, parsed, bestAction, start);
151
+ }
152
+ default:
153
+ break;
85
154
  }
86
155
  }
87
- // Default: return parsed summary
88
- const durationMs = Date.now() - start;
156
+ catch (err) {
157
+ return {
158
+ text: `Error processing "${fileName}" as ${bestAction}: ${err}`,
159
+ parsed_file: parsed,
160
+ auto_action: bestAction,
161
+ error: String(err),
162
+ duration_ms: Date.now() - start,
163
+ };
164
+ }
165
+ // Fallback: return parsed data with a chart
166
+ const chartInput = csvToChart(csvData, fileName);
167
+ if (chartInput) {
168
+ const result = await (0, chart_js_1.handleChart)({ type: "chart", input_payload: chartInput });
169
+ return withMeta(result, parsed, "chart", start);
170
+ }
89
171
  return {
90
- text: `Parsed "${fileName}" (${fileType}).\n\n${JSON.stringify(parsed.data, null, 2)}`,
172
+ text: `Parsed "${fileName}" ${csvData.rowCount} rows, ${csvData.headers.length} columns.\n\nHeaders: ${csvData.headers.join(", ")}`,
91
173
  parsed_file: parsed,
92
- suggested_actions: parsed.suggestedActions,
93
- duration_ms: durationMs,
174
+ duration_ms: Date.now() - start,
94
175
  };
95
176
  }
96
- /**
97
- * Convert CSV data into expense objects for the expense handler.
98
- */
177
+ function withMeta(result, parsed, action, start) {
178
+ const csv = parsed.data;
179
+ return {
180
+ ...result,
181
+ parsed_file: { type: parsed.type, rows: csv.rowCount || 0, columns: csv.headers?.length || 0 },
182
+ auto_action: action,
183
+ duration_ms: Date.now() - start,
184
+ };
185
+ }
186
+ // ═══════════════════════════════════════════════════════════
187
+ // CSV → Handler Data Converters
188
+ // ═══════════════════════════════════════════════════════════
189
+ function findCol(headers, ...patterns) {
190
+ for (const p of patterns) {
191
+ const idx = headers.findIndex(h => p.test(h));
192
+ if (idx >= 0)
193
+ return idx;
194
+ }
195
+ return -1;
196
+ }
197
+ function parseNum(val) {
198
+ return parseFloat((val || "0").replace(/[$,]/g, "")) || 0;
199
+ }
99
200
  function csvToExpenses(csv) {
100
- const headersLower = csv.headers.map((h) => h.toLowerCase());
101
- // Find relevant columns
102
- const descCol = headersLower.findIndex((h) => /description|name|item|memo/.test(h));
103
- const amountCol = headersLower.findIndex((h) => /amount|cost|price|total|debit/.test(h));
104
- const categoryCol = headersLower.findIndex((h) => /category|type|class|department/.test(h));
105
- const dateCol = headersLower.findIndex((h) => /date/.test(h));
201
+ const h = csv.headers.map(h => h.toLowerCase());
202
+ const descCol = findCol(h, /description|name|item|memo/);
203
+ const amountCol = findCol(h, /amount|cost|price|total/);
204
+ const categoryCol = findCol(h, /category|type|class|department/);
205
+ const dateCol = findCol(h, /date/);
106
206
  if (amountCol === -1)
107
207
  return [];
108
- return csv.rows.map((row) => ({
109
- description: descCol >= 0 ? row[descCol] : "Item",
110
- amount: parseFloat((row[amountCol] || "0").replace(/[$,]/g, "")) || 0,
111
- category: categoryCol >= 0 ? row[categoryCol] : "Uncategorized",
112
- date: dateCol >= 0 ? row[dateCol] : undefined,
113
- })).filter((e) => e.amount > 0);
208
+ return csv.rows.map(r => ({
209
+ description: descCol >= 0 ? r[descCol] : "Item",
210
+ amount: parseNum(r[amountCol]),
211
+ category: categoryCol >= 0 ? r[categoryCol] : "Uncategorized",
212
+ date: dateCol >= 0 ? r[dateCol] : undefined,
213
+ })).filter(e => e.amount > 0);
114
214
  }
115
- /**
116
- * Convert CSV data into chart parameters.
117
- */
118
- function csvToChart(csv, fileName) {
119
- if (csv.summary.numericColumns.length === 0)
120
- return null;
121
- const headersLower = csv.headers.map((h) => h.toLowerCase());
122
- const labelCol = headersLower.findIndex((h) => /name|description|category|date|month|item|label/.test(h));
123
- const numCol = csv.headers.findIndex((h) => csv.columnTypes[h] === "number" || csv.columnTypes[h] === "currency");
124
- if (numCol === -1)
125
- return null;
126
- const labels = labelCol >= 0
127
- ? csv.rows.map((r) => r[labelCol]).slice(0, 20)
128
- : csv.rows.map((_, i) => `Row ${i + 1}`).slice(0, 20);
129
- const data = csv.rows
130
- .map((r) => parseFloat((r[numCol] || "0").replace(/[$,]/g, "")))
131
- .filter((n) => !isNaN(n))
132
- .slice(0, 20);
133
- return {
134
- chart_type: data.length > 8 ? "line" : "bar",
135
- title: fileName.replace(/\.[^.]+$/, "").replace(/[_-]/g, " "),
136
- labels,
137
- datasets: [{ label: csv.headers[numCol], data }],
138
- };
215
+ function csvToInvoices(csv) {
216
+ const h = csv.headers.map(h => h.toLowerCase());
217
+ const customerCol = findCol(h, /customer|client|bill.?to/);
218
+ const invNumCol = findCol(h, /invoice|inv/);
219
+ const amountCol = findCol(h, /amount|total/);
220
+ const dateIssuedCol = findCol(h, /date.?issued|issue.?date|^date$/);
221
+ const dateDueCol = findCol(h, /due.?date|payment.?due/);
222
+ const statusCol = findCol(h, /status/);
223
+ const paidCol = findCol(h, /paid|payment/);
224
+ if (amountCol === -1)
225
+ return [];
226
+ return csv.rows.map(r => {
227
+ const status = statusCol >= 0 ? r[statusCol]?.toLowerCase() || "" : "";
228
+ const paid = paidCol >= 0 ? parseNum(r[paidCol]) : (status === "paid" ? parseNum(r[amountCol]) : 0);
229
+ return {
230
+ customer: customerCol >= 0 ? r[customerCol] : "Unknown",
231
+ invoice_number: invNumCol >= 0 ? r[invNumCol] : undefined,
232
+ amount: parseNum(r[amountCol]),
233
+ date_issued: dateIssuedCol >= 0 ? r[dateIssuedCol] : new Date().toISOString().split("T")[0],
234
+ date_due: dateDueCol >= 0 ? r[dateDueCol] : new Date().toISOString().split("T")[0],
235
+ amount_paid: paid,
236
+ };
237
+ }).filter(e => e.amount > 0);
238
+ }
239
+ function csvToBills(csv) {
240
+ const h = csv.headers.map(h => h.toLowerCase());
241
+ const vendorCol = findCol(h, /vendor|supplier|payee/);
242
+ const billNumCol = findCol(h, /bill|inv/);
243
+ const amountCol = findCol(h, /amount|total/);
244
+ const dateRecCol = findCol(h, /date.?received|receive|^date$/);
245
+ const dateDueCol = findCol(h, /due.?date/);
246
+ const paidCol = findCol(h, /paid|payment/);
247
+ if (amountCol === -1)
248
+ return [];
249
+ return csv.rows.map(r => ({
250
+ vendor: vendorCol >= 0 ? r[vendorCol] : "Unknown",
251
+ bill_number: billNumCol >= 0 ? r[billNumCol] : undefined,
252
+ amount: parseNum(r[amountCol]),
253
+ date_received: dateRecCol >= 0 ? r[dateRecCol] : new Date().toISOString().split("T")[0],
254
+ date_due: dateDueCol >= 0 ? r[dateDueCol] : new Date().toISOString().split("T")[0],
255
+ amount_paid: paidCol >= 0 ? parseNum(r[paidCol]) : 0,
256
+ })).filter(e => e.amount > 0);
257
+ }
258
+ function csvToBankTransactions(csv) {
259
+ const h = csv.headers.map(h => h.toLowerCase());
260
+ const dateCol = findCol(h, /date/);
261
+ const descCol = findCol(h, /description|desc|memo|payee/);
262
+ const amountCol = findCol(h, /amount|total/);
263
+ const typeCol = findCol(h, /^type$/);
264
+ const refCol = findCol(h, /reference|ref|check/);
265
+ if (amountCol === -1)
266
+ return [];
267
+ return csv.rows.map(r => {
268
+ const amount = parseNum(r[amountCol]);
269
+ let type = amount >= 0 ? "credit" : "debit";
270
+ if (typeCol >= 0) {
271
+ const t = (r[typeCol] || "").toLowerCase();
272
+ if (t === "debit")
273
+ type = "debit";
274
+ else if (t === "credit")
275
+ type = "credit";
276
+ }
277
+ return {
278
+ date: dateCol >= 0 ? r[dateCol] : "",
279
+ description: descCol >= 0 ? r[descCol] : "",
280
+ amount: Math.abs(amount),
281
+ type,
282
+ reference: refCol >= 0 ? r[refCol] : undefined,
283
+ };
284
+ }).filter(t => t.amount > 0);
285
+ }
286
+ function csvToBudget(csv) {
287
+ const h = csv.headers.map(h => h.toLowerCase());
288
+ const catCol = findCol(h, /category|item|line|department|account/);
289
+ const budgetCol = findCol(h, /budget|planned|forecast/);
290
+ const actualCol = findCol(h, /actual|spent|real/);
291
+ if (budgetCol === -1 || actualCol === -1)
292
+ return [];
293
+ return csv.rows.map(r => ({
294
+ category: catCol >= 0 ? r[catCol] : "Item",
295
+ budget: parseNum(r[budgetCol]),
296
+ actual: parseNum(r[actualCol]),
297
+ })).filter(l => l.budget > 0 || l.actual > 0);
298
+ }
299
+ function csvToPayroll(csv) {
300
+ const h = csv.headers.map(h => h.toLowerCase());
301
+ const nameCol = findCol(h, /employee|name/);
302
+ const typeCol = findCol(h, /^type$/);
303
+ const rateCol = findCol(h, /rate|salary|wage|pay/);
304
+ const hoursCol = findCol(h, /hours/);
305
+ const deptCol = findCol(h, /department|dept/);
306
+ if (nameCol === -1 || rateCol === -1)
307
+ return [];
308
+ return csv.rows.map(r => {
309
+ const type = typeCol >= 0 ? (r[typeCol]?.toLowerCase().includes("hourly") ? "hourly" : "salary") : "salary";
310
+ return {
311
+ name: r[nameCol] || "Employee",
312
+ type: type,
313
+ rate: parseNum(r[rateCol]),
314
+ hours: hoursCol >= 0 && r[hoursCol] ? parseNum(r[hoursCol]) : undefined,
315
+ };
316
+ }).filter(e => e.rate > 0);
317
+ }
318
+ function csvToSalesTax(csv) {
319
+ const h = csv.headers.map(h => h.toLowerCase());
320
+ const dateCol = findCol(h, /date/);
321
+ const descCol = findCol(h, /description|item/);
322
+ const amountCol = findCol(h, /amount|total|sales/);
323
+ const taxRateCol = findCol(h, /tax.?rate/);
324
+ const stateCol = findCol(h, /state/);
325
+ const taxableCol = findCol(h, /taxable/);
326
+ if (amountCol === -1)
327
+ return [];
328
+ return csv.rows.map(r => ({
329
+ date: dateCol >= 0 ? r[dateCol] : "",
330
+ description: descCol >= 0 ? r[descCol] : "Sale",
331
+ amount: parseNum(r[amountCol]),
332
+ tax_rate: taxRateCol >= 0 ? parseNum(r[taxRateCol]) : 0,
333
+ state: stateCol >= 0 ? r[stateCol] : undefined,
334
+ taxable: taxableCol >= 0 ? /yes|true|1/i.test(r[taxableCol]) : true,
335
+ })).filter(t => t.amount > 0);
336
+ }
337
+ function csvToAssets(csv) {
338
+ const h = csv.headers.map(h => h.toLowerCase());
339
+ const nameCol = findCol(h, /name|asset|description/);
340
+ const costCol = findCol(h, /cost|price|value/);
341
+ const salvageCol = findCol(h, /salvage|residual/);
342
+ const lifeCol = findCol(h, /useful.?life|lifespan|years/);
343
+ const acquiredCol = findCol(h, /acquired|purchase|date/);
344
+ if (costCol === -1)
345
+ return [];
346
+ return csv.rows.map(r => ({
347
+ name: nameCol >= 0 ? r[nameCol] : "Asset",
348
+ cost: parseNum(r[costCol]),
349
+ salvage_value: salvageCol >= 0 ? parseNum(r[salvageCol]) : 0,
350
+ useful_life_years: lifeCol >= 0 ? parseNum(r[lifeCol]) : 5,
351
+ date_acquired: acquiredCol >= 0 ? r[acquiredCol] : "2024-01-01",
352
+ })).filter(a => a.cost > 0);
353
+ }
354
+ function csvToDeptExpenses(csv) {
355
+ const h = csv.headers.map(h => h.toLowerCase());
356
+ const deptCol = findCol(h, /department|dept|team|division/);
357
+ const catCol = findCol(h, /category|type|class/);
358
+ const amountCol = findCol(h, /amount|cost|total/);
359
+ if (deptCol === -1 || amountCol === -1)
360
+ return [];
361
+ return csv.rows.map(r => ({
362
+ department: r[deptCol] || "General",
363
+ category: catCol >= 0 ? r[catCol] : "General",
364
+ amount: parseNum(r[amountCol]),
365
+ })).filter(e => e.amount > 0);
139
366
  }
140
- /**
141
- * Convert CSV data into P&L parameters.
142
- */
143
367
  function csvToPnl(csv) {
144
- const headersLower = csv.headers.map((h) => h.toLowerCase());
145
- const descCol = headersLower.findIndex((h) => /description|name|item/.test(h));
146
- const amountCol = headersLower.findIndex((h) => /amount|total/.test(h));
147
- const typeCol = headersLower.findIndex((h) => /type|category/.test(h));
368
+ const h = csv.headers.map(h => h.toLowerCase());
369
+ const descCol = findCol(h, /description|name|item/);
370
+ const amountCol = findCol(h, /amount|total/);
371
+ const typeCol = findCol(h, /type|category/);
148
372
  if (amountCol === -1)
149
373
  return null;
150
374
  const revenue = [];
151
375
  const expenses = [];
152
376
  for (const row of csv.rows) {
153
377
  const desc = descCol >= 0 ? row[descCol] : "Item";
154
- const amount = Math.abs(parseFloat((row[amountCol] || "0").replace(/[$,]/g, "")));
378
+ const amount = Math.abs(parseNum(row[amountCol]));
155
379
  const type = typeCol >= 0 ? row[typeCol].toLowerCase() : "";
156
380
  if (amount === 0)
157
381
  continue;
@@ -166,3 +390,23 @@ function csvToPnl(csv) {
166
390
  return null;
167
391
  return { revenue, expenses };
168
392
  }
393
+ function csvToChart(csv, fileName) {
394
+ if (csv.summary.numericColumns.length === 0)
395
+ return null;
396
+ const h = csv.headers.map(h => h.toLowerCase());
397
+ const labelCol = findCol(h, /name|description|category|month|item|label|employee/);
398
+ const numCol = csv.headers.findIndex(hdr => csv.columnTypes[hdr] === "number" || csv.columnTypes[hdr] === "currency");
399
+ if (numCol === -1)
400
+ return null;
401
+ const labels = labelCol >= 0 ? csv.rows.map(r => r[labelCol]).slice(0, 20) : csv.rows.map((_, i) => `Row ${i + 1}`).slice(0, 20);
402
+ const data = csv.rows.map(r => parseNum(r[numCol])).filter(n => !isNaN(n)).slice(0, 20);
403
+ // Pick chart type: line only for time-series data, bar for everything else
404
+ const isTimeSeries = labelCol >= 0 && csv.columnTypes[csv.headers[labelCol]] === "date";
405
+ const chartType = isTimeSeries ? "line" : "bar";
406
+ return {
407
+ chart_type: chartType,
408
+ title: fileName.replace(/\.[^.]+$/, "").replace(/[_-]/g, " "),
409
+ labels,
410
+ datasets: [{ label: csv.headers[numCol], data }],
411
+ };
412
+ }
@@ -9,12 +9,6 @@ export interface TaskOutput {
9
9
  }
10
10
  export type TaskHandler = (input: TaskInput) => Promise<TaskOutput>;
11
11
  declare const handlers: Record<string, TaskHandler>;
12
- /**
13
- * Check if we have a specialized handler for this task type.
14
- */
15
12
  export declare function hasHandler(type: string): boolean;
16
- /**
17
- * Run the specialized handler for a task type.
18
- */
19
13
  export declare function runHandler(task: TaskInput): Promise<TaskOutput>;
20
14
  export { handlers };
@@ -9,24 +9,44 @@ const expense_js_1 = require("./expense.js");
9
9
  const pnl_js_1 = require("./pnl.js");
10
10
  const smart_route_js_1 = require("./smart-route.js");
11
11
  const file_processor_js_1 = require("./file-processor.js");
12
+ const chat_js_1 = require("./chat.js");
13
+ const ar_aging_js_1 = require("./ar-aging.js");
14
+ const ap_aging_js_1 = require("./ap-aging.js");
15
+ const bank_reconciliation_js_1 = require("./bank-reconciliation.js");
16
+ const budget_vs_actuals_js_1 = require("./budget-vs-actuals.js");
17
+ const payroll_js_1 = require("./payroll.js");
18
+ const sales_tax_js_1 = require("./sales-tax.js");
19
+ const depreciation_js_1 = require("./depreciation.js");
20
+ const cash_flow_js_1 = require("./cash-flow.js");
21
+ const department_spending_js_1 = require("./department-spending.js");
22
+ const variance_analysis_js_1 = require("./variance-analysis.js");
23
+ const w2_1099_js_1 = require("./w2-1099.js");
12
24
  const handlers = {
25
+ // Original handlers
13
26
  chart: chart_js_1.handleChart,
14
27
  invoice: invoice_js_1.handleInvoice,
15
28
  expense_report: expense_js_1.handleExpenseReport,
16
29
  pnl: pnl_js_1.handlePnl,
17
30
  smart_route: smart_route_js_1.handleSmartRoute,
18
31
  process_file: file_processor_js_1.handleFileProcess,
32
+ chat: chat_js_1.handleChat,
33
+ // Tier 1 accounting handlers
34
+ ar_aging: ar_aging_js_1.handleARAging,
35
+ ap_aging: ap_aging_js_1.handleAPAging,
36
+ bank_reconciliation: bank_reconciliation_js_1.handleBankReconciliation,
37
+ budget_vs_actuals: budget_vs_actuals_js_1.handleBudgetVsActuals,
38
+ payroll: payroll_js_1.handlePayroll,
39
+ sales_tax: sales_tax_js_1.handleSalesTax,
40
+ depreciation: depreciation_js_1.handleDepreciation,
41
+ cash_flow: cash_flow_js_1.handleCashFlow,
42
+ department_spending: department_spending_js_1.handleDepartmentSpending,
43
+ variance_analysis: variance_analysis_js_1.handleVarianceAnalysis,
44
+ w2_1099: w2_1099_js_1.handleW21099,
19
45
  };
20
46
  exports.handlers = handlers;
21
- /**
22
- * Check if we have a specialized handler for this task type.
23
- */
24
47
  function hasHandler(type) {
25
48
  return type in handlers;
26
49
  }
27
- /**
28
- * Run the specialized handler for a task type.
29
- */
30
50
  async function runHandler(task) {
31
51
  const handler = handlers[task.type];
32
52
  if (!handler) {
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handlePayroll(task: TaskInput): Promise<TaskOutput>;