Bestellnummer prüfen
Der Einkauf trägt bei der sachlichen Prüfung die Bestellnummer der Rechnung ein, ein Feld, das der Workflow selbst deklariert. Danach fragt das Skript das Bestellsystem über die Datenquelle bestellungen nach dieser Bestellung. Passt die Rechnung zur Bestellung (bis zu 2 % darüber), geht sie zur Freigabe, mit dem Betrag der Bestellung als Hinweis. Fehlt die Nummer, gibt es die Bestellung nicht, antwortet das Bestellsystem nicht oder liegt die Rechnung darüber, klärt der Einkauf sie zuerst. Liegt die Bestellung als Dokument in Acriva, geht es ohne Skript und ohne Datenquelle: Bestellabgleich.
Der Workflow
Abschnitt betitelt „Der Workflow“Der Workflow startet für jedes Dokument vom Typ incoming-invoice. Seine Datei workflow.yaml:
$schema: 'https://docs.acriva.de/schemas/workflow.schema.json'format: 1schemaVersion: 4sdk: '1.0.0'key: order-number-checkname: Bestellnummer prüfentemplate: customtrigger: documentType: incoming-invoicefields: - key: orderNumber kind: text labelDe: Bestellnummer labelEn: Order number documentTypes: - incoming-invoicestart: reviewsteps: - kind: humanTask name: review label: Sachliche Prüfung taskKind: review assignees: - when: null assignee: kind: member member: einkauf@example.com fallback: kind: role role: Buchhaltung options: excludeRequester: false excludeActorsOfSteps: [] pickFile: false next: check onRejected: rejected - kind: script name: check label: Bestellung prüfen script: check.ts hook: onApproved inputs: - kind: field key: orderNumber type: text - kind: field key: totalGross type: money - kind: source key: bestellungen returns: - key: result type: enumeration values: - matches - clarify branch: result exits: - value: matches next: approve - value: clarify next: clarify next: approve - kind: humanTask name: clarify label: Bestellung klären taskKind: fix assignees: - when: null assignee: kind: member member: einkauf@example.com fallback: kind: role role: Buchhaltung options: excludeRequester: false excludeActorsOfSteps: [] pickFile: false next: approve - kind: humanTask name: approve label: Freigabe taskKind: approve assignees: - when: null assignee: kind: costCenterResponsible fallback: kind: role role: Buchhaltung options: excludeRequester: true excludeActorsOfSteps: [] pickFile: false next: approved onRejected: rejected - kind: end name: approved label: Freigegeben outcome: approved - kind: end name: rejected label: Zurückgewiesen outcome: rejectedDas Skript check.ts
Abschnitt betitelt „Das Skript check.ts“Hook: onApproved · Eingaben: orderNumber, totalGross, Datenquelle bestellungen · Rückgaben: result (matches, clarify)
import { defineScript, money } from '@acriva/workflow-sdk';
/** How far an invoice may lie above its order, as a share of the order's amount. */const TOLERANCE = 0.02;
/** What the order system answers to `GET bestellungen/<Bestellnummer>`: the order's gross amount in euros. */interface Order { betrag: number;}
/** A source's answer is JSON of any shape until the script has checked it. */const isOrder = (data: unknown): data is Order => typeof data === 'object' && data !== null && typeof (data as Order).betrag === 'number';
export default defineScript({ hook: 'onApproved', outputs: { result: ['matches', 'clarify'] }, async run(ctx) { const { orderNumber, totalGross } = ctx.document.fields; const number = orderNumber?.trim(); if (!number) { ctx.hint( 'Die Rechnung hat keine Bestellnummer. Bitte klären Sie, zu welcher Bestellung sie gehört.', ); return ctx.branch('clarify'); } const result = await ctx.sources.get('bestellungen', { path: number }); if (!result.ok) { ctx.hint( result.status === 404 ? `Die Bestellung ${number} gibt es im Bestellsystem nicht.` : `Das Bestellsystem hat nicht geantwortet (${result.error}). Bitte prüfen Sie die Bestellung ${number} von Hand.`, ); return ctx.branch('clarify'); } if (!isOrder(result.data)) { ctx.hint(`Das Bestellsystem hat zur Bestellung ${number} keinen Betrag geliefert.`); return ctx.branch('clarify'); } const ordered = result.data.betrag; if (totalGross != null && totalGross > ordered * (1 + TOLERANCE)) { ctx.hint( `Die Rechnung über ${money.format(totalGross)} liegt über der Bestellung ${number} über ${money.format(ordered)}.`, ); return ctx.branch('clarify'); } ctx.hint(`Passt zur Bestellung ${number} über ${money.format(ordered)}.`); return ctx.branch('matches'); },});Was es tut
Abschnitt betitelt „Was es tut“Ein Test führt jeden dieser Fälle in der Sandbox aus und vergleicht das Ergebnis.
Eine Rechnung über der Bestellung
Abschnitt betitelt „Eine Rechnung über der Bestellung“- Eingabe:
orderNumber4500012345,totalGross1499.4, Ergebnis der letzten AufgabeApproved - Datenquelle
bestellungen: antwortet{"betrag":1190} - Ausgang:
clarify - Änderungen: Hinweis an der nächsten Aufgabe: „Die Rechnung über 1.499,40 € liegt über der Bestellung 4500012345 über 1.190,00 €.“
Eine Rechnung, die zur Bestellung passt
Abschnitt betitelt „Eine Rechnung, die zur Bestellung passt“- Eingabe:
orderNumber4500012345,totalGross1190, Ergebnis der letzten AufgabeApproved - Datenquelle
bestellungen: antwortet{"betrag":1190} - Ausgang:
matches - Änderungen: Hinweis an der nächsten Aufgabe: „Passt zur Bestellung 4500012345 über 1.190,00 €.“
Eine Rechnung ohne Bestellnummer
Abschnitt betitelt „Eine Rechnung ohne Bestellnummer“- Eingabe:
orderNumbernull,totalGross238, Ergebnis der letzten AufgabeApproved - Ausgang:
clarify - Änderungen: Hinweis an der nächsten Aufgabe: „Die Rechnung hat keine Bestellnummer. Bitte klären Sie, zu welcher Bestellung sie gehört.“
Eine Bestellnummer, die es nicht gibt
Abschnitt betitelt „Eine Bestellnummer, die es nicht gibt“- Eingabe:
orderNumber4500099999,totalGross595, Ergebnis der letzten AufgabeApproved - Datenquelle
bestellungen: keine Daten:http-error(Status 404) - Ausgang:
clarify - Änderungen: Hinweis an der nächsten Aufgabe: „Die Bestellung 4500099999 gibt es im Bestellsystem nicht.“