Prepare booking fields
The workflow adds the fields booking text and G/L account and fills them as soon as an invoice arrives: the booking text from the vendor and the invoice number in at most 60 characters, as DATEV takes it, and the G/L account from a table in the script. A vendor name that is too long is cut at a word boundary, so the invoice number stays complete. The fields are on the document for accounting; the DATEV export forms its own booking text from the vendor and the invoice number and doesn’t read these fields.
The workflow
Section titled “The workflow”The workflow starts for every document of the type incoming-invoice. Its file workflow.yaml:
$schema: 'https://docs.acriva.de/schemas/workflow.schema.json'format: 1schemaVersion: 4sdk: '1.0.0'key: datev-fieldsname: Buchungsfelder vorbereitentemplate: customtrigger: documentType: incoming-invoicefields: - key: bookingText kind: text labelDe: Buchungstext labelEn: Booking text documentTypes: - incoming-invoice - key: glAccount kind: text labelDe: Sachkonto labelEn: G/L account documentTypes: - incoming-invoicestart: preparesteps: - kind: script name: prepare label: DATEV-Felder vorbereiten script: prepare.ts hook: onDocumentArrived inputs: - kind: field key: vendorName type: text - kind: field key: invoiceNumber type: text 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: rejectedThe script prepare.ts
Section titled “The script prepare.ts”Hook: onDocumentArrived · Inputs: vendorName, invoiceNumber · Return values: none
import { defineScript } from '@acriva/workflow-sdk';
/** DATEV takes at most 60 characters as the booking text. */const MAX_BOOKING_TEXT = 60;
/** The G/L account (SKR03) per vendor; a vendor matches when its name starts with the entry's name. */const GL_ACCOUNTS: readonly { vendor: string; glAccount: string }[] = [ { vendor: 'Telekom', glAccount: '4920' }, { vendor: 'Deutsche Bahn', glAccount: '4663' }, { vendor: 'Bürobedarf', glAccount: '4930' },];
/** * The vendor and the invoice number in at most 60 characters. A vendor that is too long is cut at a word boundary, so the * invoice number always stays complete. */function bookingText(vendor: string, invoiceNumber: string | null): string { const suffix = invoiceNumber == null ? '' : ` ${invoiceNumber}`; const full = `${vendor}${suffix}`; if (full.length <= MAX_BOOKING_TEXT) return full; const room = MAX_BOOKING_TEXT - suffix.length; if (room <= 0) return suffix.trim().slice(0, MAX_BOOKING_TEXT); // Keep one character more, so a word that ends exactly at the limit stays whole. const head = vendor.slice(0, room + 1); const space = head.lastIndexOf(' '); const shortVendor = (space > 0 ? head.slice(0, space) : vendor.slice(0, room)).trimEnd(); return `${shortVendor}${suffix}`;}
export default defineScript({ hook: 'onDocumentArrived', run(ctx) { const { vendorName, invoiceNumber } = ctx.document.fields; if (vendorName == null) return; ctx.setField('bookingText', bookingText(vendorName.trim(), invoiceNumber?.trim() || null));
const match = GL_ACCOUNTS.find((entry) => vendorName.toLowerCase().startsWith(entry.vendor.toLowerCase()), ); if (match) { ctx.setField('glAccount', match.glAccount); } else { ctx.hint( 'Für diesen Lieferanten ist kein Sachkonto hinterlegt. Bitte ergänzen Sie es von Hand.', ); } },});What it does
Section titled “What it does”A test runs each of these cases in the sandbox and compares the result.
A known vendor
Section titled “A known vendor”- Input:
vendorNameTelekom Deutschland GmbH,invoiceNumber4711-2026-10 - Exit: the default next step
- Changes: field
bookingText=Telekom Deutschland GmbH 4711-2026-10; fieldglAccount=4920
A long vendor name
Section titled “A long vendor name”- Input:
vendorNameGebäudereinigung Sauber & Glanz Facility Services Deutschland GmbH,invoiceNumberRE-2026-0815 - Exit: the default next step
- Changes: field
bookingText=Gebäudereinigung Sauber & Glanz Facility RE-2026-0815; hint on the next task: “Für diesen Lieferanten ist kein Sachkonto hinterlegt. Bitte ergänzen Sie es von Hand.”
An invoice without a vendor
Section titled “An invoice without a vendor”- Input:
vendorNamenull,invoiceNumberRE-2026-0815 - Exit: the default next step
- Changes: none