Finalisieren von MCP-Ausgangsbelegen korrigieren

Passt die Ausgangsbeleg-Tools an die bestehende FEDEO-Logik an: Entwürfe erhalten keine Belegnummer, Create und Update akzeptieren keine manuellen Nummern mehr, und die Nummernvergabe erfolgt ausschließlich über ein separates Finalisieren-Tool.
This commit is contained in:
2026-05-11 16:38:30 +02:00
parent 2bf52b35fe
commit 1969610130

View File

@@ -78,7 +78,6 @@ const buildOutgoingDocumentPayload = (
const stringFields = [ const stringFields = [
"state", "state",
"documentNumber",
"documentDate", "documentDate",
"deliveryDate", "deliveryDate",
"deliveryDateEnd", "deliveryDateEnd",
@@ -118,8 +117,11 @@ const buildOutgoingDocumentPayload = (
return payload return payload
} }
const shouldAssignDocumentNumber = (args: Record<string, unknown>, state?: unknown) => const assertNoManualDocumentNumber = (args: Record<string, unknown>) => {
args.assignDocumentNumber === true || (state && state !== "Entwurf" && !stringArg(args, "documentNumber")) if (args.documentNumber !== undefined || args.assignDocumentNumber !== undefined) {
throw new Error("Belegnummern werden nur beim Finalisieren vergeben")
}
}
export const accountingTools: McpTool[] = [ export const accountingTools: McpTool[] = [
{ {
@@ -193,21 +195,18 @@ export const accountingTools: McpTool[] = [
{ {
name: "accounting.outgoing_documents.create", name: "accounting.outgoing_documents.create",
title: "Ausgangsbeleg erstellen", 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"], requiredPermissions: ["accounting.outgoing_documents.write"],
inputSchema: { inputSchema: {
type: "object", type: "object",
required: ["type"], required: ["type"],
properties: { properties: {
type: { type: "string" }, type: { type: "string" },
state: { type: "string", default: "Entwurf" },
assignDocumentNumber: { type: "boolean", default: false },
customer: { type: "number" }, customer: { type: "number" },
contact: { type: "number" }, contact: { type: "number" },
contract: { type: "number" }, contract: { type: "number" },
project: { type: "number" }, project: { type: "number" },
plant: { type: "number" }, plant: { type: "number" },
documentNumber: { type: "string" },
documentDate: { type: "string" }, documentDate: { type: "string" },
deliveryDate: { type: "string" }, deliveryDate: { type: "string" },
deliveryDateEnd: { type: "string" }, deliveryDateEnd: { type: "string" },
@@ -228,12 +227,9 @@ export const accountingTools: McpTool[] = [
}, },
}, },
async handler(context, args) { async handler(context, args) {
assertNoManualDocumentNumber(args)
const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId, true) const payload = buildOutgoingDocumentPayload(args, context.userId, context.tenantId, true)
payload.state = "Entwurf"
if (shouldAssignDocumentNumber(args, payload.state) && !payload.documentNumber) {
const result = await useNextNumberRangeNumber(context.server, context.tenantId, String(payload.type))
payload.documentNumber = result.usedNumber
}
const [created] = await context.server.db const [created] = await context.server.db
.insert(createddocuments) .insert(createddocuments)
@@ -246,7 +242,7 @@ export const accountingTools: McpTool[] = [
{ {
name: "accounting.outgoing_documents.update", name: "accounting.outgoing_documents.update",
title: "Ausgangsbeleg aktualisieren", 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"], requiredPermissions: ["accounting.outgoing_documents.write"],
inputSchema: { inputSchema: {
type: "object", type: "object",
@@ -255,13 +251,11 @@ export const accountingTools: McpTool[] = [
id: { type: "number" }, id: { type: "number" },
type: { type: "string" }, type: { type: "string" },
state: { type: "string" }, state: { type: "string" },
assignDocumentNumber: { type: "boolean", default: false },
customer: { type: "number" }, customer: { type: "number" },
contact: { type: "number" }, contact: { type: "number" },
contract: { type: "number" }, contract: { type: "number" },
project: { type: "number" }, project: { type: "number" },
plant: { type: "number" }, plant: { type: "number" },
documentNumber: { type: "string" },
documentDate: { type: "string" }, documentDate: { type: "string" },
deliveryDate: { type: "string" }, deliveryDate: { type: "string" },
deliveryDateEnd: { type: "string" }, deliveryDateEnd: { type: "string" },
@@ -284,6 +278,7 @@ export const accountingTools: McpTool[] = [
async handler(context, args) { async handler(context, args) {
const id = numberArg(args, "id") const id = numberArg(args, "id")
if (!id) throw new Error("id ist erforderlich") if (!id) throw new Error("id ist erforderlich")
assertNoManualDocumentNumber(args)
const [existing] = await context.server.db const [existing] = await context.server.db
.select() .select()
@@ -292,14 +287,60 @@ export const accountingTools: McpTool[] = [
.limit(1) .limit(1)
if (!existing) throw new Error("Ausgangsbeleg nicht gefunden") 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 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 [updated] = await context.server.db
const result = await useNextNumberRangeNumber(context.server, context.tenantId, nextType) .update(createddocuments)
payload.documentNumber = result.usedNumber .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 const [updated] = await context.server.db
.update(createddocuments) .update(createddocuments)