noxctl 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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +326 -0
  3. package/dist/auth.d.ts +29 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +267 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +1012 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/credentials-store.d.ts +4 -0
  12. package/dist/credentials-store.d.ts.map +1 -0
  13. package/dist/credentials-store.js +223 -0
  14. package/dist/credentials-store.js.map +1 -0
  15. package/dist/formatter.d.ts +62 -0
  16. package/dist/formatter.d.ts.map +1 -0
  17. package/dist/formatter.js +200 -0
  18. package/dist/formatter.js.map +1 -0
  19. package/dist/fortnox-client.d.ts +27 -0
  20. package/dist/fortnox-client.d.ts.map +1 -0
  21. package/dist/fortnox-client.js +178 -0
  22. package/dist/fortnox-client.js.map +1 -0
  23. package/dist/identifiers.d.ts +4 -0
  24. package/dist/identifiers.d.ts.map +1 -0
  25. package/dist/identifiers.js +16 -0
  26. package/dist/identifiers.js.map +1 -0
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +43 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/operations/accounts.d.ts +18 -0
  32. package/dist/operations/accounts.d.ts.map +1 -0
  33. package/dist/operations/accounts.js +28 -0
  34. package/dist/operations/accounts.js.map +1 -0
  35. package/dist/operations/articles.d.ts +20 -0
  36. package/dist/operations/articles.d.ts.map +1 -0
  37. package/dist/operations/articles.js +36 -0
  38. package/dist/operations/articles.js.map +1 -0
  39. package/dist/operations/company.d.ts +2 -0
  40. package/dist/operations/company.d.ts.map +1 -0
  41. package/dist/operations/company.js +6 -0
  42. package/dist/operations/company.js.map +1 -0
  43. package/dist/operations/customers.d.ts +20 -0
  44. package/dist/operations/customers.d.ts.map +1 -0
  45. package/dist/operations/customers.js +37 -0
  46. package/dist/operations/customers.js.map +1 -0
  47. package/dist/operations/financial-reports.d.ts +37 -0
  48. package/dist/operations/financial-reports.d.ts.map +1 -0
  49. package/dist/operations/financial-reports.js +193 -0
  50. package/dist/operations/financial-reports.js.map +1 -0
  51. package/dist/operations/invoices.d.ts +32 -0
  52. package/dist/operations/invoices.d.ts.map +1 -0
  53. package/dist/operations/invoices.js +74 -0
  54. package/dist/operations/invoices.js.map +1 -0
  55. package/dist/operations/supplier-invoices.d.ts +23 -0
  56. package/dist/operations/supplier-invoices.d.ts.map +1 -0
  57. package/dist/operations/supplier-invoices.js +36 -0
  58. package/dist/operations/supplier-invoices.js.map +1 -0
  59. package/dist/operations/suppliers.d.ts +20 -0
  60. package/dist/operations/suppliers.d.ts.map +1 -0
  61. package/dist/operations/suppliers.js +36 -0
  62. package/dist/operations/suppliers.js.map +1 -0
  63. package/dist/operations/tax.d.ts +26 -0
  64. package/dist/operations/tax.d.ts.map +1 -0
  65. package/dist/operations/tax.js +47 -0
  66. package/dist/operations/tax.js.map +1 -0
  67. package/dist/operations/vouchers.d.ts +22 -0
  68. package/dist/operations/vouchers.d.ts.map +1 -0
  69. package/dist/operations/vouchers.js +41 -0
  70. package/dist/operations/vouchers.js.map +1 -0
  71. package/dist/tool-output.d.ts +16 -0
  72. package/dist/tool-output.d.ts.map +1 -0
  73. package/dist/tool-output.js +48 -0
  74. package/dist/tool-output.js.map +1 -0
  75. package/dist/tools/articles.d.ts +3 -0
  76. package/dist/tools/articles.d.ts.map +1 -0
  77. package/dist/tools/articles.js +75 -0
  78. package/dist/tools/articles.js.map +1 -0
  79. package/dist/tools/bookkeeping.d.ts +3 -0
  80. package/dist/tools/bookkeeping.d.ts.map +1 -0
  81. package/dist/tools/bookkeeping.js +82 -0
  82. package/dist/tools/bookkeeping.js.map +1 -0
  83. package/dist/tools/company.d.ts +3 -0
  84. package/dist/tools/company.d.ts.map +1 -0
  85. package/dist/tools/company.js +13 -0
  86. package/dist/tools/company.js.map +1 -0
  87. package/dist/tools/customers.d.ts +3 -0
  88. package/dist/tools/customers.d.ts.map +1 -0
  89. package/dist/tools/customers.js +75 -0
  90. package/dist/tools/customers.js.map +1 -0
  91. package/dist/tools/financial-reports.d.ts +3 -0
  92. package/dist/tools/financial-reports.d.ts.map +1 -0
  93. package/dist/tools/financial-reports.js +35 -0
  94. package/dist/tools/financial-reports.js.map +1 -0
  95. package/dist/tools/invoices.d.ts +3 -0
  96. package/dist/tools/invoices.d.ts.map +1 -0
  97. package/dist/tools/invoices.js +160 -0
  98. package/dist/tools/invoices.js.map +1 -0
  99. package/dist/tools/status.d.ts +3 -0
  100. package/dist/tools/status.d.ts.map +1 -0
  101. package/dist/tools/status.js +109 -0
  102. package/dist/tools/status.js.map +1 -0
  103. package/dist/tools/supplier-invoices.d.ts +3 -0
  104. package/dist/tools/supplier-invoices.d.ts.map +1 -0
  105. package/dist/tools/supplier-invoices.js +88 -0
  106. package/dist/tools/supplier-invoices.js.map +1 -0
  107. package/dist/tools/suppliers.d.ts +3 -0
  108. package/dist/tools/suppliers.d.ts.map +1 -0
  109. package/dist/tools/suppliers.js +77 -0
  110. package/dist/tools/suppliers.js.map +1 -0
  111. package/dist/tools/tax.d.ts +3 -0
  112. package/dist/tools/tax.d.ts.map +1 -0
  113. package/dist/tools/tax.js +18 -0
  114. package/dist/tools/tax.js.map +1 -0
  115. package/dist/views.d.ts +19 -0
  116. package/dist/views.d.ts.map +1 -0
  117. package/dist/views.js +165 -0
  118. package/dist/views.js.map +1 -0
  119. package/package.json +60 -0
