feat(mcp): Belegvorbereitung für Eingangsrechnungen anstoßen
- accounting.incoming_invoices.prepare startet die Vorbereitung für alle offenen oder ausgewählte Dateien und liefert angelegte Entwürfe samt Validierung sowie übersprungene Dateien - Vorbereitungslauf meldet sein Ergebnis und läuft je Mandant nacheinander, damit parallele Aufrufe keine doppelten Belege anlegen Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
41
backend/tests/mcpIncomingInvoicePreparation.test.ts
Normal file
41
backend/tests/mcpIncomingInvoicePreparation.test.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import assert from "node:assert/strict"
|
||||
import test from "node:test"
|
||||
import { mcpToolMap } from "../src/mcp/registry"
|
||||
|
||||
const fileA = "00000000-0000-4000-8000-00000000000a"
|
||||
const fileB = "00000000-0000-4000-8000-00000000000b"
|
||||
const tool = mcpToolMap.get("accounting.incoming_invoices.prepare")!
|
||||
|
||||
function context(result: any, invoices: any[] = []) {
|
||||
const calls: any[] = []
|
||||
const db: any = {
|
||||
select: () => ({ from: () => ({ where: async () => invoices }) }),
|
||||
}
|
||||
const services = { prepareIncomingInvoices: { run: async (tenantId: number, options: any) => { calls.push({ tenantId, options }); return result } } }
|
||||
return { calls, context: { server: { db, services }, tenantId: 7, userId: "user", isAdmin: true, permissions: [] } as any }
|
||||
}
|
||||
|
||||
test("prepare runs for the active tenant and returns created drafts with validation", async () => {
|
||||
const invoice = { id: 11, tenant: 7, state: "Entwurf", archived: false }
|
||||
const { calls, context: ctx } = context({ filesFound: 1, created: [{ fileId: fileA, invoiceId: 11, source: "gpt" }], skipped: [] }, [invoice])
|
||||
const result: any = await tool.handler(ctx, {})
|
||||
assert.deepEqual(calls, [{ tenantId: 7, options: { fileIds: undefined } }])
|
||||
assert.equal(result.created[0].invoice.id, 11)
|
||||
assert.ok(result.created[0].validation)
|
||||
assert.deepEqual(result.skipped, [])
|
||||
})
|
||||
|
||||
test("prepare limits to given files and reports files it could not handle", async () => {
|
||||
const { calls, context: ctx } = context({ filesFound: 1, created: [], skipped: [{ fileId: fileA, reason: "Keine Belegdaten erkannt" }] })
|
||||
const result: any = await tool.handler(ctx, { fileIds: [fileA, fileB.toUpperCase(), fileB] })
|
||||
assert.deepEqual(calls[0].options.fileIds, [fileA, fileB])
|
||||
assert.deepEqual(result.skipped.map((entry: any) => entry.fileId), [fileA, fileB])
|
||||
})
|
||||
|
||||
test("prepare validates input and surfaces tenant configuration errors", async () => {
|
||||
const { context: ctx } = context({ filesFound: 0, created: [], skipped: [], error: "Dateityp für Eingangsrechnungen fehlt" })
|
||||
await assert.rejects(tool.handler(ctx, { fileIds: [] }), /1 bis 50/)
|
||||
await assert.rejects(tool.handler(ctx, { fileIds: ["abc"] }), /UUID/)
|
||||
await assert.rejects(tool.handler(ctx, {}), /Dateityp für Eingangsrechnungen fehlt/)
|
||||
assert.deepEqual(tool.requiredPermissions, ["accounting.incoming_invoices.write"])
|
||||
})
|
||||
Reference in New Issue
Block a user