Workflow starten

Dieser Leitfaden zeigt, wie ein enaio-Workflow über die API gestartet wird, inklusive Eingangsvariablen und einer angehängten Datei. Als durchgängiges Beispiel dient der mitgelieferte Standard-Ad-hoc-Workflow.

Der Ablauf in vier Schritten:

  1. Workflow, Client-Typ und Workflow-Benutzer ermitteln (Discovery).

  2. Eingangsvariablen des Workflows bestimmen.

  3. Ein Dokument mit Datei im DMS anlegen.

  4. Den Workflow starten und dabei Variablen und Dokument mitgeben.

Eine Datei wird nicht direkt beim Start hochgeladen. Stattdessen wird das Dokument (mit seiner Datei) zuerst im DMS angelegt und dann über seine Objekt-ID als ECMWorkspaceDocument referenziert. Der Server legt es in den Workspace der Workflow-Akte.

1. Verbindung

from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import SyncPoolClient

ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="<user>", password="<pass>"))

Async (AsyncPoolClient) funktioniert analog mit await vor den Aufrufen.

2. Schritt 1: Discovery

start_process benötigt drei Identifikatoren: den Workflow-Benutzer (Workflow-Organisations-GUID, nicht der Security-User), einen Client-Typ und den Workflow.

# Workflow-Benutzer aus einem Login-Namen aufloesen
user = ecm.workflow.organisation_user_by_login("root")

# Verfuegbare Client-Typen (der Name genuegt fuer die folgenden Aufrufe)
client_type = "#OSECM_Client#"   # siehe ecm.workflow.client_types()

# Startbare Workflows fuer diesen Benutzer und Client-Typ
workflows = ecm.workflow.workflow_list(user, client_type)
adhoc = next(wf for wf in workflows if wf.name == "Standard-Ad-hoc-Workflow")

Den Workflow über seinen stabilen Anzeigenamen (wf.name) zu suchen ist robuster als über den model_name, der eine Versionsnummer enthält (z. B. "Ad-hoc Version 3.0.5"). start_process akzeptiert das ECMWorkflow-Objekt direkt, ebenso eine Family-GUID oder einen Modellnamen.

3. Schritt 2: Eingangsvariablen bestimmen