@@ -0,0 +1,16 @@
1
+ import { type Column } from './formatter.js';
2
+ type TextContent = {
3
+ content: [{
4
+ type: 'text';
5
+ text: string;
6
+ }];
7
+ };
8
+ export declare function textResponse(text: string): TextContent;
9
+ export declare function listResponse(rows: Record<string, unknown>[], columns: Column[], rawData: unknown, meta?: Record<string, unknown>, includeRaw?: boolean): TextContent;
10
+ export declare function detailResponse(record: Record<string, unknown>, columns: Column[], rawData?: unknown, includeRaw?: boolean): TextContent;
11
+ export declare function confirmationResponse(message: string, rawData: unknown, columns?: Column[], includeRaw?: boolean): TextContent;
12
+ export declare function taxReportResponse(report: Record<string, unknown>, includeRaw?: boolean): TextContent;
13
+ export declare function dryRunResponse(action: string, payload?: unknown): TextContent;
14
+ export declare function requireConfirmation(action: string): never;
15
+ export {};
16
+ //# sourceMappingURL=tool-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-output.d.ts","sourceRoot":"","sources":["../src/tool-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AAExB,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3C,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAItD;AAYD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,UAAU,CAAC,EAAE,OAAO,GACnB,WAAW,CAKb;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE,OAAgB,EACzB,UAAU,CAAC,EAAE,OAAO,GACnB,WAAW,CAGb;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,MAAM,EAAE,EAClB,UAAU,CAAC,EAAE,OAAO,GACnB,WAAW,CAOb;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,UAAU,CAAC,EAAE,OAAO,GACnB,WAAW,CAEb;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAM7E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAIzD"}
@@ -0,0 +1,48 @@
1
+ import { formatDetail, formatMeta, formatTable, formatTaxReport, } from './formatter.js';
2
+ export function textResponse(text) {
3
+ return {
4
+ content: [{ type: 'text', text }],
5
+ };
6
+ }
7
+ function appendRawJson(text, raw, includeRaw) {
8
+ if (!includeRaw)
9
+ return text;
10
+ const rawJson = JSON.stringify(raw, null, 2);
11
+ const warning = 'Warning: includeRaw may expose additional accounting and personal data in logs, terminals, and AI transcripts.';
12
+ if (!text)
13
+ return `${warning}\n\nRaw JSON:\n${rawJson}`;
14
+ return `${text}\n\n${warning}\n\nRaw JSON:\n${rawJson}`;
15
+ }
16
+ export function listResponse(rows, columns, rawData, meta, includeRaw) {
17
+ const table = formatTable(rows, columns);
18
+ const metaLine = formatMeta(meta);
19
+ const text = metaLine ? `${table}${metaLine}` : table;
20
+ return textResponse(appendRawJson(text, rawData, includeRaw));
21
+ }
22
+ export function detailResponse(record, columns, rawData = record, includeRaw) {
23
+ const summary = formatDetail(record, columns) || 'No visible fields.';
24
+ return textResponse(appendRawJson(summary, rawData, includeRaw));
25
+ }
26
+ export function confirmationResponse(message, rawData, columns, includeRaw) {
27
+ let text = message;
28
+ if (columns && rawData && typeof rawData === 'object') {
29
+ const detail = formatDetail(rawData, columns);
30
+ if (detail)
31
+ text += `\n${detail}`;
32
+ }
33
+ return textResponse(appendRawJson(text, rawData, includeRaw));
34
+ }
35
+ export function taxReportResponse(report, includeRaw) {
36
+ return textResponse(appendRawJson(formatTaxReport(report), report, includeRaw));
37
+ }
38
+ export function dryRunResponse(action, payload) {
39
+ let text = `Dry run: ${action}. No request was sent to Fortnox.`;
40
+ if (payload !== undefined) {
41
+ text += `\n\nRequest payload:\n${JSON.stringify(payload, null, 2)}`;
42
+ }
43
+ return textResponse(text);
44
+ }
45
+ export function requireConfirmation(action) {
46
+ throw new Error(`Confirmation required to ${action}. Re-run with confirm: true, or dryRun: true to preview without executing.`);
47
+ }
48
+ //# sourceMappingURL=tool-output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-output.js","sourceRoot":"","sources":["../src/tool-output.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,GAEhB,MAAM,gBAAgB,CAAC;AAMxB,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,GAAY,EAAE,UAAoB;IACrE,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,OAAO,GACX,gHAAgH,CAAC;IACnH,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,OAAO,kBAAkB,OAAO,EAAE,CAAC;IACxD,OAAO,GAAG,IAAI,OAAO,OAAO,kBAAkB,OAAO,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAA+B,EAC/B,OAAiB,EACjB,OAAgB,EAChB,IAA8B,EAC9B,UAAoB;IAEpB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IACtD,OAAO,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAA+B,EAC/B,OAAiB,EACjB,UAAmB,MAAM,EACzB,UAAoB;IAEpB,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,oBAAoB,CAAC;IACtE,OAAO,YAAY,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,OAAgB,EAChB,OAAkB,EAClB,UAAoB;IAEpB,IAAI,IAAI,GAAG,OAAO,CAAC;IACnB,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAkC,EAAE,OAAO,CAAC,CAAC;QACzE,IAAI,MAAM;YAAE,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAA+B,EAC/B,UAAoB;IAEpB,OAAO,YAAY,CAAC,aAAa,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAiB;IAC9D,IAAI,IAAI,GAAG,YAAY,MAAM,mCAAmC,CAAC;IACjE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,IAAI,yBAAyB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IACtE,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,4EAA4E,CAC/G,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerArticleTools(server: McpServer): void;
3
+ //# sourceMappingURL=articles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../src/tools/articles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkG5D"}
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ import { listArticles, getArticle, createArticle, updateArticle } from '../operations/articles.js';
3
+ import { articleListColumns, articleDetailColumns } from '../views.js';
4
+ import { detailResponse, dryRunResponse, listResponse, requireConfirmation, } from '../tool-output.js';
5
+ export function registerArticleTools(server) {
6
+ server.tool('fortnox_list_articles', 'Lista/sök artiklar i Fortnox. Returnerar: ArticleNumber, Description, SalesPrice, Unit, Active.', {
7
+ search: z.string().optional().describe('Sökterm (beskrivning)'),
8
+ page: z.number().optional().describe('Sidnummer (default 1)'),
9
+ limit: z.number().optional().describe('Antal per sida (default 100, max 500)'),
10
+ all: z.boolean().optional().describe('Hämta alla sidor (ignorerar page/limit)'),
11
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
12
+ }, async ({ search, page, limit, all, includeRaw }) => {
13
+ const data = await listArticles({ search, page, limit, all });
14
+ return listResponse(data.Articles ?? [], articleListColumns, data, data.MetaInformation, includeRaw);
15
+ });
16
+ server.tool('fortnox_get_article', 'Hämta en enskild artikel från Fortnox. Returnerar: ArticleNumber, Description, SalesPrice, PurchasePrice, Unit, SalesAccount, VAT, Active.', {
17
+ articleNumber: z.string().describe('Artikelnummer'),
18
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
19
+ }, async ({ articleNumber, includeRaw }) => {
20
+ const data = await getArticle(articleNumber);
21
+ return detailResponse(data, articleDetailColumns, data, includeRaw);
22
+ });
23
+ server.tool('fortnox_create_article', 'Skapa en ny artikel i Fortnox', {
24
+ Description: z.string().describe('Artikelbeskrivning'),
25
+ ArticleNumber: z
26
+ .string()
27
+ .optional()
28
+ .describe('Artikelnummer (genereras automatiskt om det utelämnas)'),
29
+ SalesPrice: z.number().optional().describe('Försäljningspris exkl. moms'),
30
+ PurchasePrice: z.number().optional().describe('Inköpspris'),
31
+ Unit: z.string().optional().describe('Enhet (t.ex. st, tim, kg)'),
32
+ SalesAccount: z.number().optional().describe('Försäljningskonto'),
33
+ VAT: z.number().optional().describe('Momssats i procent (t.ex. 25)'),
34
+ Active: z.boolean().optional().describe('Om artikeln är aktiv'),
35
+ confirm: z.boolean().optional().describe('Bekräfta att artikeln ska skapas'),
36
+ dryRun: z
37
+ .boolean()
38
+ .optional()
39
+ .describe('Visa vad som skulle skickas utan att skapa artikeln'),
40
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
41
+ }, async ({ confirm, dryRun, includeRaw, ...params }) => {
42
+ if (dryRun) {
43
+ return dryRunResponse(`create article "${params.Description}"`, { Article: params });
44
+ }
45
+ if (!confirm)
46
+ requireConfirmation(`create article "${params.Description}"`);
47
+ const data = await createArticle(params);
48
+ return detailResponse(data, articleDetailColumns, data, includeRaw);
49
+ });
50
+ server.tool('fortnox_update_article', 'Uppdatera en befintlig artikel i Fortnox', {
51
+ articleNumber: z.string().describe('Artikelnummer att uppdatera'),
52
+ Description: z.string().optional().describe('Artikelbeskrivning'),
53
+ SalesPrice: z.number().optional().describe('Försäljningspris exkl. moms'),
54
+ PurchasePrice: z.number().optional().describe('Inköpspris'),
55
+ Unit: z.string().optional().describe('Enhet (t.ex. st, tim, kg)'),
56
+ SalesAccount: z.number().optional().describe('Försäljningskonto'),
57
+ VAT: z.number().optional().describe('Momssats i procent (t.ex. 25)'),
58
+ Active: z.boolean().optional().describe('Om artikeln är aktiv'),
59
+ confirm: z.boolean().optional().describe('Bekräfta att artikeln ska uppdateras'),
60
+ dryRun: z
61
+ .boolean()
62
+ .optional()
63
+ .describe('Visa vad som skulle skickas utan att uppdatera artikeln'),
64
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
65
+ }, async ({ articleNumber, confirm, dryRun, includeRaw, ...fields }) => {
66
+ if (dryRun) {
67
+ return dryRunResponse(`update article ${articleNumber}`, { Article: fields });
68
+ }
69
+ if (!confirm)
70
+ requireConfirmation(`update article ${articleNumber}`);
71
+ const data = await updateArticle(articleNumber, fields);
72
+ return detailResponse(data, articleDetailColumns, data, includeRaw);
73
+ });
74
+ }
75
+ //# sourceMappingURL=articles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"articles.js","sourceRoot":"","sources":["../../src/tools/articles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerBookkeepingTools(server: McpServer): void;
3
+ //# sourceMappingURL=bookkeeping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bookkeeping.d.ts","sourceRoot":"","sources":["../../src/tools/bookkeeping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6BpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoGhE"}
@@ -0,0 +1,82 @@
1
+ import { z } from 'zod';
2
+ import { listAccounts } from '../operations/accounts.js';
3
+ import { listVouchers, getVoucher, createVoucher } from '../operations/vouchers.js';
4
+ import { accountListColumns, voucherDetailColumns, voucherListColumns, voucherRowColumns, } from '../views.js';
5
+ import { detailResponse, dryRunResponse, listResponse, requireConfirmation, } from '../tool-output.js';
6
+ const VoucherRowSchema = z.object({
7
+ Account: z.number().describe('Kontonummer'),
8
+ Debit: z.number().optional().describe('Debetbelopp'),
9
+ Credit: z.number().optional().describe('Kreditbelopp'),
10
+ Description: z.string().optional().describe('Beskrivning'),
11
+ });
12
+ const VoucherSeriesSchema = z
13
+ .string()
14
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,9}$/, 'Voucher series must be alphanumeric')
15
+ .optional();
16
+ export function registerBookkeepingTools(server) {
17
+ server.tool('fortnox_list_vouchers', 'Lista verifikationer i Fortnox. Returnerar: VoucherSeries, VoucherNumber, TransactionDate, Description.', {
18
+ financialYear: z.number().optional().describe('Räkenskapsår (default: nuvarande)'),
19
+ series: z.string().optional().describe('Verifikationsserie (t.ex. "A")'),
20
+ fromDate: z.string().optional().describe('Från datum (YYYY-MM-DD)'),
21
+ toDate: z.string().optional().describe('Till datum (YYYY-MM-DD)'),
22
+ page: z.number().optional().describe('Sidnummer'),
23
+ limit: z.number().optional().describe('Antal per sida'),
24
+ all: z.boolean().optional().describe('Hämta alla sidor (ignorerar page/limit)'),
25
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
26
+ }, async ({ financialYear, series, fromDate, toDate, page, limit, all, includeRaw }) => {
27
+ const data = await listVouchers({
28
+ financialYear,
29
+ series,
30
+ fromDate,
31
+ toDate,
32
+ page,
33
+ limit,
34
+ all,
35
+ });
36
+ return listResponse(data.Vouchers ?? [], voucherListColumns, data, data.MetaInformation, includeRaw);
37
+ });
38
+ server.tool('fortnox_get_voucher', 'Hämta en enskild verifikation med rader från Fortnox. Returnerar: VoucherSeries, VoucherNumber, TransactionDate, Description, samt VoucherRows med Account, Debit, Credit.', {
39
+ series: z.string().describe('Verifikationsserie (t.ex. "A")'),
40
+ voucherNumber: z.string().describe('Verifikationsnummer'),
41
+ financialYear: z.number().optional().describe('Räkenskapsår (default: nuvarande)'),
42
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
43
+ }, async ({ series, voucherNumber, financialYear, includeRaw }) => {
44
+ const data = await getVoucher(series, voucherNumber, financialYear);
45
+ const rows = data.VoucherRows ?? [];
46
+ const header = detailResponse(data, voucherDetailColumns, data, false);
47
+ const rowTable = listResponse(rows, voucherRowColumns, data, undefined, includeRaw);
48
+ const headerText = header.content[0].text;
49
+ const rowText = rowTable.content[0].text;
50
+ return { content: [{ type: 'text', text: `${headerText}\n\nRows:\n${rowText}` }] };
51
+ });
52
+ server.tool('fortnox_create_voucher', 'Skapa en verifikation i Fortnox', {
53
+ Description: z.string().describe('Beskrivning av verifikationen'),
54
+ VoucherSeries: VoucherSeriesSchema.describe('Verifikationsserie (default: "A")'),
55
+ TransactionDate: z.string().describe('Transaktionsdatum (YYYY-MM-DD)'),
56
+ VoucherRows: z.array(VoucherRowSchema).describe('Verifikationsrader (debet och kredit)'),
57
+ confirm: z.boolean().optional().describe('Bekräfta att verifikationen ska skapas'),
58
+ dryRun: z
59
+ .boolean()
60
+ .optional()
61
+ .describe('Visa vad som skulle skickas utan att skapa verifikationen'),
62
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
63
+ }, async ({ confirm, dryRun, includeRaw, ...params }) => {
64
+ if (dryRun) {
65
+ return dryRunResponse(`create voucher "${params.Description}"`, { Voucher: params });
66
+ }
67
+ if (!confirm)
68
+ requireConfirmation(`create voucher "${params.Description}"`);
69
+ const data = await createVoucher(params);
70
+ return detailResponse(data, voucherDetailColumns, data, includeRaw);
71
+ });
72
+ server.tool('fortnox_list_accounts', 'Visa kontoplan i Fortnox. Returnerar: Number, Description, SRU.', {
73
+ financialYear: z.number().optional().describe('Räkenskapsår (default: nuvarande)'),
74
+ search: z.string().optional().describe('Sök på kontonamn'),
75
+ all: z.boolean().optional().describe('Hämta alla sidor (ignorerar page/limit)'),
76
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
77
+ }, async ({ includeRaw, ...params }) => {
78
+ const data = await listAccounts(params);
79
+ return listResponse(data.Accounts ?? [], accountListColumns, data, data.MetaInformation, includeRaw);
80
+ });
81
+ }
82
+ //# sourceMappingURL=bookkeeping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bookkeeping.js","sourceRoot":"","sources":["../../src/tools/bookkeeping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCompanyTools(server: McpServer): void;
3
+ //# sourceMappingURL=company.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"company.d.ts","sourceRoot":"","sources":["../../src/tools/company.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAY5D"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ import { getCompanyInfo } from '../operations/company.js';
3
+ import { companyDetailColumns } from '../views.js';
4
+ import { detailResponse } from '../tool-output.js';
5
+ export function registerCompanyTools(server) {
6
+ server.tool('fortnox_company_info', 'Hämta företagsinformation och inställningar från Fortnox', {
7
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
8
+ }, async ({ includeRaw }) => {
9
+ const data = await getCompanyInfo();
10
+ return detailResponse(data, companyDetailColumns, data, includeRaw);
11
+ });
12
+ }
13
+ //# sourceMappingURL=company.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"company.js","sourceRoot":"","sources":["../../src/tools/company.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,0DAA0D,EAC1D;QACE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;QACpC,OAAO,cAAc,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IACtE,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCustomerTools(server: McpServer): void;
3
+ //# sourceMappingURL=customers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.d.ts","sourceRoot":"","sources":["../../src/tools/customers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoBpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+F7D"}
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ import { listCustomers, getCustomer, createCustomer, updateCustomer, } from '../operations/customers.js';
3
+ import { customerListColumns, customerDetailColumns } from '../views.js';
4
+ import { detailResponse, dryRunResponse, listResponse, requireConfirmation, } from '../tool-output.js';
5
+ const CustomerNumberSchema = z
6
+ .string()
7
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,49}$/, 'Customer number must be alphanumeric');
8
+ export function registerCustomerTools(server) {
9
+ server.tool('fortnox_list_customers', 'Lista/sök kunder i Fortnox. Returnerar: CustomerNumber, Name, OrganisationNumber, City, Email.', {
10
+ search: z.string().optional().describe('Sökterm (namn, kundnummer, orgnummer)'),
11
+ page: z.number().optional().describe('Sidnummer (default 1)'),
12
+ limit: z.number().optional().describe('Antal per sida (default 100, max 500)'),
13
+ all: z.boolean().optional().describe('Hämta alla sidor (ignorerar page/limit)'),
14
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
15
+ }, async ({ search, page, limit, all, includeRaw }) => {
16
+ const data = await listCustomers({ search, page, limit, all });
17
+ return listResponse(data.Customers ?? [], customerListColumns, data, data.MetaInformation, includeRaw);
18
+ });
19
+ server.tool('fortnox_get_customer', 'Hämta en enskild kund från Fortnox. Returnerar: CustomerNumber, Name, OrganisationNumber, Email, Phone, Address1, ZipCode, City, Country, VATNumber.', {
20
+ customerNumber: CustomerNumberSchema.describe('Kundnummer'),
21
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
22
+ }, async ({ customerNumber, includeRaw }) => {
23
+ const data = await getCustomer(customerNumber);
24
+ return detailResponse(data, customerDetailColumns, data, includeRaw);
25
+ });
26
+ server.tool('fortnox_create_customer', 'Skapa en ny kund i Fortnox', {
27
+ Name: z.string().describe('Kundnamn'),
28
+ OrganisationNumber: z.string().optional().describe('Organisationsnummer'),
29
+ Email: z.string().optional().describe('E-postadress'),
30
+ Phone: z.string().optional().describe('Telefonnummer'),
31
+ Address1: z.string().optional().describe('Adressrad 1'),
32
+ Address2: z.string().optional().describe('Adressrad 2'),
33
+ ZipCode: z.string().optional().describe('Postnummer'),
34
+ City: z.string().optional().describe('Ort'),
35
+ VATNumber: z.string().optional().describe('Momsregistreringsnummer'),
36
+ confirm: z.boolean().optional().describe('Bekräfta att kunden ska skapas'),
37
+ dryRun: z.boolean().optional().describe('Visa vad som skulle skickas utan att skapa kunden'),
38
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
39
+ }, async ({ confirm, dryRun, includeRaw, ...params }) => {
40
+ if (dryRun) {
41
+ return dryRunResponse(`create customer "${params.Name}"`, { Customer: params });
42
+ }
43
+ if (!confirm)
44
+ requireConfirmation(`create customer "${params.Name}"`);
45
+ const data = await createCustomer(params);
46
+ return detailResponse(data, customerDetailColumns, data, includeRaw);
47
+ });
48
+ server.tool('fortnox_update_customer', 'Uppdatera en befintlig kund i Fortnox', {
49
+ customerNumber: CustomerNumberSchema.describe('Kundnummer att uppdatera'),
50
+ Name: z.string().optional().describe('Kundnamn'),
51
+ OrganisationNumber: z.string().optional().describe('Organisationsnummer'),
52
+ Email: z.string().optional().describe('E-postadress'),
53
+ Phone: z.string().optional().describe('Telefonnummer'),
54
+ Address1: z.string().optional().describe('Adressrad 1'),
55
+ Address2: z.string().optional().describe('Adressrad 2'),
56
+ ZipCode: z.string().optional().describe('Postnummer'),
57
+ City: z.string().optional().describe('Ort'),
58
+ VATNumber: z.string().optional().describe('Momsregistreringsnummer'),
59
+ confirm: z.boolean().optional().describe('Bekräfta att kunden ska uppdateras'),
60
+ dryRun: z
61
+ .boolean()
62
+ .optional()
63
+ .describe('Visa vad som skulle skickas utan att uppdatera kunden'),
64
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
65
+ }, async ({ customerNumber, confirm, dryRun, includeRaw, ...fields }) => {
66
+ if (dryRun) {
67
+ return dryRunResponse(`update customer ${customerNumber}`, { Customer: fields });
68
+ }
69
+ if (!confirm)
70
+ requireConfirmation(`update customer ${customerNumber}`);
71
+ const data = await updateCustomer(customerNumber, fields);
72
+ return detailResponse(data, customerDetailColumns, data, includeRaw);
73
+ });
74
+ }
75
+ //# sourceMappingURL=customers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.js","sourceRoot":"","sources":["../../src/tools/customers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerFinancialReportTools(server: McpServer): void;
3
+ //# sourceMappingURL=financial-reports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"financial-reports.d.ts","sourceRoot":"","sources":["../../src/tools/financial-reports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwCpE"}
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ import { getIncomeStatement, getBalanceSheet } from '../operations/financial-reports.js';
3
+ import { formatFinancialReport } from '../formatter.js';
4
+ import { textResponse } from '../tool-output.js';
5
+ export function registerFinancialReportTools(server) {
6
+ server.tool('fortnox_income_statement', 'Resultaträkning — visar intäkter, kostnader och resultat. Kan filtreras på period med fromDate/toDate.', {
7
+ financialYear: z.number().optional().describe('Räkenskapsår (default: nuvarande)'),
8
+ fromDate: z
9
+ .string()
10
+ .optional()
11
+ .describe('Från datum (YYYY-MM-DD) — visar bara periodens rörelser'),
12
+ toDate: z.string().optional().describe('Till datum (YYYY-MM-DD)'),
13
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
14
+ }, async ({ financialYear, fromDate, toDate, includeRaw }) => {
15
+ const report = await getIncomeStatement({ financialYear, fromDate, toDate });
16
+ const text = formatFinancialReport(report);
17
+ if (includeRaw) {
18
+ return textResponse(`${text}\n\nRaw JSON:\n${JSON.stringify(report, null, 2)}`);
19
+ }
20
+ return textResponse(text);
21
+ });
22
+ server.tool('fortnox_balance_sheet', 'Balansräkning — visar tillgångar, skulder och eget kapital. Kan filtreras med toDate för ställning per datum.', {
23
+ financialYear: z.number().optional().describe('Räkenskapsår (default: nuvarande)'),
24
+ toDate: z.string().optional().describe('Per datum (YYYY-MM-DD) — ställning vid detta datum'),
25
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
26
+ }, async ({ financialYear, toDate, includeRaw }) => {
27
+ const report = await getBalanceSheet({ financialYear, toDate });
28
+ const text = formatFinancialReport(report);
29
+ if (includeRaw) {
30
+ return textResponse(`${text}\n\nRaw JSON:\n${JSON.stringify(report, null, 2)}`);
31
+ }
32
+ return textResponse(text);
33
+ });
34
+ }
35
+ //# sourceMappingURL=financial-reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"financial-reports.js","sourceRoot":"","sources":["../../src/tools/financial-reports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,MAAM,CAAC,IAAI,CACT,0BAA0B,EAC1B,wGAAwG,EACxG;QACE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QAClF,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACjE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,YAAY,CAAC,GAAG,IAAI,kBAAkB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,+GAA+G,EAC/G;QACE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QAClF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QAC5F,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,YAAY,CAAC,GAAG,IAAI,kBAAkB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerInvoiceTools(server: McpServer): void;
3
+ //# sourceMappingURL=invoices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/tools/invoices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyN5D"}
@@ -0,0 +1,160 @@
1
+ import { z } from 'zod';
2
+ import { listInvoices, getInvoice, createInvoice, updateInvoice, sendInvoice, bookkeepInvoice, creditInvoice, } from '../operations/invoices.js';
3
+ import { invoiceListColumns, invoiceDetailColumns, invoiceConfirmColumns } from '../views.js';
4
+ import { confirmationResponse, detailResponse, dryRunResponse, listResponse, requireConfirmation, } from '../tool-output.js';
5
+ const InvoiceRowSchema = z.object({
6
+ ArticleNumber: z.string().optional().describe('Artikelnummer'),
7
+ Description: z.string().describe('Beskrivning'),
8
+ DeliveredQuantity: z.number().describe('Antal'),
9
+ Price: z.number().describe('Pris per enhet (exkl. moms)'),
10
+ AccountNumber: z.number().optional().describe('Kontonummer (default: 3001)'),
11
+ VAT: z.number().optional().describe('Momssats i procent (default: 25)'),
12
+ Unit: z.string().optional().describe('Enhet (t.ex. "st", "tim")'),
13
+ Discount: z.number().optional().describe('Rabatt i procent'),
14
+ });
15
+ const DocumentNumberSchema = z.string().regex(/^\d+$/, 'Document number must be numeric');
16
+ export function registerInvoiceTools(server) {
17
+ server.tool('fortnox_list_invoices', 'Lista/filtrera fakturor i Fortnox. Returnerar: DocumentNumber, CustomerName, InvoiceDate, DueDate, Total, Balance.', {
18
+ filter: z
19
+ .enum(['cancelled', 'fullypaid', 'unpaid', 'unpaidoverdue', 'unbooked'])
20
+ .optional()
21
+ .describe('Filtrera fakturor'),
22
+ customerNumber: z.string().optional().describe('Filtrera på kundnummer'),
23
+ fromDate: z.string().optional().describe('Från datum (YYYY-MM-DD)'),
24
+ toDate: z.string().optional().describe('Till datum (YYYY-MM-DD)'),
25
+ page: z.number().optional().describe('Sidnummer'),
26
+ limit: z.number().optional().describe('Antal per sida'),
27
+ all: z.boolean().optional().describe('Hämta alla sidor (ignorerar page/limit)'),
28
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
29
+ }, async ({ includeRaw, ...params }) => {
30
+ const data = await listInvoices(params);
31
+ return listResponse(data.Invoices ?? [], invoiceListColumns, data, data.MetaInformation, includeRaw);
32
+ });
33
+ server.tool('fortnox_get_invoice', 'Hämta en enskild faktura från Fortnox. Returnerar: DocumentNumber, CustomerNumber, CustomerName, InvoiceDate, DueDate, Total, Balance, Currency, Booked, Sent, OurReference, InvoiceRows.', {
34
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer'),
35
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
36
+ }, async ({ documentNumber, includeRaw }) => {
37
+ const invoice = await getInvoice(documentNumber);
38
+ return detailResponse(invoice, invoiceDetailColumns, invoice, includeRaw);
39
+ });
40
+ server.tool('fortnox_create_invoice', 'Skapa en faktura i Fortnox', {
41
+ CustomerNumber: z.string().describe('Kundnummer'),
42
+ InvoiceRows: z.array(InvoiceRowSchema).describe('Fakturarader'),
43
+ DueDate: z.string().optional().describe('Förfallodatum (YYYY-MM-DD)'),
44
+ InvoiceDate: z.string().optional().describe('Fakturadatum (YYYY-MM-DD)'),
45
+ OurReference: z.string().optional().describe('Vår referens'),
46
+ YourReference: z.string().optional().describe('Er referens'),
47
+ Remarks: z.string().optional().describe('Anmärkning/kommentar'),
48
+ Currency: z.string().optional().describe('Valutakod (default: SEK)'),
49
+ confirm: z.boolean().optional().describe('Bekräfta att fakturan ska skapas'),
50
+ dryRun: z
51
+ .boolean()
52
+ .optional()
53
+ .describe('Visa vad som skulle skickas utan att skapa fakturan'),
54
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
55
+ }, async ({ confirm, dryRun, includeRaw, ...params }) => {
56
+ if (dryRun) {
57
+ return dryRunResponse(`create invoice for customer ${params.CustomerNumber}`, {
58
+ Invoice: params,
59
+ });
60
+ }
61
+ if (!confirm)
62
+ requireConfirmation(`create invoice for customer ${params.CustomerNumber}`);
63
+ const invoice = await createInvoice(params);
64
+ return detailResponse(invoice, invoiceDetailColumns, invoice, includeRaw);
65
+ });
66
+ server.tool('fortnox_update_invoice', 'Uppdatera en befintlig faktura i Fortnox (ej bokförda)', {
67
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer att uppdatera'),
68
+ CustomerNumber: z.string().optional().describe('Kundnummer'),
69
+ InvoiceRows: z
70
+ .array(z.object({
71
+ ArticleNumber: z.string().optional().describe('Artikelnummer'),
72
+ Description: z.string().optional().describe('Beskrivning'),
73
+ DeliveredQuantity: z.number().optional().describe('Antal'),
74
+ Price: z.number().optional().describe('Pris per enhet (exkl. moms)'),
75
+ AccountNumber: z.number().optional().describe('Kontonummer'),
76
+ VAT: z.number().optional().describe('Momssats i procent'),
77
+ Unit: z.string().optional().describe('Enhet (t.ex. "st", "tim")'),
78
+ Discount: z.number().optional().describe('Rabatt i procent'),
79
+ }))
80
+ .optional()
81
+ .describe('Fakturarader (ersätter alla befintliga rader)'),
82
+ DueDate: z.string().optional().describe('Förfallodatum (YYYY-MM-DD)'),
83
+ InvoiceDate: z.string().optional().describe('Fakturadatum (YYYY-MM-DD)'),
84
+ OurReference: z.string().optional().describe('Vår referens'),
85
+ YourReference: z.string().optional().describe('Er referens'),
86
+ Remarks: z.string().optional().describe('Anmärkning/kommentar'),
87
+ Currency: z.string().optional().describe('Valutakod'),
88
+ confirm: z.boolean().optional().describe('Bekräfta att fakturan ska uppdateras'),
89
+ dryRun: z
90
+ .boolean()
91
+ .optional()
92
+ .describe('Visa vad som skulle skickas utan att uppdatera fakturan'),
93
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
94
+ }, async ({ documentNumber, confirm, dryRun, includeRaw, ...fields }) => {
95
+ if (dryRun) {
96
+ return dryRunResponse(`update invoice ${documentNumber}`, { Invoice: fields });
97
+ }
98
+ if (!confirm)
99
+ requireConfirmation(`update invoice ${documentNumber}`);
100
+ const invoice = await updateInvoice(documentNumber, fields);
101
+ return detailResponse(invoice, invoiceDetailColumns, invoice, includeRaw);
102
+ });
103
+ server.tool('fortnox_send_invoice', 'Skicka en faktura via e-post (eller markera för utskrift)', {
104
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer'),
105
+ method: z
106
+ .enum(['email', 'print', 'einvoice'])
107
+ .optional()
108
+ .describe('Sändmetod (default: email)'),
109
+ emailSubject: z
110
+ .string()
111
+ .optional()
112
+ .describe('E-postens ämnesrad (default: behåller befintlig)'),
113
+ emailBody: z.string().optional().describe('E-postens brödtext'),
114
+ emailBcc: z.string().optional().describe('BCC-adress för kopia'),
115
+ confirm: z.boolean().optional().describe('Bekräfta att fakturan ska skickas'),
116
+ dryRun: z.boolean().optional().describe('Visa åtgärden utan att skicka fakturan'),
117
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
118
+ }, async ({ documentNumber, method, emailSubject, emailBody, emailBcc, confirm, dryRun, includeRaw, }) => {
119
+ const sendMethod = method || 'email';
120
+ if (dryRun) {
121
+ return dryRunResponse(`send invoice ${documentNumber} via ${sendMethod}`);
122
+ }
123
+ if (!confirm)
124
+ requireConfirmation(`send invoice ${documentNumber} via ${sendMethod}`);
125
+ const emailOptions = emailSubject || emailBody || emailBcc
126
+ ? { subject: emailSubject, body: emailBody, bcc: emailBcc }
127
+ : undefined;
128
+ const invoice = await sendInvoice(documentNumber, sendMethod, emailOptions);
129
+ return confirmationResponse(`Faktura ${documentNumber} skickad via ${sendMethod}.`, invoice, invoiceConfirmColumns, includeRaw);
130
+ });
131
+ server.tool('fortnox_bookkeep_invoice', 'Bokför en faktura i Fortnox', {
132
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer att bokföra'),
133
+ confirm: z.boolean().optional().describe('Bekräfta att fakturan ska bokföras'),
134
+ dryRun: z.boolean().optional().describe('Visa åtgärden utan att bokföra fakturan'),
135
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
136
+ }, async ({ documentNumber, confirm, dryRun, includeRaw }) => {
137
+ if (dryRun) {
138
+ return dryRunResponse(`bookkeep invoice ${documentNumber}`);
139
+ }
140
+ if (!confirm)
141
+ requireConfirmation(`bookkeep invoice ${documentNumber}`);
142
+ const invoice = await bookkeepInvoice(documentNumber);
143
+ return confirmationResponse(`Faktura ${documentNumber} bokförd.`, invoice, invoiceConfirmColumns, includeRaw);
144
+ });
145
+ server.tool('fortnox_credit_invoice', 'Kreditera en faktura i Fortnox', {
146
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer att kreditera'),
147
+ confirm: z.boolean().optional().describe('Bekräfta att fakturan ska krediteras'),
148
+ dryRun: z.boolean().optional().describe('Visa åtgärden utan att kreditera fakturan'),
149
+ includeRaw: z.boolean().optional().describe('Inkludera rå JSON från Fortnox'),
150
+ }, async ({ documentNumber, confirm, dryRun, includeRaw }) => {
151
+ if (dryRun) {
152
+ return dryRunResponse(`credit invoice ${documentNumber}`);
153
+ }
154
+ if (!confirm)
155
+ requireConfirmation(`credit invoice ${documentNumber}`);
156
+ const invoice = await creditInvoice(documentNumber);
157
+ return confirmationResponse(`Kreditfaktura skapad för faktura ${documentNumber}.`, invoice, invoiceConfirmColumns, includeRaw);
158
+ });
159
+ }
160
+ //# sourceMappingURL=invoices.js.map