Skip to content

Check the project budget

Invoices of a project are in its file of the file type project. You keep each project’s budget and the amount spent so far in a data table projekte with the project number as its key column, as the files are numbered; your controlling can update the amount spent regularly by an upload or through the API. The script looks up the invoice’s project in the table: when the invoice fits into the remaining budget, it goes to the normal approval with the budget left as a hint; when it exceeds it, the management approves. An invoice without a project file goes to the normal approval without a check.

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: 1
schemaVersion: 4
sdk: '1.0.0'
key: project-budget
name: Projektbudget prüfen
template: custom
trigger:
documentType: incoming-invoice
fields: []
start: budget
steps:
- kind: script
name: budget
label: Projektbudget prüfen
script: budget.ts
hook: onDocumentArrived
inputs:
- kind: field
key: totalGross
type: money
- kind: table
key: projekte
returns:
- key: budget
type: enumeration
values:
- within
- exceeded
branch: budget
exits:
- value: within
next: approve
- value: exceeded
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: onDocumentArrived · Inputs: totalGross, data table projekte · Return values: budget (within, exceeded)

import { defineScript, money } from '@acriva/workflow-sdk';
export default defineScript({
hook: 'onDocumentArrived',
outputs: { budget: ['within', 'exceeded'] },
async run(ctx) {
// An invoice outside a project's Akte goes on to its default next step, the normal approval.
const project = ctx.document.files.find((file) => file.type === 'project');
if (!project) return;
const row = await ctx.tables.lookup('projekte', project.number);
if (row === null || row.budget === null) {
ctx.hint(
`Das Projekt ${project.number} steht nicht in der Projektliste; sein Budget ist nicht geprüft.`,
);
return;
}
const name = row.bezeichnung ?? project.number;
const left = money.round(row.budget - (row.verbraucht ?? 0));
const total = ctx.document.fields.totalGross ?? 0;
if (total > left) {
ctx.hint(
`Die Rechnung über ${money.format(total)} übersteigt das Restbudget des Projekts ${name} von ${money.format(left)}.`,
);
return ctx.branch('exceeded');
}
ctx.hint(
`Projekt ${name}: Nach dieser Rechnung bleiben ${money.format(money.round(left - total))} vom Budget.`,
);
return ctx.branch('within');
},
});

A test runs each of these cases in the sandbox and compares the result.

  • Input: totalGross 119
  • Exit: the default next step
  • Changes: none
  • Input: totalGross 11900
  • Data table projekte: 2 rows
    • projektnummer P-2026-014, bezeichnung Umbau Lager Nord, budget 50000, verbraucht 41250.5
    • projektnummer P-2026-021, bezeichnung Messe Hannover, budget 18000, verbraucht 2400
  • Exit: exceeded
  • Changes: hint on the next task: “Die Rechnung über 11.900,00 € übersteigt das Restbudget des Projekts Umbau Lager Nord von 8.749,50 €.”
  • Input: totalGross 595
  • Data table projekte: 2 rows
    • projektnummer P-2026-014, bezeichnung Umbau Lager Nord, budget 50000, verbraucht 41250.5
    • projektnummer P-2026-021, bezeichnung Messe Hannover, budget 18000, verbraucht 2400
  • Exit: the default next step
  • Changes: hint on the next task: “Das Projekt P-2026-099 steht nicht in der Projektliste; sein Budget ist nicht geprüft.”
  • Input: totalGross 2380
  • Data table projekte: 2 rows
    • projektnummer P-2026-014, bezeichnung Umbau Lager Nord, budget 50000, verbraucht 41250.5
    • projektnummer P-2026-021, bezeichnung Messe Hannover, budget 18000, verbraucht 2400
  • Exit: within
  • Changes: hint on the next task: “Projekt Umbau Lager Nord: Nach dieser Rechnung bleiben 6.369,50 € vom Budget.”