ecm-generate-workflow-models

ecm-generate-workflow-models ist ein Kommandozeilen-Werkzeug, das typisierte Python-Modellklassen für die Eingangsvariablen eines Workflows generiert — das statische Gegenstück zu workflow_model_by_name().

Die generierten Klassen bilden jede Eingangsvariable als typisiertes Attribut ab (Skalare auf native Python-Typen, Listen auf list[…​], Records auf eigene, vollständig typisierte Nested-Klassen). Damit stehen in der IDE Code-Completion und Typprüfung zur Verfügung, und eine Modellinstanz kann direkt an start_process() übergeben werden — sie serialisiert sich selbst in das vom Server erwartete DataFields-Format.

1. Installation

Das Kommando ist in der Hauptinstallation enthalten — kein zusätzliches Extra erforderlich:

  • uv

  • pip

uv add ecmind-blue-client
pip install ecmind-blue-client

2. Voraussetzungen

Das Tool liest die Workflows live vom Server (wfm.GetWorkflowList zum Auflisten, wfm.GetWorkflow je Workflow). Es gibt — anders als bei ecm-generate-models — keine --file-Quelle.

Zum Auflisten der startbaren Workflows verlangt der Server zwei Angaben:

  • einen Workflow-Organisations-Benutzer (nicht den Security-Login). Wird --user weggelassen, löst das Tool ihn automatisch aus dem Login-Namen (--username) über dessen Login-Attribut auf.

  • einen Client-Typ (--client-type), als GUID oder als Name wie OSECM_Client. Der Server erzwingt genau einen Client-Typ; es gibt keinen „alle Clients"-Wert.

3. Argumente

3.1. Server-Verbindung

Argument Standard Beschreibung

--host HOST

Hostname oder IP-Adresse des enaio-Servers. Erforderlich.

--port PORT

4000

TCP-Port des enaio-Servers.

--username USER

$ECM_USERNAME

Benutzername für die Anmeldung. Ohne Angabe aus der Umgebungsvariable ECM_USERNAME.

--password PASS

$ECM_PASSWORD

Passwort für die Anmeldung. Ohne Angabe aus der Umgebungsvariable ECM_PASSWORD.

--no-ssl

SSL aktiv

SSL/TLS deaktivieren. Standard: SSL ist aktiviert.

--name APPNAME

Anwendungsname, der im Enterprise Manager angezeigt wird (optional).

3.2. Workflow-Auswahl

Argument Standard Beschreibung

--user ORG_USER_GUID

aus --username

Workflow-Organisations-Benutzer-GUID, dessen startbare Workflows gelesen werden. Ohne Angabe wird sie aus dem Login-Namen (--username) über das Login-Attribut aufgelöst. Ein expliziter --user hat Vorrang.

--client-type CLIENT_TYPE

Client-Typ als GUID oder Name (z. B. OSECM_Client). Serverseitig erforderlich.

--organisation ORG

aktive Org

Organisations-GUID. Standard: die aktive Organisation.

--workflow MODEL_NAME

alle

Nur den Workflow mit diesem Modellnamen generieren.

3.3. Ausgabe

Argument Standard Beschreibung

--output-dir DIR

stdout

Verzeichnis, in das die generierten .py-Dateien geschrieben werden — eine Datei je Workflow. Ohne Angabe wird der Code auf der Standardausgabe ausgegeben.

4. Beispiele

4.1. Alle startbaren Workflows generieren

Der häufigste Anwendungsfall — --user wird aus --username aufgelöst:

ecm-generate-workflow-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --client-type "#OSECM_Client#" \
    --output-dir ./wf_models

Ausgabe im Terminal:

wrote wf_models/test.py

4.2. Credentials aus der Umgebung

export ECM_USERNAME=admin ECM_PASSWORD=secret
ecm-generate-workflow-models \
    --host enaio.example.com \
    --client-type "#OSECM_Client#" \
    --output-dir ./wf_models

4.3. Nur einen Workflow, Vorschau auf der Konsole

ecm-generate-workflow-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --client-type "#OSECM_Client#" \
    --workflow test

4.4. Expliziter Org-Benutzer

Hat Vorrang vor der Login-Auflösung:

ecm-generate-workflow-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --user 46E29564BC464929A0A2ECA5387B4855 \
    --client-type "#OSECM_Client#" \
    --output-dir ./wf_models

5. Ausgabeformat

Pro Workflow wird eine .py-Datei geschrieben. Sie definiert eine ECMWorkflowModel-Subklasse mit den Eingangsvariablen als typisierte Attribute. Record-Variablen werden als eigene, vollständig typisierte ECMWorkflowRecordModel-Subklassen generiert (rekursiv, inkl. Record-in-Record und Listen von Records).

Beispiel einer generierten Datei:

# DO NOT EDIT — regenerate with generate_workflow_models.py (ecm-generate-workflow-models).

"""Generated typed workflow-variable model."""

from __future__ import annotations

from datetime import date, datetime, time

from ecmind_blue_client.ecm import ECMWorkflowModel, ECMWorkflowRecordModel  # base classes for typed access


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

    StringField: str | None = None
    IntegerField: int | None = None
    TimeField: time | None = None
    DateTimeField: datetime | None = None
    FloatField: float | None = None
    StringListField: list[str] | None = None


