Files
FEDEO/backend/src/mcp/documentSchemas.ts
florianfederspiel c10bfac23b fix(mcp): Artikel- und Leistungsbeschreibung in Ausgangsbelegpositionen übernehmen
Wie im Belegeditor werden bei mode=normal/service fehlende Beschreibung, Name, Einheit, Preis, USt-Satz und Kostenstelle aus Artikel bzw. Leistung übernommen. descriptionText wird als description gespeichert, weil der Editor nur description liest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 08:23:33 +01:00

64 lines
3.4 KiB
TypeScript

const nullableText = { type: ["string", "null"] }
export const outgoingAddressSchema = {
type: "object",
description: "Abweichende Empfängeradresse; Feldnamen entsprechen dem Belegeditor.",
properties: { street: nullableText, special: nullableText, zip: nullableText, city: nullableText },
additionalProperties: true,
}
export const outgoingRowsSchema = {
type: "array",
description: "Belegpositionen als Objekte. Beträge numerisch in EUR, unit als Einheiten-ID. Mengen und Preise dürfen für Korrekturpositionen negativ sein.",
items: {
type: "object",
properties: {
id: { type: "string", format: "uuid", description: "Optionale Positions-ID; wird sonst erzeugt." },
pos: { type: "string", description: "Positionsnummer, z. B. 1.1; wird sonst erzeugt." },
mode: { type: "string", enum: ["free", "normal", "service", "title", "text", "pagebreak"], default: "free" },
text: { type: "string" },
description: { type: "string", description: "Positionsbeschreibung. Ohne Angabe wird sie bei mode=normal/service aus Artikel bzw. Leistung übernommen, ebenso fehlender Name, Einheit, Preis und USt-Satz." },
descriptionText: { type: "string", description: "Veraltet; wird als description übernommen, wenn description fehlt." },
product: { type: "integer", minimum: 1, description: "Artikel-ID bei mode=normal." },
service: { type: "integer", minimum: 1, description: "Leistungs-ID bei mode=service." },
quantity: { type: "number", default: 1 },
unit: { type: "integer", minimum: 1 },
price: { type: "number", description: "Netto-Einzelpreis vor Positionsrabatt." },
inputPrice: { type: "number", description: "Eingegebener Einzelpreis; wird ohne price auch als price verwendet." },
purchasePrice: { type: "number" },
taxPercent: { type: "number", minimum: 0, maximum: 100 },
discountPercent: { type: "number", minimum: 0, maximum: 100, default: 0 },
costCentre: { type: ["string", "null"], format: "uuid", description: "Positionskostenstelle (abweichende Schreibweise zum Belegfeld costcentre)." },
optional: { type: "boolean" },
alternative: { type: "boolean" },
titleLevel: { type: "integer", minimum: 1, maximum: 3 },
linkedEntitys: {
type: "array",
items: { type: "object", properties: { type: { type: "string" }, subtype: { type: "string" }, id: { type: "integer", minimum: 1 } } },
},
},
// Preserve module-specific position fields used by existing callers.
additionalProperties: true,
},
}
export const outgoingReportSchema = {
type: "object",
description: "Optionale, vom Aufrufer berechnete Kalkulationswerte. Diese Felder werden gespeichert, nicht durch MCP berechnet.",
properties: {
totalProductsPurchasePrice: { type: "number" },
totalProductsFromServicesPurchasePrice: { type: "number" },
totalMargin: { type: "number" },
totalHoursSellingPrice: { type: "number" },
totalHoursFromServices: {
type: "object",
properties: {
total: { type: "number" },
totalPurchasePrice: { type: "number" },
byName: { type: "object", additionalProperties: { type: "number" } },
},
},
},
additionalProperties: true,
}