diff --git a/backend/src/mcp/tools/accounting.ts b/backend/src/mcp/tools/accounting.ts index 807f9e9..22a6b43 100644 --- a/backend/src/mcp/tools/accounting.ts +++ b/backend/src/mcp/tools/accounting.ts @@ -78,7 +78,6 @@ const buildOutgoingDocumentPayload = ( const stringFields = [ "state", - "documentNumber", "documentDate", "deliveryDate", "deliveryDateEnd", @@ -118,8 +117,11 @@ const buildOutgoingDocumentPayload = ( return payload } -const shouldAssignDocumentNumber = (args: Record, state?: unknown) => - args.assignDocumentNumber === true || (state && state !== "Entwurf" && !stringArg(args, "documentNumber")) +const assertNoManualDocumentNumber = (args: Record) => { + if (args.documentNumber !== undefined || args.assignDocumentNumber !== undefined) { + throw new Error("Belegnummern werden nur beim Finalisieren vergeben") + } +} export const accountingTools: McpTool[] = [ { @@ -193,21 +195,18 @@ export const accountingTools: McpTool[] = [ { name: "accounting.outgoing_documents.create", title: "Ausgangsbeleg erstellen", - description: "Erstellt einen Ausgangsbeleg im aktiven Mandanten. Ohne assignDocumentNumber bleibt der Beleg als Entwurf ohne neue Nummer möglich.", + description: "Erstellt einen Ausgangsbeleg-Entwurf im aktiven Mandanten. Belegnummern werden erst beim Finalisieren vergeben.", requiredPermissions: ["accounting.outgoing_documents.write"], inputSchema: { type: "object", required: ["type"], properties: { type: { type: "string" }, - state: { type: "string", default: "Entwurf" }, - assignDocumentNumber: { type: "boolean", default: false }, customer: { type: "number" }, contact: { type: "number" }, contract: { type: "number" }, project: { type: "number" }, plant: { type: "number" }, - documentNumber: { type: "string" }, documentDate: { type: "string" }, deliveryDate: { type: "string" }, deliveryDateEnd: { type: "string" }, @@ -228,12 +227,9 @@ export const accountingTools: McpTool[] = [ }, }, async handler(context, args) { + assertNoManualDocumentNumber(args) const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId, true) - - if (shouldAssignDocumentNumber(args, payload.state) && !payload.documentNumber) { - const result = await useNextNumberRangeNumber(context.server, context.tenantId, String(payload.type)) - payload.documentNumber = result.usedNumber - } + payload.state = "Entwurf" const [created] = await context.server.db .insert(createddocuments) @@ -246,7 +242,7 @@ export const accountingTools: McpTool[] = [ { name: "accounting.outgoing_documents.update", title: "Ausgangsbeleg aktualisieren", - description: "Aktualisiert einen Ausgangsbeleg im aktiven Mandanten.", + description: "Aktualisiert einen Ausgangsbeleg im aktiven Mandanten, solange er noch nicht finalisiert ist.", requiredPermissions: ["accounting.outgoing_documents.write"], inputSchema: { type: "object", @@ -255,13 +251,11 @@ export const accountingTools: McpTool[] = [ id: { type: "number" }, type: { type: "string" }, state: { type: "string" }, - assignDocumentNumber: { type: "boolean", default: false }, customer: { type: "number" }, contact: { type: "number" }, contract: { type: "number" }, project: { type: "number" }, plant: { type: "number" }, - documentNumber: { type: "string" }, documentDate: { type: "string" }, deliveryDate: { type: "string" }, deliveryDateEnd: { type: "string" }, @@ -284,6 +278,7 @@ export const accountingTools: McpTool[] = [ async handler(context, args) { const id = numberArg(args, "id") if (!id) throw new Error("id ist erforderlich") + assertNoManualDocumentNumber(args) const [existing] = await context.server.db .select() @@ -292,14 +287,60 @@ export const accountingTools: McpTool[] = [ .limit(1) if (!existing) throw new Error("Ausgangsbeleg nicht gefunden") + if (existing.state !== "Entwurf") throw new Error("Finalisierte Ausgangsbelege können nicht über update geändert werden") const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId) - const nextType = String(payload.type || existing.type) + payload.state = "Entwurf" - if (shouldAssignDocumentNumber(args, payload.state || existing.state) && !payload.documentNumber && !existing.documentNumber) { - const result = await useNextNumberRangeNumber(context.server, context.tenantId, nextType) - payload.documentNumber = result.usedNumber - } + const [updated] = await context.server.db + .update(createddocuments) + .set(payload as any) + .where(and(eq(createddocuments.id, id), eq(createddocuments.tenant, context.tenantId))) + .returning() + + return { document: updated } + }, + }, + { + name: "accounting.outgoing_documents.finalize", + title: "Ausgangsbeleg finalisieren", + description: "Finalisiert einen Ausgangsbeleg, setzt den Status auf Gebucht und vergibt dabei genau einmal eine Belegnummer.", + requiredPermissions: ["accounting.outgoing_documents.write"], + inputSchema: { + type: "object", + required: ["id"], + properties: { + id: { type: "number" }, + documentDate: { type: "string" }, + deliveryDate: { type: "string" }, + deliveryDateEnd: { type: "string" }, + paymentDays: { type: "number" }, + payment_type: { type: "string" }, + taxType: { type: "string" }, + rows: { type: "array" }, + report: { type: "object" }, + availableInPortal: { type: "boolean" }, + }, + }, + async handler(context, args) { + const id = numberArg(args, "id") + if (!id) throw new Error("id ist erforderlich") + assertNoManualDocumentNumber(args) + + const [existing] = await context.server.db + .select() + .from(createddocuments) + .where(and(eq(createddocuments.id, id), eq(createddocuments.tenant, context.tenantId))) + .limit(1) + + if (!existing) throw new Error("Ausgangsbeleg nicht gefunden") + if (existing.documentNumber) throw new Error("Ausgangsbeleg wurde bereits finalisiert") + + const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId) + const result = await useNextNumberRangeNumber(context.server, context.tenantId, existing.type) + + payload.state = "Gebucht" + payload.documentNumber = result.usedNumber const [updated] = await context.server.db .update(createddocuments)