Welche Variablen beim Start gesetzt werden dürfen, legt die Workflow-Definition fest (Flag „Eingangsvariable"). workflow_model_by_name() liefert ein typisiertes Modell, dessen Felder genau diese Eingangsvariablen sind.

Variables = ecm.workflow.workflow_model_by_name(adhoc.model_name, user, client_type)
# Felder von Variables = die Eingangsvariablen des Workflows

Der Standard-Ad-hoc-Workflow hat fünf Eingangsvariablen: sAntragsteller, lLaufliste, sSubject (jeweils IN) sowie sBemHist und lAbstimmungsergebnis (jeweils INOUT). Reine Ausgabevariablen (OUT, z. B. iFreigabe) und interne Prozessvariablen, die der Workflow selbst befüllt, sind nicht zum Setzen beim Start vorgesehen. Mit include_internal=True lassen sich auch die internen Variablen zur Inspektion anzeigen.

Maßgeblich ist die Schnittstelle des Workflow-Prozesses: Eine Variable ist beim Start setzbar, wenn sie dort als IN- oder INOUT-Parameter geführt wird.

4. Schritt 3 (optional): Typisierte Modelle generieren

Für volle IDE-Unterstützung und Typprüfung können die Modelle als .py-Dateien generiert werden, statt sie zur Laufzeit aufzulösen.

# Dokument-Modelle des Schranks
ecm-generate-models \
    --host enaio.example.com --username <user> --password <pass> \
    --cabinet <Schrank> --output-dir ./models

# Workflow-Variablen-Modell
ecm-generate-workflow-models \
    --host enaio.example.com --username <user> --password <pass> \
    --client-type "#OSECM_Client#" \
    --workflow "Ad-hoc Version 3.0.5" --output-dir ./wf_models

Das erzeugte Workflow-Modell listet die Eingangsvariablen explizit als Klassenattribute:

# wf_models/... (DO NOT EDIT - neu generieren)
from ecmind_blue_client.ecm import ECMWorkflowModel, ECMWorkflowRecordModel


class LAbstimmungsergebnisRecord(ECMWorkflowRecordModel):
    """Generated record model."""

    Kategorie: str | None = None
    Anzahl: int | None = None


class LLauflisteRecord(ECMWorkflowRecordModel):
    """Generated record model."""

    AktivitaetId: str | None = None


class Standard_Ad_hoc_WorkflowModel(ECMWorkflowModel):
    """Input variables for the 'Ad-hoc Version 3.0.5' workflow."""

    sBemHist: str | None = None
    sAntragsteller: str | None = None
    sSubject: str | None = None
    lAbstimmungsergebnis: list[LAbstimmungsergebnisRecord] | None = None
    lLaufliste: list[LLauflisteRecord] | None = None

Der Klassenname wird aus dem stabilen Anzeigenamen des Workflows abgeleitet (Standard_Ad_hoc_WorkflowModel), nicht aus dem versionierten Modellnamen. Er bleibt damit über Workflow-Versionen hinweg gleich; die Version steht nur im Docstring. Listen-von-Record-Variablen (lAbstimmungsergebnis, lLaufliste) werden als list[…​Record] mit typisierten Membern erzeugt.

5. Schritt 4: Dokument mit Datei anlegen

Das Dokument wird mit seiner Datei im DMS angelegt; insert() gibt die Objekt-ID und die Objekttyp-ID zurück.

from ecmind_blue_client.ecm.model import make_document_model
from ecmind_blue_client.rpc import JobRequestFileFromBytes

# TODO: Dokumenttyp und Ablageort an den Ziel-Schrank anpassen
Document = make_document_model("Dokument")
object_id, object_type_id = ecm.dms.insert(
    Document(),
    files=[JobRequestFileFromBytes(b"Beispielinhalt der Datei.\n", "txt")],
    folder_id=42,
)

6. Schritt 5: Workflow starten

from ecmind_blue_client.ecm import ECMWorkspaceDocument

process_id = ecm.workflow.start_process(
    user=user,
    workflow=adhoc,                  # ECMWorkflow-Objekt aus Schritt 1
    client_type=client_type,
    variables={
        "sAntragsteller": "ROOT",                              # IN
        "sSubject": "Freigabe Angebot 2026-001",               # IN
        "sBemHist": "Ad-hoc-Start per API mit angehaengtem Dokument.",  # INOUT
    },
    documents=[ECMWorkspaceDocument(id=object_id, type=object_type_id)],
)
print(f"Workflow gestartet, ProcessId: {process_id}")

variables akzeptiert ein einfaches Mapping (String-Werte werden als String gesendet, der Server konvertiert) oder eine typisierte Modellinstanz aus Schritt 3. Das typisierte Modell ist bei Datum, Zeit, Listen und Records vorzuziehen, da es die korrekte Serialisierung übernimmt.

7. Vollständiges Beispiel

from ecmind_blue_client.ecm import ECM, ECMWorkspaceDocument
from ecmind_blue_client.ecm.model import make_document_model
from ecmind_blue_client.pool import SyncPoolClient
from ecmind_blue_client.rpc import JobRequestFileFromBytes

CLIENT_TYPE = "#OSECM_Client#"
ADHOC_NAME = "Standard-Ad-hoc-Workflow"   # stabiler Anzeigename

ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="<user>", password="<pass>"))

# 1. Discovery
user = ecm.workflow.organisation_user_by_login("root")
adhoc = next(wf for wf in ecm.workflow.workflow_list(user, CLIENT_TYPE) if wf.name == ADHOC_NAME)

# 2. Dokument mit Datei anlegen (TODO: Dokumenttyp und Ablage anpassen)
Document = make_document_model("Dokument")
object_id, object_type_id = ecm.dms.insert(
    Document(),
    files=[JobRequestFileFromBytes(b"Beispielinhalt der Datei.\n", "txt")],
    folder_id=42,
)

# 3. Workflow starten: Parameter + Dokument im Workspace
process_id = ecm.workflow.start_process(
    user=user,
    workflow=adhoc,
    client_type=CLIENT_TYPE,
    variables={
        "sAntragsteller": "ROOT",                              # IN
        "sSubject": "Freigabe Angebot 2026-001",               # IN
        "sBemHist": "Ad-hoc-Start per API mit angehaengtem Dokument.",  # INOUT
    },
    documents=[ECMWorkspaceDocument(id=object_id, type=object_type_id)],
)
print(f"Workflow gestartet, ProcessId: {process_id}")

8. Verwandte Themen