@mpurdon/mcp-freshbooks 0.1.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.
@@ -0,0 +1,235 @@
1
+ /**
2
+ * generate_invoice tool — fetches FreshBooks time entries for a date range,
3
+ * groups them by project + service, looks up the billable rate for each
4
+ * service, and creates a draft invoice for the Trajector client.
5
+ *
6
+ * The line-item format exactly matches the Python fb.py script:
7
+ * name → service name (e.g. "Principal Engineer")
8
+ * description → "(Project Name) Matthew Purdon – Apr 16, 2026 - Apr 30, 2026"
9
+ * qty → total hours for that service (decimal)
10
+ * unit_cost → billable rate from the FreshBooks project service record
11
+ * type → 0 (item/service)
12
+ */
13
+ import path from "node:path";
14
+ import os from "node:os";
15
+ import fs from "node:fs/promises";
16
+ import { z } from "zod";
17
+ // ── Timesheet path helper ─────────────────────────────────────────────────────
18
+ const OUTPUT_DIR = path.join(os.homedir(), "Documents", "trajector", "timesheets");
19
+ /** Returns the expected timesheet path for a given end_date (end_date + 1 day). */
20
+ function timesheetPathForPeriod(endDate) {
21
+ const dt = new Date(`${endDate}T12:00:00Z`);
22
+ dt.setUTCDate(dt.getUTCDate() + 1);
23
+ const sendDate = dt.toISOString().slice(0, 10);
24
+ return path.join(OUTPUT_DIR, `Consultant-Bi-Weekly-Timesheet ${sendDate}.xlsx`);
25
+ }
26
+ // ── Constants ─────────────────────────────────────────────────────────────────
27
+ const TRAJECTOR_CLIENT_ID = 688912;
28
+ // ── Input schema ──────────────────────────────────────────────────────────────
29
+ export const GenerateInvoiceInput = z
30
+ .object({
31
+ start_date: z
32
+ .string()
33
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
34
+ .describe("YYYY-MM-DD — start of billing period"),
35
+ end_date: z
36
+ .string()
37
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
38
+ .describe("YYYY-MM-DD — end of billing period"),
39
+ invoice_number: z
40
+ .string()
41
+ .max(50)
42
+ .optional()
43
+ .describe("Override the auto-assigned invoice number"),
44
+ create_date: z
45
+ .string()
46
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
47
+ .optional()
48
+ .describe("Invoice date (YYYY-MM-DD). Defaults to today."),
49
+ due_offset_days: z
50
+ .number()
51
+ .int()
52
+ .min(0)
53
+ .max(365)
54
+ .optional()
55
+ .default(0)
56
+ .describe("Days after create_date when the invoice is due."),
57
+ draft: z
58
+ .boolean()
59
+ .optional()
60
+ .default(true)
61
+ .describe("Create as draft (true) or immediately mark as sent (false)."),
62
+ })
63
+ .strict();
64
+ // ── Helpers ───────────────────────────────────────────────────────────────────
65
+ /** Format a YYYY-MM-DD date as "Apr 16, 2026" */
66
+ function formatDate(ymd) {
67
+ const [year, month, day] = ymd.split("-").map(Number);
68
+ const d = new Date(year, month - 1, day);
69
+ return d.toLocaleDateString("en-US", {
70
+ month: "short",
71
+ day: "numeric",
72
+ year: "numeric",
73
+ });
74
+ }
75
+ /** Round to 2 decimal places, returning as a number */
76
+ function round2(n) {
77
+ return Math.round(n * 100) / 100;
78
+ }
79
+ // ── FreshBooks data layer ─────────────────────────────────────────────────────
80
+ async function fetchProjectsWithRates(client) {
81
+ const data = await client.request("GET", `/projects/business/${client.businessId}/projects`, {
82
+ query: { active: "true", client_id: TRAJECTOR_CLIENT_ID },
83
+ });
84
+ const map = new Map();
85
+ for (const p of data.projects ?? []) {
86
+ const svcMap = new Map();
87
+ for (const s of p.services ?? []) {
88
+ const rawRate = s.rate ?? s.unit_cost ?? s.hourly_rate ?? s.price ?? null;
89
+ const rate = rawRate !== null ? Number(rawRate) : null;
90
+ svcMap.set(s.id, {
91
+ name: s.name,
92
+ rate: Number.isFinite(rate) ? rate : null,
93
+ });
94
+ }
95
+ map.set(p.id, { title: p.title, services: svcMap });
96
+ }
97
+ return map;
98
+ }
99
+ async function fetchTimeEntries(client, startDate, endDate) {
100
+ const data = await client.request("GET", `/timetracking/business/${client.businessId}/time_entries`, {
101
+ query: {
102
+ client_id: TRAJECTOR_CLIENT_ID,
103
+ started_from: `${startDate}T00:00:00Z`,
104
+ started_to: `${endDate}T23:59:59Z`,
105
+ per_page: 100,
106
+ },
107
+ });
108
+ return (data.time_entries ?? [])
109
+ .filter((e) => e.active !== false)
110
+ .map((e) => ({
111
+ projectId: e.project_id,
112
+ serviceId: e.service_id,
113
+ duration: e.duration,
114
+ }));
115
+ }
116
+ // ── Core logic ────────────────────────────────────────────────────────────────
117
+ function groupEntries(entries, projects) {
118
+ const groups = new Map();
119
+ for (const e of entries) {
120
+ const project = projects.get(e.projectId);
121
+ const projectTitle = project?.title ?? `Project ${e.projectId}`;
122
+ const service = project?.services.get(e.serviceId);
123
+ const serviceName = service?.name ?? `Service ${e.serviceId}`;
124
+ const key = `${e.projectId}::${e.serviceId}`;
125
+ const existing = groups.get(key);
126
+ if (existing) {
127
+ existing.totalSeconds += e.duration;
128
+ }
129
+ else {
130
+ groups.set(key, {
131
+ projectTitle,
132
+ serviceName,
133
+ serviceId: e.serviceId,
134
+ totalSeconds: e.duration,
135
+ });
136
+ }
137
+ }
138
+ return Array.from(groups.values());
139
+ }
140
+ // ── Main handler ──────────────────────────────────────────────────────────────
141
+ export async function generateInvoice(client, input) {
142
+ const [projects, rawEntries] = await Promise.all([
143
+ fetchProjectsWithRates(client),
144
+ fetchTimeEntries(client, input.start_date, input.end_date),
145
+ ]);
146
+ if (rawEntries.length === 0) {
147
+ throw new Error(`No time entries found for ${input.start_date} – ${input.end_date} (client ${TRAJECTOR_CLIENT_ID}).`);
148
+ }
149
+ const groups = groupEntries(rawEntries, projects);
150
+ const warnings = [];
151
+ // Build line items
152
+ const startLabel = formatDate(input.start_date);
153
+ const endLabel = formatDate(input.end_date);
154
+ const lines = groups.map((g) => {
155
+ const project = projects.get([...projects.entries()].find(([, p]) => p.title === g.projectTitle)?.[0] ?? -1);
156
+ const rate = project?.services.get(g.serviceId)?.rate ?? null;
157
+ const hours = round2(g.totalSeconds / 3600);
158
+ if (rate === null) {
159
+ warnings.push(`No rate found for service "${g.serviceName}" (id ${g.serviceId}) in project "${g.projectTitle}". Line item will have unit_cost of 0.`);
160
+ }
161
+ return {
162
+ name: g.serviceName,
163
+ description: `(${g.projectTitle}) Matthew Purdon – ${startLabel} - ${endLabel}`,
164
+ qty: String(hours),
165
+ unit_cost: { amount: rate !== null ? String(rate) : "0", code: "USD" },
166
+ type: 0,
167
+ };
168
+ });
169
+ // Invoice notes (top-level description) mirrors the Python script
170
+ const projectTitle = groups[0]?.projectTitle ?? "Unknown Project";
171
+ const notes = `(${projectTitle}) Matthew Purdon – ${startLabel} - ${endLabel}`;
172
+ const invoicePayload = {
173
+ customerid: TRAJECTOR_CLIENT_ID,
174
+ notes,
175
+ lines,
176
+ status: 1, // draft
177
+ };
178
+ if (input.create_date)
179
+ invoicePayload.create_date = input.create_date;
180
+ if (input.due_offset_days !== undefined)
181
+ invoicePayload.due_offset_days = input.due_offset_days;
182
+ if (input.invoice_number)
183
+ invoicePayload.invoice_number = input.invoice_number;
184
+ const path = `/accounting/account/${client.accountId}/invoices/invoices`;
185
+ const created = await client.accounting("POST", path, "invoice", {
186
+ body: { invoice: invoicePayload },
187
+ });
188
+ const invoiceId = created.invoiceid ?? created.id ?? 0;
189
+ const invoiceNumber = created.invoice_number ?? "";
190
+ const totalAmount = created.amount?.amount ?? "0";
191
+ const currency = created.amount?.code ?? "USD";
192
+ // Summarize line items for the return value
193
+ const lineItemSummary = groups.map((g) => {
194
+ const project = projects.get([...projects.entries()].find(([, p]) => p.title === g.projectTitle)?.[0] ?? -1);
195
+ const rate = project?.services.get(g.serviceId)?.rate ?? null;
196
+ const hours = round2(g.totalSeconds / 3600);
197
+ return {
198
+ service: g.serviceName,
199
+ project: g.projectTitle,
200
+ hours,
201
+ rate,
202
+ amount: rate !== null ? round2(hours * rate) : null,
203
+ };
204
+ });
205
+ // ── Attach timesheet if it exists ─────────────────────────────────────────
206
+ let timesheetAttached = false;
207
+ let timesheetPath = null;
208
+ if (invoiceId) {
209
+ const expectedPath = timesheetPathForPeriod(input.end_date);
210
+ try {
211
+ await fs.access(expectedPath);
212
+ // File exists — attach it
213
+ timesheetPath = expectedPath;
214
+ await client.attachFileToInvoice(invoiceId, expectedPath);
215
+ timesheetAttached = true;
216
+ }
217
+ catch {
218
+ // File doesn't exist (generate_timesheet hasn't been run yet, or different path)
219
+ timesheetPath = null;
220
+ warnings.push(`Timesheet not attached: no file found at ${expectedPath}. ` +
221
+ "Run generate_timesheet first, then the attachment will be added automatically.");
222
+ }
223
+ }
224
+ return {
225
+ invoiceId,
226
+ invoiceNumber,
227
+ totalAmount,
228
+ currency,
229
+ lineItems: lineItemSummary,
230
+ timesheetAttached,
231
+ timesheetPath,
232
+ warnings,
233
+ };
234
+ }
235
+ //# sourceMappingURL=invoice_generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoice_generator.js","sourceRoot":"","sources":["../../src/tools/invoice_generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Invoice tools: list, get, create, update, send, delete.
3
+ *
4
+ * FreshBooks invoice status mapping (v3_status):
5
+ * draft, created, sent, viewed, partial, paid, auto-paid, retry,
6
+ * failed, declined, overdue, disputed, resolved
7
+ *
8
+ * Money on invoice creation uses the { amount: "12.50", code: "USD" } shape
9
+ * for `unit_cost`. Read-side amount fields use the same shape.
10
+ *
11
+ * Delete is a soft delete: PUT with { invoice: { vis_state: 1 } }. We
12
+ * expose this via delete_invoice and document it in the README.
13
+ */
14
+ import { z } from "zod";
15
+ // ---------- Schemas ----------
16
+ const InvoiceStatusEnum = z.enum([
17
+ "draft",
18
+ "created",
19
+ "sent",
20
+ "viewed",
21
+ "partial",
22
+ "paid",
23
+ "auto-paid",
24
+ "retry",
25
+ "failed",
26
+ "declined",
27
+ "overdue",
28
+ "disputed",
29
+ "resolved",
30
+ ]);
31
+ export const ListInvoicesInput = z
32
+ .object({
33
+ status: InvoiceStatusEnum.optional().describe("Filter by v3_status."),
34
+ client_id: z
35
+ .number()
36
+ .int()
37
+ .positive()
38
+ .optional()
39
+ .describe("FreshBooks client (userid)."),
40
+ date_from: z
41
+ .string()
42
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
43
+ .optional()
44
+ .describe("YYYY-MM-DD."),
45
+ date_to: z
46
+ .string()
47
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
48
+ .optional()
49
+ .describe("YYYY-MM-DD."),
50
+ search: z
51
+ .string()
52
+ .max(200)
53
+ .optional()
54
+ .describe("Match invoice number or notes."),
55
+ page: z.number().int().min(1).default(1),
56
+ per_page: z.number().int().min(1).max(100).default(20),
57
+ })
58
+ .strict();
59
+ export const GetInvoiceInput = z
60
+ .object({
61
+ invoice_id: z.number().int().positive(),
62
+ })
63
+ .strict();
64
+ const LineItemInput = z
65
+ .object({
66
+ description: z.string().min(1).max(10_000),
67
+ qty: z.number().positive(),
68
+ unit_cost: z
69
+ .number()
70
+ .nonnegative()
71
+ .describe("Per-unit price as a decimal, e.g. 75.00."),
72
+ name: z.string().max(200).optional(),
73
+ taxName1: z.string().max(50).optional(),
74
+ taxAmount1: z
75
+ .number()
76
+ .min(0)
77
+ .max(100)
78
+ .optional()
79
+ .describe("Percent, e.g. 13."),
80
+ })
81
+ .strict();
82
+ export const CreateInvoiceInput = z
83
+ .object({
84
+ client_id: z
85
+ .number()
86
+ .int()
87
+ .positive()
88
+ .describe("FreshBooks userid of the client."),
89
+ lines: z.array(LineItemInput).min(1).max(100),
90
+ currency_code: z.string().length(3).default("USD"),
91
+ due_offset_days: z.number().int().min(0).max(365).optional(),
92
+ notes: z.string().max(10_000).optional(),
93
+ terms: z.string().max(10_000).optional(),
94
+ invoice_number: z.string().max(50).optional(),
95
+ create_date: z
96
+ .string()
97
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
98
+ .optional(),
99
+ })
100
+ .strict();
101
+ export const UpdateInvoiceInput = z
102
+ .object({
103
+ invoice_id: z.number().int().positive(),
104
+ notes: z.string().max(10_000).optional(),
105
+ terms: z.string().max(10_000).optional(),
106
+ due_offset_days: z.number().int().min(0).max(365).optional(),
107
+ invoice_number: z.string().max(50).optional(),
108
+ lines: z
109
+ .array(LineItemInput)
110
+ .min(1)
111
+ .max(100)
112
+ .optional()
113
+ .describe("If provided, REPLACES all line items."),
114
+ })
115
+ .strict();
116
+ export const SendInvoiceInput = z
117
+ .object({
118
+ invoice_id: z.number().int().positive(),
119
+ recipients: z
120
+ .array(z.string().email())
121
+ .max(10)
122
+ .optional()
123
+ .describe("Override recipients. Defaults to client's email on file."),
124
+ subject: z.string().max(200).optional(),
125
+ body: z.string().max(10_000).optional(),
126
+ })
127
+ .strict();
128
+ export const DeleteInvoiceInput = z
129
+ .object({
130
+ invoice_id: z.number().int().positive(),
131
+ })
132
+ .strict();
133
+ // ---------- Handlers ----------
134
+ export async function listInvoices(client, input) {
135
+ const path = `/accounting/account/${client.accountId}/invoices/invoices`;
136
+ const query = {
137
+ page: input.page,
138
+ per_page: input.per_page,
139
+ };
140
+ if (input.status)
141
+ query["search[v3_status]"] = input.status;
142
+ if (input.client_id)
143
+ query["search[customerid]"] = input.client_id;
144
+ if (input.date_from)
145
+ query["search[date_min]"] = input.date_from;
146
+ if (input.date_to)
147
+ query["search[date_max]"] = input.date_to;
148
+ if (input.search)
149
+ query["search[invoice_number_like]"] = input.search;
150
+ const result = await client.accounting("GET", path, "", { query });
151
+ // accounting<T> returns env.response.result[key]; for list we want the whole result.
152
+ // Use a different unwrap path: pull the whole result object.
153
+ return summarizeListResult(result);
154
+ }
155
+ // listInvoices/listClients/listItems all share the same envelope shape.
156
+ // `accounting` extracts result[key]; for lists we want the result object itself,
157
+ // so use a custom unwrap helper here.
158
+ function summarizeListResult(result) {
159
+ return result;
160
+ }
161
+ export async function getInvoice(client, input) {
162
+ const path = `/accounting/account/${client.accountId}/invoices/invoices/${input.invoice_id}`;
163
+ return client.accounting("GET", path, "invoice", {
164
+ query: { "include[]": "lines" },
165
+ });
166
+ }
167
+ export async function createInvoice(client, input) {
168
+ const path = `/accounting/account/${client.accountId}/invoices/invoices`;
169
+ const body = {
170
+ invoice: {
171
+ customerid: input.client_id,
172
+ currency_code: input.currency_code,
173
+ create_date: input.create_date,
174
+ due_offset_days: input.due_offset_days,
175
+ invoice_number: input.invoice_number,
176
+ notes: input.notes,
177
+ terms: input.terms,
178
+ lines: input.lines.map((l) => ({
179
+ type: 0,
180
+ name: l.name,
181
+ description: l.description,
182
+ qty: String(l.qty),
183
+ unit_cost: {
184
+ amount: l.unit_cost.toFixed(2),
185
+ code: input.currency_code,
186
+ },
187
+ ...(l.taxName1 ? { taxName1: l.taxName1 } : {}),
188
+ ...(l.taxAmount1 !== undefined
189
+ ? { taxAmount1: String(l.taxAmount1) }
190
+ : {}),
191
+ })),
192
+ },
193
+ };
194
+ return client.accounting("POST", path, "invoice", { body });
195
+ }
196
+ export async function updateInvoice(client, input) {
197
+ const path = `/accounting/account/${client.accountId}/invoices/invoices/${input.invoice_id}`;
198
+ const invoice = {};
199
+ if (input.notes !== undefined)
200
+ invoice.notes = input.notes;
201
+ if (input.terms !== undefined)
202
+ invoice.terms = input.terms;
203
+ if (input.due_offset_days !== undefined)
204
+ invoice.due_offset_days = input.due_offset_days;
205
+ if (input.invoice_number !== undefined)
206
+ invoice.invoice_number = input.invoice_number;
207
+ if (input.lines) {
208
+ invoice.lines = input.lines.map((l) => ({
209
+ type: 0,
210
+ name: l.name,
211
+ description: l.description,
212
+ qty: String(l.qty),
213
+ unit_cost: { amount: l.unit_cost.toFixed(2), code: "USD" },
214
+ ...(l.taxName1 ? { taxName1: l.taxName1 } : {}),
215
+ ...(l.taxAmount1 !== undefined
216
+ ? { taxAmount1: String(l.taxAmount1) }
217
+ : {}),
218
+ }));
219
+ }
220
+ return client.accounting("PUT", path, "invoice", {
221
+ body: { invoice },
222
+ });
223
+ }
224
+ export async function sendInvoice(client, input) {
225
+ const path = `/accounting/account/${client.accountId}/invoices/invoices/${input.invoice_id}`;
226
+ const invoice = { action_email: true };
227
+ if (input.recipients && input.recipients.length > 0) {
228
+ invoice.email_recipients = input.recipients;
229
+ }
230
+ if (input.subject)
231
+ invoice.email_subject = input.subject;
232
+ if (input.body)
233
+ invoice.email_body = input.body;
234
+ return client.accounting("PUT", path, "invoice", {
235
+ body: { invoice },
236
+ });
237
+ }
238
+ /**
239
+ * FreshBooks soft-deletes invoices: vis_state=1 (deleted), 2 (archived), 0 (active).
240
+ */
241
+ export async function deleteInvoice(client, input) {
242
+ const path = `/accounting/account/${client.accountId}/invoices/invoices/${input.invoice_id}`;
243
+ return client.accounting("PUT", path, "invoice", {
244
+ body: { invoice: { vis_state: 1 } },
245
+ });
246
+ }
247
+ //# sourceMappingURL=invoices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoices.js","sourceRoot":"","sources":["../../src/tools/invoices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Item tools: list_items.
3
+ *
4
+ * Endpoint: /accounting/account/<account_id>/items/items
5
+ */
6
+ import { z } from "zod";
7
+ export const ListItemsInput = z
8
+ .object({
9
+ search: z.string().max(200).optional().describe("Match item name."),
10
+ page: z.number().int().min(1).default(1),
11
+ per_page: z.number().int().min(1).max(100).default(20),
12
+ })
13
+ .strict();
14
+ export async function listItems(client, input) {
15
+ const path = `/accounting/account/${client.accountId}/items/items`;
16
+ const query = {
17
+ page: input.page,
18
+ per_page: input.per_page,
19
+ };
20
+ if (input.search)
21
+ query["search[name_like]"] = input.search;
22
+ return client.accounting("GET", path, "", { query });
23
+ }
24
+ //# sourceMappingURL=items.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"items.js","sourceRoot":"","sources":["../../src/tools/items.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACnE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACxC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACvD,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAAwB,EACxB,KAAqC;IAErC,MAAM,IAAI,GAAG,uBAAuB,MAAM,CAAC,SAAS,cAAc,CAAC;IACnE,MAAM,KAAK,GAAoC;QAC7C,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;IACF,IAAI,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,mBAAmB,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAS5D,OAAO,MAAM,CAAC,UAAU,CAAS,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/D,CAAC"}