neuronix-node 0.2.0 → 0.5.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.
@@ -1,38 +1,82 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleExpenseReport = handleExpenseReport;
4
+ /**
5
+ * Format a date string to YYYY-MM-DD for proper Excel sorting.
6
+ */
7
+ function normalizeDate(dateStr) {
8
+ if (!dateStr)
9
+ return "";
10
+ // Already YYYY-MM-DD
11
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr))
12
+ return dateStr;
13
+ // M/D/YYYY or MM/DD/YYYY
14
+ const match = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
15
+ if (match)
16
+ return `${match[3]}-${match[1].padStart(2, "0")}-${match[2].padStart(2, "0")}`;
17
+ return dateStr;
18
+ }
19
+ /**
20
+ * Format a number as currency without trailing spaces.
21
+ */
22
+ function fmtCurrency(n) {
23
+ return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
24
+ }
25
+ /**
26
+ * Detect department from filename for merged file processing.
27
+ */
28
+ function detectDepartment(fileName) {
29
+ const lower = fileName.toLowerCase();
30
+ if (/marketing/.test(lower))
31
+ return "Marketing";
32
+ if (/operation/.test(lower))
33
+ return "Operations";
34
+ if (/tech/.test(lower))
35
+ return "Technology";
36
+ if (/hr|payroll|human/.test(lower))
37
+ return "HR & Payroll";
38
+ if (/travel|entertainment/.test(lower))
39
+ return "Travel & Entertainment";
40
+ if (/sales/.test(lower))
41
+ return "Sales";
42
+ if (/admin/.test(lower))
43
+ return "Administration";
44
+ return "General";
45
+ }
4
46
  async function handleExpenseReport(task) {
5
47
  const start = Date.now();
6
48
  const input = task.input_payload;
7
49
  const period = input.period || "Current Period";
50
+ const mergedFrom = input.merged_from || [];
8
51
  const expenses = input.expenses || [
9
52
  { description: "Office Supplies", amount: 245.50, category: "Operations", date: "2026-03-01" },
10
53
  { description: "Software Subscriptions", amount: 890.00, category: "Technology", date: "2026-03-05" },
11
54
  { description: "Team Lunch", amount: 156.75, category: "Meals", date: "2026-03-08" },
12
- { description: "Cloud Hosting", amount: 432.00, category: "Technology", date: "2026-03-10" },
13
- { description: "Marketing Ads", amount: 1200.00, category: "Marketing", date: "2026-03-12" },
14
- { description: "Travel - Client Meeting", amount: 387.25, category: "Travel", date: "2026-03-15" },
15
- { description: "Printer Ink", amount: 89.99, category: "Operations", date: "2026-03-18" },
16
- { description: "Conference Tickets", amount: 599.00, category: "Education", date: "2026-03-20" },
17
55
  ];
56
+ // Assign departments from merged file names if available
57
+ if (mergedFrom.length > 0 && expenses.every((e) => !e.department)) {
58
+ // Try to detect department from category patterns
59
+ for (const exp of expenses) {
60
+ exp.department = detectDepartmentFromCategory(exp.category);
61
+ }
62
+ }
63
+ // Sort by amount descending
64
+ const sorted = [...expenses].sort((a, b) => b.amount - a.amount);
18
65
  // Calculate totals by category
19
66
  const byCategory = {};
20
67
  let total = 0;
21
68
  for (const exp of expenses) {
22
69
  total += exp.amount;
23
70
  if (!byCategory[exp.category]) {
24
- byCategory[exp.category] = { total: 0, count: 0, items: [] };
71
+ byCategory[exp.category] = { total: 0, count: 0 };
25
72
  }
26
73
  byCategory[exp.category].total += exp.amount;
27
74
  byCategory[exp.category].count += 1;
28
- byCategory[exp.category].items.push(exp);
29
75
  }
30
- // Round totals
31
76
  total = Math.round(total * 100) / 100;
32
77
  for (const cat of Object.keys(byCategory)) {
33
78
  byCategory[cat].total = Math.round(byCategory[cat].total * 100) / 100;
34
79
  }
35
- // Sort categories by total descending
36
80
  const sortedCategories = Object.entries(byCategory)
37
81
  .sort((a, b) => b[1].total - a[1].total)
38
82
  .map(([name, data]) => ({
@@ -41,41 +85,110 @@ async function handleExpenseReport(task) {
41
85
  count: data.count,
42
86
  percentage: Math.round((data.total / total) * 1000) / 10,
43
87
  }));
44
- // Generate chart data for the frontend
88
+ // Calculate by department if available
89
+ const hasDepartments = sorted.some((e) => e.department);
90
+ const byDepartment = {};
91
+ if (hasDepartments) {
92
+ for (const exp of expenses) {
93
+ const dept = exp.department || "General";
94
+ if (!byDepartment[dept])
95
+ byDepartment[dept] = { total: 0, count: 0 };
96
+ byDepartment[dept].total += exp.amount;
97
+ byDepartment[dept].count += 1;
98
+ }
99
+ }
100
+ const sortedDepartments = Object.entries(byDepartment)
101
+ .sort((a, b) => b[1].total - a[1].total)
102
+ .map(([name, data]) => ({
103
+ department: name,
104
+ total: Math.round(data.total * 100) / 100,
105
+ count: data.count,
106
+ percentage: Math.round((data.total / total) * 1000) / 10,
107
+ }));
108
+ // Chart data
45
109
  const chartData = {
46
110
  chart_type: "doughnut",
47
111
  title: `Expenses by Category — ${period}`,
48
112
  labels: sortedCategories.map((c) => c.category),
49
- datasets: [{
50
- label: "Expenses",
51
- data: sortedCategories.map((c) => c.total),
52
- }],
113
+ datasets: [{ label: "Expenses", data: sortedCategories.map((c) => c.total) }],
53
114
  };
54
115
  // Summary text
55
116
  const summaryLines = [
56
117
  `Expense Report: ${period}`,
57
- `Total: $${total.toFixed(2)} across ${expenses.length} expenses`,
118
+ `Total: ${fmtCurrency(total)} across ${expenses.length} expenses in ${sortedCategories.length} categories`,
58
119
  ``,
59
- `By Category:`,
60
- ...sortedCategories.map((c) => ` ${c.category}: $${c.total.toFixed(2)} (${c.percentage}%) — ${c.count} item${c.count > 1 ? "s" : ""}`),
120
+ `Top Categories:`,
121
+ ...sortedCategories.slice(0, 10).map((c) => ` ${c.category}: ${fmtCurrency(c.total)} (${c.percentage}%) — ${c.count} items`),
61
122
  ``,
62
- `Largest expense: ${expenses.sort((a, b) => b.amount - a.amount)[0].description} ($${expenses.sort((a, b) => b.amount - a.amount)[0].amount.toFixed(2)})`,
63
- ];
64
- // Generate CSV output
65
- const csvLines = [
66
- "EXPENSE REPORT",
67
- `Period,${period}`,
68
- "",
69
- "EXPENSES BY ITEM",
70
- "Date,Description,Amount,Category",
71
- ...expenses.map((e) => `${e.date || ""},${csvEscape(e.description)},$${e.amount.toFixed(2)},${csvEscape(e.category)}`),
72
- "",
73
- "SUMMARY BY CATEGORY",
74
- "Category,Total,% of Total,Item Count",
75
- ...sortedCategories.map((c) => `${csvEscape(c.category)},$${c.total.toFixed(2)},${c.percentage}%,${c.count}`),
76
- "",
77
- `TOTAL,,$${total.toFixed(2)},${expenses.length} items`,
123
+ `Largest expense: ${sorted[0].description} (${fmtCurrency(sorted[0].amount)})`,
124
+ `Smallest expense: ${sorted[sorted.length - 1].description} (${fmtCurrency(sorted[sorted.length - 1].amount)})`,
78
125
  ];
126
+ // ── Build clean CSV output ────────────────────────────────
127
+ const csvLines = [];
128
+ const hasDept = hasDepartments;
129
+ const itemHeaders = hasDept
130
+ ? "Date,Department,Description,Category,Amount"
131
+ : "Date,Description,Category,Amount";
132
+ // Report header
133
+ csvLines.push("EXPENSE REPORT");
134
+ csvLines.push(`Period: ${period}`);
135
+ csvLines.push(`Generated: ${new Date().toISOString().split("T")[0]}`);
136
+ if (mergedFrom.length > 0) {
137
+ csvLines.push(`Sources: ${mergedFrom.length} files merged`);
138
+ }
139
+ csvLines.push(`Total Items: ${expenses.length}`);
140
+ csvLines.push(`Grand Total: ${fmtCurrency(total)}`);
141
+ csvLines.push("");
142
+ // Section 1: All expenses sorted by amount
143
+ csvLines.push("DETAILED EXPENSES (sorted by amount)");
144
+ csvLines.push(itemHeaders);
145
+ for (const exp of sorted) {
146
+ const date = normalizeDate(exp.date);
147
+ const desc = csvEscape(exp.description);
148
+ const cat = csvEscape(exp.category);
149
+ const amt = fmtCurrency(exp.amount);
150
+ if (hasDept) {
151
+ csvLines.push(`${date},${csvEscape(exp.department || "General")},${desc},${cat},${amt}`);
152
+ }
153
+ else {
154
+ csvLines.push(`${date},${desc},${cat},${amt}`);
155
+ }
156
+ }
157
+ // Subtotal row
158
+ if (hasDept) {
159
+ csvLines.push(`,,,,`);
160
+ csvLines.push(`,,,SUBTOTAL,${fmtCurrency(total)}`);
161
+ }
162
+ else {
163
+ csvLines.push(`,,,`);
164
+ csvLines.push(`,,SUBTOTAL,${fmtCurrency(total)}`);
165
+ }
166
+ csvLines.push("");
167
+ // Section 2: Summary by category
168
+ csvLines.push("SUMMARY BY CATEGORY");
169
+ csvLines.push("Category,Amount,% of Total,Item Count");
170
+ for (const c of sortedCategories) {
171
+ csvLines.push(`${csvEscape(c.category)},${fmtCurrency(c.total)},${c.percentage}%,${c.count}`);
172
+ }
173
+ csvLines.push("");
174
+ // Section 3: Summary by department (if merged)
175
+ if (hasDept && sortedDepartments.length > 0) {
176
+ csvLines.push("SUMMARY BY DEPARTMENT");
177
+ csvLines.push("Department,Amount,% of Total,Item Count");
178
+ for (const d of sortedDepartments) {
179
+ csvLines.push(`${csvEscape(d.department)},${fmtCurrency(d.total)},${d.percentage}%,${d.count}`);
180
+ }
181
+ csvLines.push("");
182
+ }
183
+ // Grand total
184
+ csvLines.push("GRAND TOTAL");
185
+ csvLines.push(`Total Expenses,${fmtCurrency(total)}`);
186
+ csvLines.push(`Total Items,${expenses.length}`);
187
+ csvLines.push(`Total Categories,${sortedCategories.length}`);
188
+ if (hasDept)
189
+ csvLines.push(`Total Departments,${sortedDepartments.length}`);
190
+ csvLines.push(`Largest Expense,${csvEscape(sorted[0].description)} (${fmtCurrency(sorted[0].amount)})`);
191
+ csvLines.push(`Average Expense,${fmtCurrency(Math.round((total / expenses.length) * 100) / 100)}`);
79
192
  const durationMs = Date.now() - start;
80
193
  return {
81
194
  text: summaryLines.join("\n"),
@@ -86,10 +199,12 @@ async function handleExpenseReport(task) {
86
199
  expense_count: expenses.length,
87
200
  category_count: sortedCategories.length,
88
201
  largest_category: sortedCategories[0]?.category,
89
- largest_expense: expenses.sort((a, b) => b.amount - a.amount)[0],
202
+ largest_expense: sorted[0],
203
+ average_expense: Math.round((total / expenses.length) * 100) / 100,
90
204
  },
91
205
  by_category: sortedCategories,
92
- expenses,
206
+ by_department: sortedDepartments.length > 0 ? sortedDepartments : undefined,
207
+ expenses: sorted,
93
208
  chart_data: chartData,
94
209
  duration_ms: durationMs,
95
210
  };
@@ -100,3 +215,19 @@ function csvEscape(value) {
100
215
  }
101
216
  return value;
102
217
  }
218
+ function detectDepartmentFromCategory(category) {
219
+ const lower = category.toLowerCase();
220
+ if (/payroll|benefits|recruiting|onboarding|training|employee|hr|insurance|safety/.test(lower))
221
+ return "HR & Payroll";
222
+ if (/digital|marketing|pr|creative|print|email|influencer|affiliate|content|seo|advertising/.test(lower))
223
+ return "Marketing";
224
+ if (/cloud|software|hardware|ai|infrastructure|security/.test(lower))
225
+ return "Technology";
226
+ if (/rent|utilities|maintenance|office supplies|equipment|furniture/.test(lower))
227
+ return "Operations";
228
+ if (/airfare|lodging|hotel|transport|conference|entertainment|team meal/.test(lower))
229
+ return "Travel & Entertainment";
230
+ if (/consulting/.test(lower))
231
+ return "Consulting";
232
+ return "General";
233
+ }
@@ -29,7 +29,7 @@ async function handleFileProcess(task) {
29
29
  if (expenses.length > 0) {
30
30
  const result = await (0, expense_js_1.handleExpenseReport)({
31
31
  type: "expense_report",
32
- input_payload: { expenses },
32
+ input_payload: { expenses, merged_from: payload.merged_from },
33
33
  });
34
34
  return {
35
35
  ...result,
@@ -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>;
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handlePayroll = handlePayroll;
4
+ async function handlePayroll(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.pay_period || "Bi-Weekly";
8
+ const fedRate = input.federal_tax_rate || 0.22;
9
+ const stateRate = input.state_tax_rate || 0.05;
10
+ const ficaRate = input.fica_rate || 0.062;
11
+ const medicareRate = input.medicare_rate || 0.0145;
12
+ const periodsPerYear = period === "Weekly" ? 52 : period === "Bi-Weekly" ? 26 : period === "Semi-Monthly" ? 24 : 12;
13
+ const employees = input.employees || [
14
+ { name: "John Smith", type: "salary", rate: 85000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (6%)", amount: 196.15 }] },
15
+ { name: "Jane Doe", type: "salary", rate: 72000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (4%)", amount: 110.77 }] },
16
+ { name: "Bob Wilson", type: "hourly", rate: 28.50, hours: 80, deductions: [{ name: "Health Insurance", amount: 180 }] },
17
+ { name: "Alice Chen", type: "salary", rate: 95000, deductions: [{ name: "Health Insurance", amount: 250 }, { name: "401k (8%)", amount: 292.31 }, { name: "HSA", amount: 100 }] },
18
+ { name: "Mike Torres", type: "hourly", rate: 22.00, hours: 84, deductions: [{ name: "Health Insurance", amount: 180 }] },
19
+ ];
20
+ let totalGross = 0, totalFed = 0, totalState = 0, totalFica = 0, totalMedicare = 0, totalDeductions = 0, totalNet = 0, totalEmployerFica = 0, totalEmployerMedicare = 0;
21
+ const payStubs = employees.map(emp => {
22
+ const gross = emp.type === "salary" ? round(emp.rate / periodsPerYear) : round((emp.rate) * (emp.hours || 80));
23
+ const overtimeHours = emp.type === "hourly" && (emp.hours || 0) > 80 ? (emp.hours || 0) - 80 : 0;
24
+ const overtimePay = emp.type === "hourly" ? round(overtimeHours * emp.rate * 0.5) : 0;
25
+ const totalGrossPay = round(gross + overtimePay);
26
+ const fedTax = round(totalGrossPay * fedRate);
27
+ const stateTax = round(totalGrossPay * stateRate);
28
+ const ficaTax = round(totalGrossPay * ficaRate);
29
+ const medicareTax = round(totalGrossPay * medicareRate);
30
+ const totalTax = round(fedTax + stateTax + ficaTax + medicareTax);
31
+ const deductionTotal = round((emp.deductions || []).reduce((s, d) => s + d.amount, 0));
32
+ const netPay = round(totalGrossPay - totalTax - deductionTotal);
33
+ const employerFica = ficaTax;
34
+ const employerMedicare = medicareTax;
35
+ totalGross += totalGrossPay;
36
+ totalFed += fedTax;
37
+ totalState += stateTax;
38
+ totalFica += ficaTax;
39
+ totalMedicare += medicareTax;
40
+ totalDeductions += deductionTotal;
41
+ totalNet += netPay;
42
+ totalEmployerFica += employerFica;
43
+ totalEmployerMedicare += employerMedicare;
44
+ return {
45
+ name: emp.name, type: emp.type, hours: emp.hours, rate: emp.rate,
46
+ gross: totalGrossPay, overtime_pay: overtimePay,
47
+ federal_tax: fedTax, state_tax: stateTax, fica: ficaTax, medicare: medicareTax,
48
+ total_tax: totalTax, deductions: emp.deductions || [], deduction_total: deductionTotal,
49
+ net_pay: netPay, employer_fica: employerFica, employer_medicare: employerMedicare,
50
+ };
51
+ });
52
+ totalGross = round(totalGross);
53
+ totalNet = round(totalNet);
54
+ totalDeductions = round(totalDeductions);
55
+ const totalTaxes = round(totalFed + totalState + totalFica + totalMedicare);
56
+ const totalEmployerCost = round(totalGross + totalEmployerFica + totalEmployerMedicare);
57
+ const csv = [
58
+ "PAYROLL REGISTER",
59
+ `Pay Period: ${period}`,
60
+ `Date: ${new Date().toISOString().split("T")[0]}`,
61
+ `Employees: ${employees.length}`,
62
+ "",
63
+ "EMPLOYEE DETAIL",
64
+ "Name,Type,Rate,Hours,Gross Pay,Federal Tax,State Tax,FICA,Medicare,Deductions,Net Pay",
65
+ ...payStubs.map(p => `${esc(p.name)},${p.type},${p.type === "salary" ? fmt(p.rate) + "/yr" : fmt(p.rate) + "/hr"},${p.hours || "N/A"},${fmt(p.gross)},${fmt(p.federal_tax)},${fmt(p.state_tax)},${fmt(p.fica)},${fmt(p.medicare)},${fmt(p.deduction_total)},${fmt(p.net_pay)}`),
66
+ "",
67
+ `TOTALS,,,,${fmt(totalGross)},${fmt(totalFed)},${fmt(round(totalState))},${fmt(round(totalFica))},${fmt(round(totalMedicare))},${fmt(totalDeductions)},${fmt(totalNet)}`,
68
+ "",
69
+ "DEDUCTION DETAIL",
70
+ "Employee,Deduction,Amount",
71
+ ...payStubs.flatMap(p => p.deductions.map(d => `${esc(p.name)},${esc(d.name)},${fmt(d.amount)}`)),
72
+ "",
73
+ "TAX SUMMARY",
74
+ `Federal Income Tax,${fmt(round(totalFed))}`,
75
+ `State Income Tax,${fmt(round(totalState))}`,
76
+ `Employee FICA (Social Security),${fmt(round(totalFica))}`,
77
+ `Employee Medicare,${fmt(round(totalMedicare))}`,
78
+ `Total Employee Taxes,${fmt(totalTaxes)}`,
79
+ "",
80
+ "EMPLOYER OBLIGATIONS",
81
+ `Employer FICA Match,${fmt(round(totalEmployerFica))}`,
82
+ `Employer Medicare Match,${fmt(round(totalEmployerMedicare))}`,
83
+ `Total Employer Taxes,${fmt(round(totalEmployerFica + totalEmployerMedicare))}`,
84
+ "",
85
+ "GRAND TOTALS",
86
+ `Total Gross Pay,${fmt(totalGross)}`,
87
+ `Total Deductions,${fmt(totalDeductions)}`,
88
+ `Total Taxes (Employee),${fmt(totalTaxes)}`,
89
+ `Total Net Pay,${fmt(totalNet)}`,
90
+ `Total Employer Cost,${fmt(totalEmployerCost)}`,
91
+ ];
92
+ return {
93
+ text: `Payroll: ${employees.length} employees | Gross: ${fmt(totalGross)} | Net: ${fmt(totalNet)} | Employer Cost: ${fmt(totalEmployerCost)}`,
94
+ output_csv: csv.join("\n"),
95
+ summary: { employee_count: employees.length, total_gross: totalGross, total_net: totalNet, total_taxes: totalTaxes, total_deductions: totalDeductions, employer_cost: totalEmployerCost },
96
+ duration_ms: Date.now() - start,
97
+ };
98
+ }
99
+ function round(n) { return Math.round(n * 100) / 100; }
100
+ function fmt(n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
101
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleSalesTax(task: TaskInput): Promise<TaskOutput>;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleSalesTax = handleSalesTax;
4
+ async function handleSalesTax(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.period || "Current Period";
8
+ const transactions = input.transactions || [
9
+ { date: "2026-03-01", description: "Product Sale - Widget A", amount: 1200, tax_rate: 0.0725, state: "CA", taxable: true },
10
+ { date: "2026-03-03", description: "Consulting Service", amount: 5000, tax_rate: 0, state: "CA", taxable: false },
11
+ { date: "2026-03-05", description: "Product Sale - Widget B", amount: 850, tax_rate: 0.0725, state: "CA", taxable: true },
12
+ { date: "2026-03-08", description: "Product Sale - Online (TX)", amount: 2300, tax_rate: 0.0625, state: "TX", taxable: true },
13
+ { date: "2026-03-12", description: "SaaS Subscription", amount: 499, tax_rate: 0, taxable: false },
14
+ { date: "2026-03-15", description: "Product Sale - Widget C", amount: 3400, tax_rate: 0.0725, state: "CA", taxable: true },
15
+ { date: "2026-03-20", description: "Product Sale - Online (NY)", amount: 1800, tax_rate: 0.08, state: "NY", taxable: true },
16
+ ];
17
+ let totalSales = 0, totalTaxable = 0, totalExempt = 0, totalTaxCollected = 0;
18
+ const byState = {};
19
+ for (const txn of transactions) {
20
+ totalSales += txn.amount;
21
+ if (txn.taxable !== false && txn.tax_rate > 0) {
22
+ const tax = round(txn.amount * txn.tax_rate);
23
+ totalTaxable += txn.amount;
24
+ totalTaxCollected += tax;
25
+ const st = txn.state || "Unknown";
26
+ if (!byState[st])
27
+ byState[st] = { sales: 0, taxable: 0, tax: 0, rate: txn.tax_rate, count: 0 };
28
+ byState[st].sales += txn.amount;
29
+ byState[st].taxable += txn.amount;
30
+ byState[st].tax += tax;
31
+ byState[st].count += 1;
32
+ }
33
+ else {
34
+ totalExempt += txn.amount;
35
+ }
36
+ }
37
+ totalSales = round(totalSales);
38
+ totalTaxable = round(totalTaxable);
39
+ totalExempt = round(totalExempt);
40
+ totalTaxCollected = round(totalTaxCollected);
41
+ const stateSummary = Object.entries(byState).sort((a, b) => b[1].tax - a[1].tax).map(([st, d]) => ({
42
+ state: st, sales: round(d.sales), taxable: round(d.taxable), tax_collected: round(d.tax), rate: d.rate, transactions: d.count,
43
+ }));
44
+ const csv = [
45
+ "SALES TAX REPORT",
46
+ `Period: ${period}`,
47
+ `Generated: ${new Date().toISOString().split("T")[0]}`,
48
+ "",
49
+ "SUMMARY",
50
+ `Total Sales,${fmt(totalSales)}`,
51
+ `Taxable Sales,${fmt(totalTaxable)}`,
52
+ `Exempt Sales,${fmt(totalExempt)}`,
53
+ `Total Tax Collected,${fmt(totalTaxCollected)}`,
54
+ `Effective Tax Rate,${totalTaxable > 0 ? round((totalTaxCollected / totalTaxable) * 100) : 0}%`,
55
+ "",
56
+ "BY STATE/JURISDICTION",
57
+ "State,Taxable Sales,Tax Rate,Tax Collected,Transactions",
58
+ ...stateSummary.map(s => `${s.state},${fmt(s.taxable)},${(s.rate * 100).toFixed(2)}%,${fmt(s.tax_collected)},${s.transactions}`),
59
+ "",
60
+ "TRANSACTION DETAIL",
61
+ "Date,Description,Amount,Taxable,Tax Rate,Tax Amount,State",
62
+ ...transactions.map(t => {
63
+ const tax = (t.taxable !== false && t.tax_rate > 0) ? round(t.amount * t.tax_rate) : 0;
64
+ return `${t.date},${esc(t.description)},${fmt(t.amount)},${t.taxable !== false && t.tax_rate > 0 ? "Yes" : "No"},${(t.tax_rate * 100).toFixed(2)}%,${fmt(tax)},${t.state || ""}`;
65
+ }),
66
+ "",
67
+ "TAX LIABILITY",
68
+ `Total Tax Owed,${fmt(totalTaxCollected)}`,
69
+ `Filing Deadline,${getNextQuarterEnd()}`,
70
+ ];
71
+ return {
72
+ text: `Sales Tax: ${fmt(totalTaxCollected)} collected on ${fmt(totalTaxable)} taxable sales (${stateSummary.length} jurisdictions)`,
73
+ output_csv: csv.join("\n"),
74
+ summary: { total_sales: totalSales, total_taxable: totalTaxable, total_exempt: totalExempt, total_tax: totalTaxCollected, jurisdictions: stateSummary.length },
75
+ by_state: stateSummary,
76
+ duration_ms: Date.now() - start,
77
+ };
78
+ }
79
+ function getNextQuarterEnd() {
80
+ const now = new Date();
81
+ const m = now.getMonth();
82
+ const q = m < 3 ? 0 : m < 6 ? 1 : m < 9 ? 2 : 3;
83
+ const deadlines = ["04-30", "07-31", "10-31", "01-31"];
84
+ const year = q === 3 ? now.getFullYear() + 1 : now.getFullYear();
85
+ return `${year}-${deadlines[q]}`;
86
+ }
87
+ function round(n) { return Math.round(n * 100) / 100; }
88
+ function fmt(n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
89
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleVarianceAnalysis(task: TaskInput): Promise<TaskOutput>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleVarianceAnalysis = handleVarianceAnalysis;
4
+ async function handleVarianceAnalysis(task) {
5
+ const start = Date.now();
6
+ const input = task.input_payload;
7
+ const period = input.period || "Current Period";
8
+ const threshold = input.threshold_pct || 10;
9
+ const lines = input.lines || [
10
+ { item: "Product Revenue", budget: 120000, actual: 115000, category: "Revenue" },
11
+ { item: "Service Revenue", budget: 80000, actual: 92000, category: "Revenue" },
12
+ { item: "Cost of Goods Sold", budget: 48000, actual: 52000, category: "COGS" },
13
+ { item: "Salaries", budget: 70000, actual: 72800, category: "OpEx" },
14
+ { item: "Marketing", budget: 15000, actual: 22000, category: "OpEx" },
15
+ { item: "Rent", budget: 8500, actual: 8500, category: "OpEx" },
16
+ { item: "Technology", budget: 10000, actual: 14200, category: "OpEx" },
17
+ { item: "Travel", budget: 5000, actual: 8900, category: "OpEx" },
18
+ { item: "Office Supplies", budget: 2000, actual: 1650, category: "OpEx" },
19
+ { item: "Insurance", budget: 3200, actual: 3200, category: "OpEx" },
20
+ ];
21
+ const analyzed = lines.map(l => {
22
+ const variance = round(l.actual - l.budget);
23
+ const variancePct = l.budget !== 0 ? round((variance / Math.abs(l.budget)) * 100) : 0;
24
+ const favorable = l.category === "Revenue" ? variance >= 0 : variance <= 0;
25
+ const significant = Math.abs(variancePct) >= threshold;
26
+ return { ...l, variance, variance_pct: variancePct, favorable, significant };
27
+ });
28
+ const significant = analyzed.filter(l => l.significant);
29
+ const favorableItems = analyzed.filter(l => l.favorable && l.variance !== 0);
30
+ const unfavorableItems = analyzed.filter(l => !l.favorable && l.variance !== 0);
31
+ const totalBudget = round(lines.reduce((s, l) => s + l.budget, 0));
32
+ const totalActual = round(lines.reduce((s, l) => s + l.actual, 0));
33
+ const totalVariance = round(totalActual - totalBudget);
34
+ const csv = [
35
+ "VARIANCE ANALYSIS REPORT",
36
+ `Period: ${period}`,
37
+ `Generated: ${new Date().toISOString().split("T")[0]}`,
38
+ `Significance Threshold: ${threshold}%`,
39
+ "",
40
+ "DETAILED ANALYSIS",
41
+ "Item,Category,Budget,Actual,Variance ($),Variance (%),Favorable?,Significant?",
42
+ ...analyzed.map(l => `${esc(l.item)},${l.category || ""},${fmt(l.budget)},${fmt(l.actual)},${l.variance >= 0 ? "+" : ""}${fmt(l.variance)},${l.variance_pct >= 0 ? "+" : ""}${l.variance_pct}%,${l.favorable ? "Yes" : "No"},${l.significant ? "YES" : "No"}`),
43
+ "",
44
+ "SIGNIFICANT VARIANCES (>${threshold}%)",
45
+ "Item,Variance ($),Variance (%),Impact",
46
+ ...significant.sort((a, b) => Math.abs(b.variance_pct) - Math.abs(a.variance_pct)).map(l => `${esc(l.item)},${l.variance >= 0 ? "+" : ""}${fmt(l.variance)},${l.variance_pct >= 0 ? "+" : ""}${l.variance_pct}%,${l.favorable ? "Favorable" : "Unfavorable"}`),
47
+ "",
48
+ "FAVORABLE VARIANCES",
49
+ "Item,Amount Saved/Gained",
50
+ ...favorableItems.map(l => `${esc(l.item)},${fmt(Math.abs(l.variance))}`),
51
+ "",
52
+ "UNFAVORABLE VARIANCES",
53
+ "Item,Amount Over/Under",
54
+ ...unfavorableItems.map(l => `${esc(l.item)},${fmt(Math.abs(l.variance))}`),
55
+ "",
56
+ "SUMMARY",
57
+ `Total Budget,${fmt(totalBudget)}`,
58
+ `Total Actual,${fmt(totalActual)}`,
59
+ `Net Variance,${totalVariance >= 0 ? "+" : ""}${fmt(totalVariance)}`,
60
+ `Significant Variances,${significant.length} of ${analyzed.length} items`,
61
+ `Favorable Items,${favorableItems.length}`,
62
+ `Unfavorable Items,${unfavorableItems.length}`,
63
+ ];
64
+ return {
65
+ text: `Variance Analysis: ${significant.length} significant variances (>${threshold}%) | Net: ${totalVariance >= 0 ? "+" : ""}${fmt(totalVariance)}`,
66
+ output_csv: csv.join("\n"),
67
+ summary: { total_budget: totalBudget, total_actual: totalActual, total_variance: totalVariance, significant_count: significant.length, favorable_count: favorableItems.length, unfavorable_count: unfavorableItems.length },
68
+ duration_ms: Date.now() - start,
69
+ };
70
+ }
71
+ function round(n) { return Math.round(n * 100) / 100; }
72
+ function fmt(n) { return "$" + Math.abs(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
73
+ function esc(v) { return v.includes(",") ? `"${v}"` : v; }
@@ -0,0 +1,2 @@
1
+ import type { TaskInput, TaskOutput } from "./index.js";
2
+ export declare function handleW21099(task: TaskInput): Promise<TaskOutput>;