Add erpnext-mcp/src/tools/accounting.ts
This commit is contained in:
parent
ea23d7146e
commit
ad1dad03d9
1 changed files with 234 additions and 0 deletions
234
erpnext-mcp/src/tools/accounting.ts
Normal file
234
erpnext-mcp/src/tools/accounting.ts
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { ERPNextClient, truncateResponse } from "../services/erpnext-client.js";
|
||||
import { z } from "zod";
|
||||
|
||||
export function registerAccountingTools(server: McpServer, client: ERPNextClient): void {
|
||||
|
||||
// ─── 16. Get Account Balance ───────────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_get_account_balance",
|
||||
{
|
||||
title: "Get Account Balance",
|
||||
description: `Get the balance of a specific GL account.
|
||||
|
||||
Args:
|
||||
- account: Account name
|
||||
- company: Company name
|
||||
- date: Optional date for balance as-of (YYYY-MM-DD)`,
|
||||
inputSchema: z.object({
|
||||
account: z.string().describe("Account name"),
|
||||
company: z.string().describe("Company name"),
|
||||
date: z.string().optional().describe("Date for as-of balance (YYYY-MM-DD)"),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await client.callMethod("erpnext.accounts.utils.get_balance_on", {
|
||||
account: params.account,
|
||||
date: params.date,
|
||||
company: params.company,
|
||||
});
|
||||
return { content: [{ type: "text", text: `Balance of ${params.account}: ${result}` }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 17. Get Exchange Rate ─────────────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_get_exchange_rate",
|
||||
{
|
||||
title: "Get Exchange Rate",
|
||||
description: `Get currency exchange rate between two currencies.
|
||||
|
||||
Args:
|
||||
- from_currency: Source currency code (e.g. "USD")
|
||||
- to_currency: Target currency code (e.g. "EUR")
|
||||
- date: Optional transaction date`,
|
||||
inputSchema: z.object({
|
||||
from_currency: z.string().describe("Source currency (e.g. USD)"),
|
||||
to_currency: z.string().describe("Target currency (e.g. EUR)"),
|
||||
date: z.string().optional().describe("Transaction date (YYYY-MM-DD)"),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await client.callMethod("erpnext.setup.utils.get_exchange_rate", {
|
||||
from_currency: params.from_currency,
|
||||
to_currency: params.to_currency,
|
||||
transaction_date: params.date,
|
||||
});
|
||||
return { content: [{ type: "text", text: `Exchange rate ${params.from_currency} → ${params.to_currency}: ${result}` }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 18. Create Journal Entry ──────────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_create_journal_entry",
|
||||
{
|
||||
title: "Create Journal Entry",
|
||||
description: `Create a Journal Entry with debit/credit lines.
|
||||
|
||||
Args:
|
||||
- company: Company name
|
||||
- posting_date: Posting date (YYYY-MM-DD)
|
||||
- accounts: Array of account line objects with {account, debit_in_account_currency, credit_in_account_currency, party_type?, party?, cost_center?}
|
||||
- user_remark: Optional remark/narration
|
||||
- voucher_type: Optional (default "Journal Entry"). Options: "Journal Entry", "Bank Entry", "Cash Entry", "Credit Card Entry", "Debit Note", "Credit Note"`,
|
||||
inputSchema: z.object({
|
||||
company: z.string(),
|
||||
posting_date: z.string(),
|
||||
accounts: z.array(z.object({
|
||||
account: z.string(),
|
||||
debit_in_account_currency: z.number().default(0),
|
||||
credit_in_account_currency: z.number().default(0),
|
||||
party_type: z.string().optional(),
|
||||
party: z.string().optional(),
|
||||
cost_center: z.string().optional(),
|
||||
})),
|
||||
user_remark: z.string().optional(),
|
||||
voucher_type: z.string().default("Journal Entry"),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const doc = await client.createDocument("Journal Entry", {
|
||||
company: params.company,
|
||||
posting_date: params.posting_date,
|
||||
voucher_type: params.voucher_type,
|
||||
user_remark: params.user_remark,
|
||||
accounts: params.accounts,
|
||||
});
|
||||
return { content: [{ type: "text", text: `Created Journal Entry: ${doc.name}` }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 19. Make Payment Entry ────────────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_make_payment_entry",
|
||||
{
|
||||
title: "Make Payment Entry from Invoice",
|
||||
description: `Create a Payment Entry from a Sales or Purchase Invoice.
|
||||
|
||||
Args:
|
||||
- source_doctype: "Sales Invoice" or "Purchase Invoice"
|
||||
- source_name: Invoice name/ID`,
|
||||
inputSchema: z.object({
|
||||
source_doctype: z.enum(["Sales Invoice", "Purchase Invoice"]),
|
||||
source_name: z.string(),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const method = params.source_doctype === "Sales Invoice"
|
||||
? "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry"
|
||||
: "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
|
||||
const result = await client.callMethod(method, {
|
||||
dt: params.source_doctype,
|
||||
dn: params.source_name,
|
||||
});
|
||||
return { content: [{ type: "text", text: `Payment Entry draft created:\n${JSON.stringify(result, null, 2)}` }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 20. Get Outstanding Invoices ──────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_get_outstanding_invoices",
|
||||
{
|
||||
title: "Get Outstanding Invoices",
|
||||
description: `List outstanding (unpaid) invoices for a party.
|
||||
|
||||
Args:
|
||||
- party_type: "Customer" or "Supplier"
|
||||
- party: Party name
|
||||
- company: Company name`,
|
||||
inputSchema: z.object({
|
||||
party_type: z.enum(["Customer", "Supplier"]),
|
||||
party: z.string(),
|
||||
company: z.string(),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await client.callMethod(
|
||||
"erpnext.accounts.doctype.payment_entry.payment_entry.get_outstanding_reference_documents",
|
||||
{
|
||||
party_type: params.party_type,
|
||||
party: params.party,
|
||||
company: params.company,
|
||||
}
|
||||
);
|
||||
return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 21. Get Fiscal Year ───────────────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_get_fiscal_year",
|
||||
{
|
||||
title: "Get Fiscal Year",
|
||||
description: `Get the fiscal year for a given date and company.`,
|
||||
inputSchema: z.object({
|
||||
date: z.string().describe("Date (YYYY-MM-DD)"),
|
||||
company: z.string().optional(),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await client.callMethod("erpnext.accounts.utils.get_fiscal_year", {
|
||||
date: params.date,
|
||||
company: params.company,
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ─── 22. Get Party Account Balance ─────────────────────
|
||||
server.registerTool(
|
||||
"erpnext_get_party_balance",
|
||||
{
|
||||
title: "Get Party Account Balance",
|
||||
description: `Get the account balance for a Customer or Supplier.`,
|
||||
inputSchema: z.object({
|
||||
party_type: z.enum(["Customer", "Supplier"]),
|
||||
party: z.string(),
|
||||
company: z.string(),
|
||||
}).strict(),
|
||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
||||
},
|
||||
async (params) => {
|
||||
try {
|
||||
const result = await client.callMethod("erpnext.accounts.utils.get_balance_on", {
|
||||
party_type: params.party_type,
|
||||
party: params.party,
|
||||
company: params.company,
|
||||
});
|
||||
return { content: [{ type: "text", text: `Balance for ${params.party_type} "${params.party}": ${result}` }] };
|
||||
} catch (error) {
|
||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue