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:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user