Zum Inhalt springen

Kostenstelle und Kreditorenkonto aus dem ERP

Ihr ERP kennt zu jedem Lieferanten die Kostenstelle und das Kreditorenkonto. Das Skript fragt es über die Datenquelle erp nach dem Lieferanten der Rechnung und setzt beide Felder, die der Workflow selbst deklariert. Kennt das ERP den Lieferanten nicht (Status 404) oder antwortet es nicht, hängt das Skript einen Hinweis an die Freigabe, damit die Rechnung von Hand kontiert wird; ein gescheiterter Aufruf beendet den Lauf nicht.

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: erp-cost-center
name: Kostenstelle und Kreditorenkonto aus dem ERP
template: custom
trigger:
documentType: incoming-invoice
fields:
- key: costCenter
kind: text
labelDe: Kostenstelle
labelEn: Cost center
documentTypes:
- incoming-invoice
- key: creditorAccount
kind: text
labelDe: Kreditorenkonto
labelEn: Creditor account
documentTypes:
- incoming-invoice
start: allocate
steps:
- kind: script
name: allocate
label: Kontierung aus dem ERP
script: allocate.ts
hook: onDocumentArrived
inputs:
- kind: field
key: vendorName
type: text
- kind: source
key: erp
returns: []
exits: []
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: rejected

Hook: onDocumentArrived · Eingaben: vendorName, Datenquelle erp · Rückgaben: keine

import { defineScript } from '@acriva/workflow-sdk';
/** What the ERP answers to `GET lieferanten?name=…`: the vendor's cost center and its creditor account. */
interface ErpVendor {
kostenstelle: string;
kreditorenkonto: string;
}
/** A source's answer is JSON of any shape until the script has checked it. */
const isErpVendor = (data: unknown): data is ErpVendor =>
typeof data === 'object' &&
data !== null &&
typeof (data as ErpVendor).kostenstelle === 'string' &&
typeof (data as ErpVendor).kreditorenkonto === 'string';
export default defineScript({
hook: 'onDocumentArrived',
async run(ctx) {
const vendor = ctx.document.fields.vendorName;
if (vendor == null) return;
const result = await ctx.sources.get('erp', { path: 'lieferanten', query: { name: vendor } });
// A failed call is a result, not an exception: the invoice is then allocated by hand.
if (!result.ok) {
ctx.hint(
result.status === 404
? `„${vendor}“ ist im ERP nicht angelegt. Bitte kontieren Sie die Rechnung von Hand.`
: `Das ERP hat nicht geantwortet (${result.error}). Bitte kontieren Sie die Rechnung von Hand.`,
);
return;
}
if (!isErpVendor(result.data)) {
ctx.hint(
'Das ERP hat keine Kostenstelle geliefert. Bitte kontieren Sie die Rechnung von Hand.',
);
return;
}
ctx.setField('costCenter', result.data.kostenstelle);
ctx.setField('creditorAccount', result.data.kreditorenkonto);
},
});

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

  • Eingabe: vendorName Bürobedarf Schmidt KG
  • Datenquelle erp: keine Daten: timeout
  • Ausgang: der Standard-Nachfolger
  • Änderungen: Hinweis an der nächsten Aufgabe: „Das ERP hat nicht geantwortet (timeout). Bitte kontieren Sie die Rechnung von Hand.“
  • Eingabe: vendorName Telekom Deutschland GmbH
  • Datenquelle erp: antwortet {"kostenstelle":"4400","kreditorenkonto":"70012"}
  • Ausgang: der Standard-Nachfolger
  • Änderungen: Feld costCenter = 4400; Feld creditorAccount = 70012
  • Eingabe: vendorName Neue Firma AG
  • Datenquelle erp: keine Daten: http-error (Status 404)
  • Ausgang: der Standard-Nachfolger
  • Änderungen: Hinweis an der nächsten Aufgabe: „„Neue Firma AG“ ist im ERP nicht angelegt. Bitte kontieren Sie die Rechnung von Hand.“