diff --git a/backend/src/mcp/tools/accounting.ts b/backend/src/mcp/tools/accounting.ts index 2462d47..0d44887 100644 --- a/backend/src/mcp/tools/accounting.ts +++ b/backend/src/mcp/tools/accounting.ts @@ -41,6 +41,23 @@ const allowedOutgoingDocumentTypes = new Set([ "serialInvoices", ]) +const allowedOutgoingDocumentTaxTypes = new Set([ + "Standard", + "13b UStG", + "19 UStG", + "12.3 UStG", +]) + +const outgoingDocumentTaxableTypes = new Set([ + "invoices", + "cancellationInvoices", + "advanceInvoices", + "serialInvoices", + "confirmationOrders", + "quotes", + "costEstimates", +]) + const documentTypeArg = (args: Record, key = "type") => { const type = stringArg(args, key) || "invoices" if (!allowedOutgoingDocumentTypes.has(type)) { @@ -49,6 +66,50 @@ const documentTypeArg = (args: Record, key = "type") => { return type } +const normalizeOutgoingDocumentTaxType = (value: unknown) => { + const taxType = typeof value === "string" && value.trim() ? value.trim() : "Standard" + if (!allowedOutgoingDocumentTaxTypes.has(taxType)) { + throw new Error(`Ungültiger Dokument-Steuertyp: ${taxType}`) + } + return taxType +} + +const applyOutgoingDocumentTaxType = ( + payload: Record, + args: Record, + documentType: string, + existingTaxType?: unknown, + existingRows?: unknown +) => { + if (!outgoingDocumentTaxableTypes.has(documentType)) { + payload.taxType = null + return + } + + const taxType = args.taxType !== undefined + ? normalizeOutgoingDocumentTaxType(args.taxType) + : existingTaxType + ? normalizeOutgoingDocumentTaxType(existingTaxType) + : "Standard" + + payload.taxType = taxType + + if (["13b UStG", "19 UStG", "12.3 UStG"].includes(taxType)) { + const rows = Array.isArray(payload.rows) + ? payload.rows + : Array.isArray(existingRows) + ? existingRows + : null + + if (!rows) return + + payload.rows = rows.map((row: any) => ({ + ...row, + taxPercent: 0, + })) + } +} + const optionalObjectArg = (args: Record, key: string) => { const value = args[key] return value && typeof value === "object" && !Array.isArray(value) ? value : null @@ -91,7 +152,6 @@ const buildOutgoingDocumentPayload = ( "description", "startText", "endText", - "taxType", ] for (const field of stringFields) { @@ -210,6 +270,26 @@ const validateIncomingInvoiceData = (invoice: Record) => { } export const accountingTools: McpTool[] = [ + { + name: "accounting.outgoing_documents.tax_types.list", + title: "Steuertypen für Ausgangsbelege auflisten", + description: "Listet die unterstützten Dokument-Steuertypen für Ausgangsbelege.", + requiredPermissions: ["accounting.outgoing_documents.read"], + inputSchema: { + type: "object", + properties: {}, + }, + async handler() { + return { + rows: [ + { key: "Standard", label: "Standard", forcesZeroTaxPercent: false }, + { key: "13b UStG", label: "13b UStG", forcesZeroTaxPercent: true }, + { key: "19 UStG", label: "19 UStG Kleinunternehmer", forcesZeroTaxPercent: true }, + { key: "12.3 UStG", label: "12.3 UStG", forcesZeroTaxPercent: true }, + ], + } + }, + }, { name: "accounting.outgoing_documents.list", title: "Ausgangsbelege auflisten", @@ -299,7 +379,11 @@ export const accountingTools: McpTool[] = [ deliveryDateType: { type: "string" }, paymentDays: { type: "number" }, payment_type: { type: "string" }, - taxType: { type: "string" }, + taxType: { + type: "string", + enum: ["Standard", "13b UStG", "19 UStG", "12.3 UStG"], + description: "Steuertyp des gesamten Ausgangsdokuments, nicht der einzelne USt-Satz einer Position.", + }, title: { type: "string" }, description: { type: "string" }, startText: { type: "string" }, @@ -316,6 +400,7 @@ export const accountingTools: McpTool[] = [ assertNoManualDocumentNumber(args) const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId, true) payload.state = "Entwurf" + applyOutgoingDocumentTaxType(payload, args, String(payload.type)) const [created] = await context.server.db .insert(createddocuments) @@ -348,7 +433,11 @@ export const accountingTools: McpTool[] = [ deliveryDateType: { type: "string" }, paymentDays: { type: "number" }, payment_type: { type: "string" }, - taxType: { type: "string" }, + taxType: { + type: "string", + enum: ["Standard", "13b UStG", "19 UStG", "12.3 UStG"], + description: "Steuertyp des gesamten Ausgangsdokuments, nicht der einzelne USt-Satz einer Position.", + }, title: { type: "string" }, description: { type: "string" }, startText: { type: "string" }, @@ -377,6 +466,7 @@ export const accountingTools: McpTool[] = [ const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId) payload.state = "Entwurf" + applyOutgoingDocumentTaxType(payload, args, String(payload.type || existing.type), existing.taxType, existing.rows) const [updated] = await context.server.db .update(createddocuments) @@ -402,7 +492,11 @@ export const accountingTools: McpTool[] = [ deliveryDateEnd: { type: "string" }, paymentDays: { type: "number" }, payment_type: { type: "string" }, - taxType: { type: "string" }, + taxType: { + type: "string", + enum: ["Standard", "13b UStG", "19 UStG", "12.3 UStG"], + description: "Steuertyp des gesamten Ausgangsdokuments, nicht der einzelne USt-Satz einer Position.", + }, rows: { type: "array" }, report: { type: "object" }, availableInPortal: { type: "boolean" }, @@ -427,6 +521,7 @@ export const accountingTools: McpTool[] = [ payload.state = "Gebucht" payload.documentNumber = result.usedNumber + applyOutgoingDocumentTaxType(payload, args, existing.type, existing.taxType, existing.rows) const [updated] = await context.server.db .update(createddocuments)