Zum Inhalt springen

Preis gegen die Preisliste prüfen

Für Verbrauchsmaterial haben Sie mit Ihren Lieferanten feste Preise vereinbart. Die Preisliste steht in einer Datentabelle preisliste mit der Artikelnummer als Schlüsselspalte, hochgeladen aus Excel oder CSV. Bei der sachlichen Prüfung trägt der Einkauf Artikelnummer und Einzelpreis der Rechnung ein, zwei Felder, die der Workflow selbst deklariert. Danach vergleicht das Skript den Einzelpreis mit dem Listenpreis: Liegt er höchstens 2 % darüber, geht die Rechnung zur normalen Freigabe; liegt er höher oder fehlt der Artikel in der Liste, gibt die Geschäftsführung frei, mit einem Hinweis auf die Abweichung.

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: 1
schemaVersion: 4
sdk: '1.0.0'
key: price-list-check
name: Preis gegen die Preisliste prüfen
template: custom
trigger:
documentType: incoming-invoice
fields:
- key: itemNumber
kind: text
labelDe: Artikelnummer
labelEn: Item number
documentTypes:
- incoming-invoice
- key: unitPrice
kind: money
labelDe: Einzelpreis
labelEn: Unit price
documentTypes:
- incoming-invoice
start: review
steps:
- 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: checkPrice
onRejected: rejected
- kind: script
name: checkPrice
label: Preis prüfen
script: check-price.ts
hook: onApproved
inputs:
- kind: field
key: itemNumber
type: text
- kind: field
key: unitPrice
type: money
- kind: table
key: preisliste
returns:
- key: price
type: enumeration
values:
- listPrice
- deviation
branch: price
exits:
- value: listPrice
next: approve
- value: deviation
next: managementApproval
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: humanTask
name: managementApproval
label: Freigabe Geschäftsführung
taskKind: approve
assignees:
- when: null
assignee:
kind: role
role: Geschäftsführung
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: rejected

Hook: onApproved · Eingaben: itemNumber, unitPrice, Datentabelle preisliste · Rückgaben: price (listPrice, deviation)

import { defineScript, money } from '@acriva/workflow-sdk';
/** How far a unit price may lie above the list price, as a share of it. */
const TOLERANCE = 0.02;
export default defineScript({
hook: 'onApproved',
outputs: { price: ['listPrice', 'deviation'] },
async run(ctx) {
const { itemNumber, unitPrice } = ctx.document.fields;
const number = itemNumber?.trim();
if (!number || unitPrice == null) {
ctx.hint('Artikelnummer oder Einzelpreis fehlt, der Preis ist nicht geprüft.');
return ctx.branch('deviation');
}
const item = await ctx.tables.lookup('preisliste', number);
if (item === null || item.preis === null) {
ctx.hint(`Der Artikel ${number} steht nicht in der Preisliste.`);
return ctx.branch('deviation');
}
if (unitPrice > item.preis * (1 + TOLERANCE)) {
ctx.hint(
`${item.bezeichnung ?? number}: berechnet ${money.format(unitPrice)}, laut Preisliste ${money.format(item.preis)}.`,
);
return ctx.branch('deviation');
}
return ctx.branch('listPrice');
},
});

Ein Test führt jeden dieser Fälle in der Sandbox aus und vergleicht das Ergebnis.

  • Eingabe: itemNumber TON-305A, unitPrice 99.5, Ergebnis der letzten Aufgabe Approved
  • Datentabelle preisliste: 2 Zeilen
    • artikelnummer PAP-A4-80, bezeichnung Kopierpapier A4, 80 g, 500 Blatt, preis 4.95
    • artikelnummer TON-305A, bezeichnung Toner 305A schwarz, preis 89.9
  • Ausgang: deviation
  • Änderungen: Hinweis an der nächsten Aufgabe: „Toner 305A schwarz: berechnet 99,50 €, laut Preisliste 89,90 €.“
  • Eingabe: itemNumber PAP-A4-80, unitPrice 4.95, Ergebnis der letzten Aufgabe Approved
  • Datentabelle preisliste: 2 Zeilen
    • artikelnummer PAP-A4-80, bezeichnung Kopierpapier A4, 80 g, 500 Blatt, preis 4.95
    • artikelnummer TON-305A, bezeichnung Toner 305A schwarz, preis 89.9
  • Ausgang: listPrice
  • Änderungen: keine
  • Eingabe: itemNumber TON-410X, unitPrice 129, Ergebnis der letzten Aufgabe Approved
  • Datentabelle preisliste: 2 Zeilen
    • artikelnummer PAP-A4-80, bezeichnung Kopierpapier A4, 80 g, 500 Blatt, preis 4.95
    • artikelnummer TON-305A, bezeichnung Toner 305A schwarz, preis 89.9
  • Ausgang: deviation
  • Änderungen: Hinweis an der nächsten Aufgabe: „Der Artikel TON-410X steht nicht in der Preisliste.“