class TestWorkflowModel(ECMWorkflowModel):
    """Input variables for the 'test' workflow."""

    test: str | None = None
    StringVar: str | None = None
    DateVar: date | None = None
    DatetimeVar: datetime | None = None
    StringListVar: list[str] | None = None
    FloatVar: float | None = None
    IntegerVar: int | None = None
    TimeVar: time | None = None
    TestRecordVar: TestRecordVarRecord | None = None

5.1. Typ-Mapping

Server-Typ Python-Typ

STRING

str

INTEGER_SAFE

int

FLOAT_SAFE

float

DATE_SAFE

date

DATETIME_SAFE

datetime

TIME_SAFE

time

ListType

list[…]

RecordType

typisierte ECMWorkflowRecordModel-Nested-Klasse

Standardmäßig werden nur die Eingangsvariablen (INOUT) abgebildet; interne Felder werden ausgeblendet.

6. Mit generierten Modellen einen Workflow starten

Die generierte Datei wird importiert und die Modellinstanz an start_process() als variables übergeben. Das Modell serialisiert die typisierten Werte selbst in das DataFields-Format (Skalare als <String>, Datetime als Unix-Epoch, Listen/Records im Server-Format).

  • Sync

  • Async

import datetime

from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import SyncPoolClient
from wf_models.test import TestWorkflowModel, TestRecordVarRecord

ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="admin", password="secret"))

# Workflow-Organisations-Benutzer aus dem Login auflösen
user = ecm.workflow.organisation_user_by_login("admin")

# Record-Variable typsicher befüllen
record = TestRecordVarRecord(
    StringField="x",
    IntegerField=1,
    TimeField="08:00:00",
    DateTimeField="1779365400",   # Datetime-Member: Unix-Epoch
    FloatField="2.5",
    StringListField=["inner"],
)

# Modellinstanz mit allen typisierten Variablen
variables = TestWorkflowModel(
    StringVar="Hallo",
    IntegerVar=42,
    FloatVar=3.14,
    DateVar=datetime.date(2026, 6, 11),
    DatetimeVar=datetime.datetime(2026, 6, 11, 10, 30, 0),   # wird als Unix-Epoch serialisiert
    TimeVar=datetime.time(10, 30, 0),
    StringListVar=["a", "b"],
    TestRecordVar=record,
)

# Starten (organisation defaultet auf die aktive Organisation)
process_id = ecm.workflow.start_process(
    user=user,
    workflow="test",
    client_type="#OSECM_Client#",
    variables=variables,
)
print("gestarteter Prozess:", process_id)
import datetime

from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import AsyncPoolClient
from wf_models.test import TestWorkflowModel, TestRecordVarRecord

ecm = ECM(AsyncPoolClient(servers="enaio.example.com:4000:1", username="admin", password="secret"))

user = await ecm.workflow.organisation_user_by_login("admin")

record = TestRecordVarRecord(
    StringField="x", IntegerField=1, TimeField="08:00:00",
    DateTimeField="1779365400", FloatField="2.5", StringListField=["inner"],
)

variables = TestWorkflowModel(
    StringVar="Hallo",
    IntegerVar=42,
    DatetimeVar=datetime.datetime(2026, 6, 11, 10, 30, 0),
    StringListVar=["a", "b"],
    TestRecordVar=record,
)

process_id = await ecm.workflow.start_process(
    user=user,
    workflow="test",
    client_type="#OSECM_Client#",
    variables=variables,
)
print("gestarteter Prozess:", process_id)

6.1. Dateien an den Workflow anhängen

Dokumente werden über den documents-Parameter angehängt. wfm.StartProcess referenziert bereits in enaio archivierte Dokumente per id/type und legt sie in den Workspace der Workflow-Akte — es lädt keine neuen Dateien hoch. Erst das DMS-Dokument anlegen, dann dessen id/type übergeben:

from ecmind_blue_client.ecm import ECMWorkspaceDocument
from ecmind_blue_client.rpc._job_request_file import JobRequestFileFromPath

# 1) DMS-Dokument mit Datei anlegen (oder ein vorhandenes verwenden)
doc = ecm.dms.insert_and_get(
    MyDocumentModel(Name="Vertrag"),
    files=[JobRequestFileFromPath("vertrag.pdf")],
    folder_id=folder_id,
    register_id=register_id,
)

# 2) dessen id/type beim Start mitgeben
process_id = ecm.workflow.start_process(
    user=user,
    workflow="test",
    client_type="#OSECM_Client#",
    variables=variables,
    documents=[ECMWorkspaceDocument(id=doc.system.id, type=doc.system.type_id)],
)

7. Ohne Generierung: Laufzeit-Modelle

Ist statisches Typing nicht erforderlich, kann das Modell auch ohne Generierung zur Laufzeit erzeugt werden — workflow_model_by_name() liefert dieselbe Klasse:

Model = ecm.workflow.workflow_model_by_name("test", user, "#OSECM_Client#")
record = Model.record_model("TestRecordVar")(StringField="x", IntegerField=1, ...)
variables = Model(StringVar="Hallo", IntegerVar=42, TestRecordVar=record)

ecm.workflow.start_process(user=user, workflow="test",
                           client_type="#OSECM_Client#", variables=variables)

8. Wann neu generieren?

Die generierten Dateien sollten neu erstellt werden, wenn:

  • Eingangsvariablen eines Workflows hinzugefügt, entfernt oder umtypisiert wurden

  • Record-Strukturen geändert wurden

Die Dateien tragen den Kommentar DO NOT EDIT — manuelle Änderungen gehen beim nächsten Generieren verloren.

9. Siehe auch