e-arveldaja-mcp 0.3.1 → 0.3.2
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.
- package/dist/index.js +17 -12
- package/dist/tools/account-balance.js +3 -8
- package/dist/tools/bank-reconciliation.js +2 -3
- package/dist/tools/crud-tools.js +9 -13
- package/dist/tools/document-audit.js +2 -2
- package/dist/tools/estonian-tax.js +4 -9
- package/dist/tools/lightyear-investments.js +4 -10
- package/dist/tools/pdf-workflow.js +9 -17
- package/dist/tools/recurring-invoices.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -93,7 +93,7 @@ async function main() {
|
|
|
93
93
|
const api = createScopedApiContext(connectionState, connectionContexts, invocationStorage);
|
|
94
94
|
const server = new McpServer({
|
|
95
95
|
name: "e-arveldaja",
|
|
96
|
-
version: "0.3.
|
|
96
|
+
version: "0.3.2",
|
|
97
97
|
description: "EXPERIMENTAL, UNOFFICIAL MCP server for the Estonian e-arveldaja (e-Financials) API. " +
|
|
98
98
|
"NOT affiliated with or endorsed by RIK. Use entirely at your own risk — " +
|
|
99
99
|
"this software interacts with live financial data and can create, modify, and delete accounting records. " +
|
|
@@ -102,17 +102,22 @@ async function main() {
|
|
|
102
102
|
"PDF invoice extraction, supplier resolution with business registry lookup, " +
|
|
103
103
|
"and smart booking suggestions based on past invoices.",
|
|
104
104
|
}, {
|
|
105
|
-
instructions: `
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Use list_purchase_articles to
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
105
|
+
instructions: `Purchase invoices:
|
|
106
|
+
- Before booking, call get_vat_info to check VAT registration status.
|
|
107
|
+
- Before creating, call detect_duplicate_purchase_invoice.
|
|
108
|
+
- Pass original vat_price and gross_price exactly — do not recalculate.
|
|
109
|
+
- Use list_purchase_articles to resolve cl_purchase_articles_id.
|
|
110
|
+
- For non-Estonian suppliers, check if reverse charge applies (reversed_vat_id=1).
|
|
111
|
+
- PDF flow: extract_pdf_invoice → validate_invoice_data → resolve_supplier → suggest_booking → create_purchase_invoice_from_pdf → upload_invoice_document → confirm_purchase_invoice.
|
|
112
|
+
|
|
113
|
+
Bank reconciliation:
|
|
114
|
+
- Run reconcile_transactions first, then auto_confirm_exact_matches with dry_run before executing.
|
|
115
|
+
|
|
116
|
+
Reporting:
|
|
117
|
+
- Confirm all journals/invoices/transactions first for accurate financial reports.
|
|
118
|
+
- list_connections / switch_connection for multi-company; switching clears caches.
|
|
119
|
+
- Batch tools default to dry_run — preview before execute=true.
|
|
120
|
+
- Amounts are EUR unless cl_currencies_id specifies otherwise.`,
|
|
116
121
|
});
|
|
117
122
|
// --- Multi-account tools ---
|
|
118
123
|
server.tool("list_connections", "List all available e-arveldaja connections (API key files). " +
|
|
@@ -62,10 +62,7 @@ async function computeAccountBalance(api, accountId, clientId, dateFrom, dateTo,
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
export function registerAccountBalanceTools(server, api) {
|
|
65
|
-
server.tool("compute_account_balance", "Compute account balance from journal postings
|
|
66
|
-
"For liability accounts (C-type): balance = credits - debits. " +
|
|
67
|
-
"For asset accounts (D-type): balance = debits - credits. " +
|
|
68
|
-
"Can filter by client and date range.", {
|
|
65
|
+
server.tool("compute_account_balance", "Compute an account balance from journal postings, with optional client and date filters. Applies the account's debit/credit direction automatically.", {
|
|
69
66
|
account_id: z.number().describe("Account number (e.g. 2110 for short-term loans)"),
|
|
70
67
|
client_id: z.number().optional().describe("Filter by client ID"),
|
|
71
68
|
date_from: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
@@ -88,12 +85,10 @@ export function registerAccountBalanceTools(server, api) {
|
|
|
88
85
|
};
|
|
89
86
|
return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
|
|
90
87
|
});
|
|
91
|
-
server.tool("compute_client_debt", "Compute how much the company owes
|
|
92
|
-
"Checks accounts 2110 (short-term loans), 2310 (accounts payable), 1210 (accounts receivable) by default. " +
|
|
93
|
-
"Override account_ids for other accounts. Uses journal D/C postings.", {
|
|
88
|
+
server.tool("compute_client_debt", "Compute how much the company owes the client and vice versa across selected accounts (default: 2110, 2310, 1210). Uses journal D/C postings.", {
|
|
94
89
|
client_id: z.number().describe("Client ID"),
|
|
95
90
|
account_ids: z.string().optional().describe("Comma-separated account IDs to check (default: 2110,2310,1210)"),
|
|
96
|
-
}, { ...readOnly, title: "Compute Client
|
|
91
|
+
}, { ...readOnly, title: "Compute Client Net Position" }, async ({ client_id, account_ids }) => {
|
|
97
92
|
const ids = account_ids
|
|
98
93
|
? account_ids.split(",").map(s => parseInt(s.trim()))
|
|
99
94
|
: [2110, 2310, 1210]; // short-term loans, accounts payable, accounts receivable
|
|
@@ -136,11 +136,10 @@ export function registerBankReconciliationTools(server, api) {
|
|
|
136
136
|
}],
|
|
137
137
|
};
|
|
138
138
|
});
|
|
139
|
-
server.tool("auto_confirm_exact_matches", "
|
|
140
|
-
"DRY RUN by default - set execute=true to actually confirm.", {
|
|
139
|
+
server.tool("auto_confirm_exact_matches", "Batch-confirm bank transactions with a single high-confidence match (>=90). DRY RUN by default — set execute=true to confirm.", {
|
|
141
140
|
execute: z.boolean().optional().describe("Actually confirm transactions (default false = dry run)"),
|
|
142
141
|
min_confidence: z.number().optional().describe("Minimum confidence (default 90)"),
|
|
143
|
-
}, { ...batch, title: "Auto-Confirm Matches" }, async ({ execute, min_confidence }) => {
|
|
142
|
+
}, { ...batch, title: "Auto-Confirm Bank Matches" }, async ({ execute, min_confidence }) => {
|
|
144
143
|
const threshold = min_confidence ?? 90;
|
|
145
144
|
const dryRun = execute !== true;
|
|
146
145
|
// Get all unconfirmed transactions across pages
|
package/dist/tools/crud-tools.js
CHANGED
|
@@ -126,7 +126,7 @@ export function registerCrudTools(server, api) {
|
|
|
126
126
|
const result = await api.clients.deactivate(id);
|
|
127
127
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
128
128
|
});
|
|
129
|
-
server.tool("restore_client", "Reactivate a
|
|
129
|
+
server.tool("restore_client", "Reactivate a deactivated client", idParam.shape, { ...mutate, title: "Restore Client" }, async ({ id }) => {
|
|
130
130
|
const result = await api.clients.restore(id);
|
|
131
131
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
132
132
|
});
|
|
@@ -136,9 +136,9 @@ export function registerCrudTools(server, api) {
|
|
|
136
136
|
const results = await api.clients.findByName(name);
|
|
137
137
|
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
138
138
|
});
|
|
139
|
-
server.tool("find_client_by_code", "Find client by registry code", {
|
|
139
|
+
server.tool("find_client_by_code", "Find a client by business registry code or personal ID", {
|
|
140
140
|
code: z.string().describe("Business registry code or personal ID"),
|
|
141
|
-
}, { ...readOnly, title: "Find Client by Code" }, async ({ code }) => {
|
|
141
|
+
}, { ...readOnly, title: "Find Client by Registry Code" }, async ({ code }) => {
|
|
142
142
|
const result = await api.clients.findByCode(code);
|
|
143
143
|
return { content: [{ type: "text", text: result ? JSON.stringify(result, null, 2) : "Not found" }] };
|
|
144
144
|
});
|
|
@@ -175,7 +175,7 @@ export function registerCrudTools(server, api) {
|
|
|
175
175
|
const result = await api.products.deactivate(id);
|
|
176
176
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
177
177
|
});
|
|
178
|
-
server.tool("restore_product", "Reactivate a
|
|
178
|
+
server.tool("restore_product", "Reactivate a deactivated product", idParam.shape, { ...mutate, title: "Restore Product" }, async ({ id }) => {
|
|
179
179
|
const result = await api.products.restore(id);
|
|
180
180
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
181
181
|
});
|
|
@@ -252,7 +252,7 @@ export function registerCrudTools(server, api) {
|
|
|
252
252
|
});
|
|
253
253
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
254
254
|
});
|
|
255
|
-
server.tool("confirm_transaction", "Confirm a transaction
|
|
255
|
+
server.tool("confirm_transaction", "Confirm a bank transaction by providing distribution rows", {
|
|
256
256
|
id: z.number().describe("Transaction ID"),
|
|
257
257
|
distributions: z.string().optional().describe("JSON array of distribution rows: [{related_table, related_id?, amount}]"),
|
|
258
258
|
}, { ...destructive, title: "Confirm Transaction" }, async ({ id, distributions }) => {
|
|
@@ -319,7 +319,7 @@ export function registerCrudTools(server, api) {
|
|
|
319
319
|
const result = await api.saleInvoices.confirm(id);
|
|
320
320
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
321
321
|
});
|
|
322
|
-
server.tool("get_sale_invoice_delivery_options", "Get delivery
|
|
322
|
+
server.tool("get_sale_invoice_delivery_options", "Get available delivery methods for a sales invoice (e-invoice or email)", idParam.shape, { ...readOnly, title: "Get Sale Invoice Delivery Options" }, async ({ id }) => {
|
|
323
323
|
const result = await api.saleInvoices.getDeliveryOptions(id);
|
|
324
324
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
325
325
|
});
|
|
@@ -349,10 +349,7 @@ export function registerCrudTools(server, api) {
|
|
|
349
349
|
const result = await api.purchaseInvoices.get(id);
|
|
350
350
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
351
351
|
});
|
|
352
|
-
server.tool("create_purchase_invoice", "Create a purchase invoice. Pass
|
|
353
|
-
"to ensure amounts match for payment reconciliation. " +
|
|
354
|
-
"Items require cl_purchase_articles_id (use list_purchase_articles). " +
|
|
355
|
-
"cl_fringe_benefits_id defaults to 1 (not a fringe benefit).", {
|
|
352
|
+
server.tool("create_purchase_invoice", "Create a draft purchase invoice with line items. Requires cl_purchase_articles_id (use list_purchase_articles). Pass EXACT vat_price and gross_price from the original invoice.", {
|
|
356
353
|
clients_id: z.number().describe("Supplier client ID"),
|
|
357
354
|
client_name: z.string().describe("Supplier name"),
|
|
358
355
|
number: z.string().describe("Invoice number"),
|
|
@@ -399,13 +396,12 @@ export function registerCrudTools(server, api) {
|
|
|
399
396
|
const result = await api.purchaseInvoices.delete(id);
|
|
400
397
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
401
398
|
});
|
|
402
|
-
server.tool("confirm_purchase_invoice", "Confirm a purchase invoice.
|
|
403
|
-
"Automatically fixes vat_price/gross_price if they are missing or inconsistent with the item totals.", idParam.shape, { ...destructive, title: "Confirm Purchase Invoice" }, async ({ id }) => {
|
|
399
|
+
server.tool("confirm_purchase_invoice", "Confirm and lock a purchase invoice. Automatically fixes vat_price/gross_price if missing or inconsistent with item totals.", idParam.shape, { ...destructive, title: "Confirm Purchase Invoice" }, async ({ id }) => {
|
|
404
400
|
const isVatReg = await isCompanyVatRegistered(api);
|
|
405
401
|
const result = await api.purchaseInvoices.confirmWithTotals(id, isVatReg);
|
|
406
402
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
407
403
|
});
|
|
408
|
-
server.tool("invalidate_purchase_invoice", "
|
|
404
|
+
server.tool("invalidate_purchase_invoice", "Return a confirmed purchase invoice to draft status for editing.", idParam.shape, { ...mutate, title: "Invalidate Purchase Invoice" }, async ({ id }) => {
|
|
409
405
|
const result = await api.purchaseInvoices.invalidate(id);
|
|
410
406
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
411
407
|
});
|
|
@@ -82,11 +82,11 @@ export function registerDocumentAuditTools(server, api) {
|
|
|
82
82
|
}],
|
|
83
83
|
};
|
|
84
84
|
});
|
|
85
|
-
server.tool("detect_duplicate_purchase_invoice", "Check for
|
|
85
|
+
server.tool("detect_duplicate_purchase_invoice", "Check for duplicate purchase invoices by supplier + invoice number, and by supplier + amount + date.", {
|
|
86
86
|
clients_id: z.number().optional().describe("Filter by supplier ID"),
|
|
87
87
|
date_from: z.string().optional().describe("Start date"),
|
|
88
88
|
date_to: z.string().optional().describe("End date"),
|
|
89
|
-
}, { ...readOnly, title: "Detect Duplicate Invoices" }, async ({ clients_id, date_from, date_to }) => {
|
|
89
|
+
}, { ...readOnly, title: "Detect Duplicate Purchase Invoices" }, async ({ clients_id, date_from, date_to }) => {
|
|
90
90
|
const allPurchases = await api.purchaseInvoices.listAll();
|
|
91
91
|
const filtered = allPurchases.filter((inv) => {
|
|
92
92
|
if (inv.status === "DELETED" || inv.status === "INVALIDATED")
|
|
@@ -48,10 +48,7 @@ async function computeRetainedEarningsBalance(api, accountId, asOfDate) {
|
|
|
48
48
|
return roundMoney(credit - debit);
|
|
49
49
|
}
|
|
50
50
|
export function registerEstonianTaxTools(server, api) {
|
|
51
|
-
server.tool("prepare_dividend_package", "Calculate dividend
|
|
52
|
-
"Estonian CIT on dividends: 22/78 (from 2025). " +
|
|
53
|
-
"Creates a debit to retained earnings and credit to payable + tax liability. " +
|
|
54
|
-
"Validates accounts exist and checks retained earnings balance before posting.", {
|
|
51
|
+
server.tool("prepare_dividend_package", "Calculate dividend tax (22/78 CIT) and create draft journal entries for dividend payable and tax liability. Validates retained earnings balance and net assets.", {
|
|
55
52
|
net_dividend: z.number().describe("Net dividend amount to shareholder (EUR)"),
|
|
56
53
|
shareholder_client_id: z.number().describe("Shareholder client ID"),
|
|
57
54
|
effective_date: z.string().describe("Distribution date (YYYY-MM-DD)"),
|
|
@@ -60,7 +57,7 @@ export function registerEstonianTaxTools(server, api) {
|
|
|
60
57
|
tax_payable_account: z.number().optional().describe("CIT payable account (default 2540)"),
|
|
61
58
|
share_capital_account: z.number().optional().describe("Share capital account for ÄS §157 net-assets check (default 3000)"),
|
|
62
59
|
force: z.boolean().optional().describe("Create journal even if retained earnings are insufficient (default false)"),
|
|
63
|
-
}, { ...create, title: "Prepare Dividend
|
|
60
|
+
}, { ...create, title: "Prepare Dividend Distribution" }, async ({ net_dividend, shareholder_client_id, effective_date, retained_earnings_account, dividend_payable_account, tax_payable_account, share_capital_account, force }) => {
|
|
64
61
|
const retainedAccount = retained_earnings_account ?? 3020;
|
|
65
62
|
const payableAccount = dividend_payable_account ?? 2370;
|
|
66
63
|
const taxAccount = tax_payable_account ?? 2540;
|
|
@@ -172,9 +169,7 @@ export function registerEstonianTaxTools(server, api) {
|
|
|
172
169
|
}],
|
|
173
170
|
};
|
|
174
171
|
});
|
|
175
|
-
server.tool("create_owner_expense_reimbursement", "
|
|
176
|
-
"Common for micro-OÜs where the owner pays with personal funds. " +
|
|
177
|
-
"Books input VAT separately only for VAT-registered companies and validates accounts in chart of accounts.", {
|
|
172
|
+
server.tool("create_owner_expense_reimbursement", "Create a journal for a business expense paid personally by the owner. Splits input VAT for VAT-registered companies.", {
|
|
178
173
|
owner_client_id: z.number().describe("Owner/shareholder client ID"),
|
|
179
174
|
effective_date: z.string().describe("Expense date (YYYY-MM-DD)"),
|
|
180
175
|
description: z.string().describe("Expense description"),
|
|
@@ -185,7 +180,7 @@ export function registerEstonianTaxTools(server, api) {
|
|
|
185
180
|
vat_account: z.number().optional().describe("Input VAT account (default 1510)"),
|
|
186
181
|
payable_account: z.number().optional().describe("Payable to owner account (default 2110)"),
|
|
187
182
|
document_number: z.string().optional().describe("Receipt/document number"),
|
|
188
|
-
}, { ...create, title: "Book Owner Expense" }, async ({ owner_client_id, effective_date, description, net_amount, vat_rate, vat_amount, expense_account, vat_account, payable_account, document_number }) => {
|
|
183
|
+
}, { ...create, title: "Book Owner-Paid Expense" }, async ({ owner_client_id, effective_date, description, net_amount, vat_rate, vat_amount, expense_account, vat_account, payable_account, document_number }) => {
|
|
189
184
|
const vatRegistered = await isCompanyVatRegistered(api);
|
|
190
185
|
const vatAcc = vat_account ?? 1510;
|
|
191
186
|
const payAcc = payable_account ?? 2110;
|
|
@@ -305,7 +305,7 @@ export function registerLightyearTools(server, api) {
|
|
|
305
305
|
"distributions, deposits, withdrawals. Filters out BRICEKSP money market fund trades. " +
|
|
306
306
|
"Pairs foreign currency trades with their FX conversion entries.", {
|
|
307
307
|
file_path: z.string().describe("Absolute path to Lightyear AccountStatement CSV file"),
|
|
308
|
-
}, { ...readOnly, title: "Parse Lightyear Statement" }, async ({ file_path }) => {
|
|
308
|
+
}, { ...readOnly, title: "Parse Lightyear Account Statement" }, async ({ file_path }) => {
|
|
309
309
|
const csv = await readCsvFile(file_path);
|
|
310
310
|
const rows = parseAccountStatement(csv);
|
|
311
311
|
const { trades, warnings: fxWarnings } = extractTrades(rows);
|
|
@@ -378,7 +378,7 @@ export function registerLightyearTools(server, api) {
|
|
|
378
378
|
server.tool("parse_lightyear_capital_gains", "Parse a Lightyear Capital Gains Statement CSV (FIFO method). " +
|
|
379
379
|
"Shows cost basis, proceeds, and realized capital gains per sale.", {
|
|
380
380
|
file_path: z.string().describe("Absolute path to Lightyear CapitalGainsStatement CSV file"),
|
|
381
|
-
}, { ...readOnly, title: "Parse Capital Gains" }, async ({ file_path }) => {
|
|
381
|
+
}, { ...readOnly, title: "Parse Lightyear Capital Gains" }, async ({ file_path }) => {
|
|
382
382
|
const csv = await readCsvFile(file_path);
|
|
383
383
|
const gains = parseCapitalGains(csv);
|
|
384
384
|
const totalGains = gains.reduce((s, g) => s + g.capital_gains_eur, 0);
|
|
@@ -661,11 +661,7 @@ export function registerLightyearTools(server, api) {
|
|
|
661
661
|
}],
|
|
662
662
|
};
|
|
663
663
|
});
|
|
664
|
-
server.tool("book_lightyear_distributions", "Create journal entries for Lightyear dividend
|
|
665
|
-
"Checks for duplicates using reference IDs. " +
|
|
666
|
-
"Books: Debit broker account (net received), Credit income account. " +
|
|
667
|
-
"Income = gross (net + tax + fee). " +
|
|
668
|
-
"Withheld tax (tax_amount) booked to tax_account. Platform fee booked to fee_account (default 8610).", {
|
|
664
|
+
server.tool("book_lightyear_distributions", "Create journal entries for Lightyear dividend and interest distributions, including withheld tax. DRY RUN by default.", {
|
|
669
665
|
file_path: z.string().describe("Absolute path to Lightyear AccountStatement CSV file"),
|
|
670
666
|
broker_account: z.number().describe("Broker cash account (e.g. 1120 Lightyear konto)"),
|
|
671
667
|
broker_dimension_id: z.number().optional().describe("Dimension ID for broker account (accounts_dimensions_id)"),
|
|
@@ -789,9 +785,7 @@ export function registerLightyearTools(server, api) {
|
|
|
789
785
|
}],
|
|
790
786
|
};
|
|
791
787
|
});
|
|
792
|
-
server.tool("lightyear_portfolio_summary", "Compute current
|
|
793
|
-
"Uses weighted average cost method. Properly reduces cost basis on sells. " +
|
|
794
|
-
"Useful for verifying investment account balance.", {
|
|
788
|
+
server.tool("lightyear_portfolio_summary", "Compute current holdings and cost basis from a Lightyear account statement. Useful for verifying investment account balance.", {
|
|
795
789
|
file_path: z.string().describe("Absolute path to Lightyear AccountStatement CSV file"),
|
|
796
790
|
}, { ...readOnly, title: "Lightyear Portfolio Summary" }, async ({ file_path }) => {
|
|
797
791
|
const csv = await readCsvFile(file_path);
|
|
@@ -46,12 +46,9 @@ function extractPdfHints(text) {
|
|
|
46
46
|
return result;
|
|
47
47
|
}
|
|
48
48
|
export function registerPdfWorkflowTools(server, api) {
|
|
49
|
-
server.tool("extract_pdf_invoice", "Extract text and
|
|
50
|
-
"Returns raw text + detected IBAN, registry code, VAT number, reference number. " +
|
|
51
|
-
"YOU must read the raw_text and extract: supplier name, invoice number, dates, " +
|
|
52
|
-
"amounts (net, VAT, gross), and line items. Then call validate_invoice_data to verify.", {
|
|
49
|
+
server.tool("extract_pdf_invoice", "Extract text and key identifiers from a supplier invoice PDF. Returns raw text + detected IBAN, registry code, VAT number, reference number. Read raw_text to extract all invoice fields, then call validate_invoice_data.", {
|
|
53
50
|
file_path: z.string().describe("Absolute path to the PDF file"),
|
|
54
|
-
}, { ...readOnly, title: "Extract
|
|
51
|
+
}, { ...readOnly, title: "Extract Supplier Invoice PDF" }, async ({ file_path }) => {
|
|
55
52
|
const resolved = await validatePdfPath(file_path);
|
|
56
53
|
const buffer = await readFile(resolved);
|
|
57
54
|
const pdfData = await pdf(buffer);
|
|
@@ -187,9 +184,7 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
187
184
|
}],
|
|
188
185
|
};
|
|
189
186
|
});
|
|
190
|
-
server.tool("resolve_supplier", "
|
|
191
|
-
"then VAT number, then name (fuzzy). If not found, optionally creates a new client. " +
|
|
192
|
-
"Also looks up business registry (äriregister) data if available.", {
|
|
187
|
+
server.tool("resolve_supplier", "Match a supplier to an existing client by registry code, VAT number, or name (fuzzy). Optionally creates a new client. Looks up Estonian business registry data.", {
|
|
193
188
|
name: z.string().optional().describe("Supplier name from invoice"),
|
|
194
189
|
reg_code: z.string().optional().describe("Registry code (registrikood)"),
|
|
195
190
|
vat_no: z.string().optional().describe("VAT number (KMKR)"),
|
|
@@ -197,7 +192,7 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
197
192
|
auto_create: z.boolean().optional().describe("Create client if not found (default false)"),
|
|
198
193
|
country: z.string().optional().describe("Country code for auto-create (default EST)"),
|
|
199
194
|
is_physical_entity: z.boolean().optional().describe("Natural person (default false = legal entity)"),
|
|
200
|
-
}, { ...create, title: "
|
|
195
|
+
}, { ...create, title: "Find or Create Supplier" }, async ({ name, reg_code, vat_no, iban, auto_create, country, is_physical_entity }) => {
|
|
201
196
|
// 1. Search by registry code
|
|
202
197
|
if (reg_code) {
|
|
203
198
|
const byCode = await api.clients.findByCode(reg_code);
|
|
@@ -308,12 +303,11 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
308
303
|
}],
|
|
309
304
|
};
|
|
310
305
|
});
|
|
311
|
-
server.tool("suggest_booking", "
|
|
312
|
-
"how to book a new invoice (which accounts, articles, etc).", {
|
|
306
|
+
server.tool("suggest_booking", "Suggest purchase articles and accounts for a new invoice based on similar confirmed invoices from the same supplier.", {
|
|
313
307
|
clients_id: z.number().describe("Supplier client ID"),
|
|
314
308
|
description: z.string().optional().describe("Invoice item description to match"),
|
|
315
309
|
limit: z.number().optional().describe("Max past invoices to return (default 3)"),
|
|
316
|
-
}, { ...readOnly, title: "Suggest Booking" }, async ({ clients_id, description, limit }) => {
|
|
310
|
+
}, { ...readOnly, title: "Suggest Purchase Booking" }, async ({ clients_id, description, limit }) => {
|
|
317
311
|
const maxResults = limit ?? 3;
|
|
318
312
|
const allInvoices = await api.purchaseInvoices.listAll();
|
|
319
313
|
// Filter by supplier
|
|
@@ -364,9 +358,7 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
364
358
|
}],
|
|
365
359
|
};
|
|
366
360
|
});
|
|
367
|
-
server.tool("create_purchase_invoice_from_pdf", "
|
|
368
|
-
"Resolves supplier, suggests booking, creates the invoice as DRAFT. " +
|
|
369
|
-
"Pass EXACT vat_price and gross_price from the original invoice for payment matching.", {
|
|
361
|
+
server.tool("create_purchase_invoice_from_pdf", "Create a draft purchase invoice from extracted and validated PDF data. Pass EXACT vat_price and gross_price from the original invoice for payment matching.", {
|
|
370
362
|
supplier_client_id: z.number().describe("Supplier client ID (from resolve_supplier)"),
|
|
371
363
|
invoice_number: z.string().describe("Invoice number"),
|
|
372
364
|
invoice_date: z.string().describe("Invoice date (YYYY-MM-DD)"),
|
|
@@ -379,7 +371,7 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
379
371
|
notes: z.string().optional().describe("Notes (e.g. PDF filename)"),
|
|
380
372
|
ref_number: z.string().optional().describe("Reference number"),
|
|
381
373
|
bank_account_no: z.string().optional().describe("Supplier bank account"),
|
|
382
|
-
}, { ...create, title: "Create Invoice from PDF" }, async (params) => {
|
|
374
|
+
}, { ...create, title: "Create Purchase Invoice from PDF" }, async (params) => {
|
|
383
375
|
const supplier = await api.clients.get(params.supplier_client_id);
|
|
384
376
|
const isVatReg = await isCompanyVatRegistered(api);
|
|
385
377
|
const purchaseArticles = await getPurchaseArticlesWithVat(api);
|
|
@@ -413,7 +405,7 @@ export function registerPdfWorkflowTools(server, api) {
|
|
|
413
405
|
server.tool("upload_invoice_document", "Upload a PDF document to an existing purchase invoice", {
|
|
414
406
|
invoice_id: z.number().describe("Purchase invoice ID"),
|
|
415
407
|
file_path: z.string().describe("Absolute path to the PDF file"),
|
|
416
|
-
}, { ...mutate, title: "Upload Invoice
|
|
408
|
+
}, { ...mutate, title: "Upload Purchase Invoice PDF" }, async ({ invoice_id, file_path }) => {
|
|
417
409
|
const resolved = await validatePdfPath(file_path);
|
|
418
410
|
const buffer = await readFile(resolved);
|
|
419
411
|
const base64 = buffer.toString("base64");
|
|
@@ -9,7 +9,7 @@ export function registerRecurringInvoiceTools(server, api) {
|
|
|
9
9
|
target_journal_date: z.string().describe("New turnover date (YYYY-MM-DD)"),
|
|
10
10
|
invoice_ids: z.string().optional().describe("Comma-separated source invoice IDs to copy (default: all confirmed from source month)"),
|
|
11
11
|
auto_confirm: z.boolean().optional().describe("Confirm created invoices (default false)"),
|
|
12
|
-
}, { ...batch, title: "Create Recurring Invoices" }, async ({ source_month, target_date, target_journal_date, invoice_ids, auto_confirm }) => {
|
|
12
|
+
}, { ...batch, title: "Create Recurring Sale Invoices" }, async ({ source_month, target_date, target_journal_date, invoice_ids, auto_confirm }) => {
|
|
13
13
|
// Get source invoices
|
|
14
14
|
const allSales = await api.saleInvoices.listAll();
|
|
15
15
|
const sourceFrom = `${source_month}-01`;
|