Die System-Skriptsprache wird u. a. im Workflow-Management verwendet, um beispielsweise eine Vorbedingung oder Übergangsbedingung zu formulieren oder um Bearbeiter zu ermitteln, die nicht in einer Workflowrolle zusammengefasst sind.
Die Workflow-Engine unterstützt sowohl die eigene System-Skriptsprache als auch JavaScript, um komplexe Zusammenhänge auszudrücken. Dieses Dokument behandelt nur die System-Skriptsprache. Es ist in folgende Kapitel aufgeteilt:
- Aufbau und Syntax
- Deklarationen
- Informationsauswertung
- Fehlerbehandlung
- Erweiterung der System-Skriptsprache
Die Einführung in die System-Skriptsprache ist auf mehrere Dokumente aufgeteilt. In diesem Dokument erhalten Sie ausführliche Informationen zum Aufbau und der Syntax der System-Skriptsprache. Für weitere Informationen zu den einzelnen Funktionen und Befehlen lesen Sie folgende Dokumentationen:
- System-Skriptsprache: Allgemeine Funktionen
- System-Skriptsprache: OLTP-Funktionen
- System-Skriptsprache: Workflow-Funktionen
Informationen zu der Workflow-Engine erhalten Sie in der gleichnamigen Dokumentation Workflow-Engine. Informationen zur Verwendung der System-Skriptsprache in Workflow-Definitionen erhalten Sie in den Dokumentationen Aktivitätsdefinitionen und Prozessdefinitionen.
Darüber hinaus kann die System-Skriptsprache u. a. in den folgenden Anwendungen verwendet werden:
- Individuelle Prüfungen
- Individuelle Hook-Implementierungen
Weitere Informationen entnehmen Sie den jeweiligen Dokumentationen.
Zielgruppe
Die Zielgruppe dieses Dokuments besteht aus Entwicklern und technischen Beratern, die Workflows bei Kunden erstellen oder anpassen, sowie Kunden, die eigene Workflows verwalten.
Für dieses Dokument wird das Verständnis des für den Benutzer sichtbaren Funktionsumfangs des Workflow-Managements vorausgesetzt. Weiterhin sollte der Leser zum Verständnis der System-Skriptsprache grundlegende Kenntnisse in SQL oder einer beliebigen Programmiersprache haben.
Begriffsbestimmung
- Aktivitätsdefinition – Aktivitätsdefinitionen legen fest, ob beim Auftreten eines bestimmten Ereignisses eine Aktivität erzeugt werden soll und welche Merkmale diese Aktivität haben soll. Eine Aktivitätsdefinition muss aktiviert sein. Wenn das der Fall ist, dann erzeugt die Workflow-Engine beim Auftreten des dort angegebenen Ereignisses eine neue Aktivität, sofern die Übergangs- und Vorbedingung erfüllt sind. Alle für die Aktivität notwendigen Daten werden aus der Aktivitätsdefinition berechnet. Die Aktivitätsdefinition stellt somit die Vorlage für die aus ihr erzeugten Aktivitäten dar. Aktivitätsdefinitionen sind unabhängig von der OLTP-Datenbank und dem System, in dem sie erfasst wurden, da sie weder System- noch OLTP-spezifische Daten enthalten. Aktivitätsdefinitionen werden in der Repository-Datenbank abgelegt.
- Deklarationen – Deklarationen sind Skripte in den Prozessdefinitionen und Aktivitätsdefinitionen, die Methoden zur Verfügung stellen, welche beim Erzeugen von Aktivitäten, bei Statuswechseln und bei der Eingabe von bestimmten Parameterwerten aufgerufen werden. Durch Anpassung der Deklarationen lassen sich die Eigenschaften von Prozessen und Aktivitäten flexibel festlegen. Deklarationen werden in einer Skriptsprache erfasst.
- GUID – GUID ist die Abkürzung für Globally Unique Identifier und entspricht einem Global eindeutigen Bezeichner. Eine GUID ist eine 128-Bit Zahl, die nach dem Schema der Open Software Foundation (OSF) für verteilte Berechnungen (Distributed Computing Environment, DCE) berechnet wurde. Sie enthält u. a. die IP-Adresse der erzeugenden Rechner, eine Zeit-Komponente und eine Zufalls-Komponente. So können zwei unabhängige Rechner ohne Synchonisation immer unterschiedliche GUIDs berechnen. In Comarch ERP Enterprise werden GUIDs als Java-Byte-Arrays der Länge 16 repräsentiert und vor allem als kompakte Primär- und Fremdschlüssel in Business Objects verwendet.
- Hook Contract – Ein Hook ist eine Schnittstelle, mit der vorhandener Programmcode unabhängig von einem Release und damit konfliktfrei erweitert werden kann. Hooks werden beispielsweise verwendet, wenn in einer Adaptierung oder einer App für eine Business-Object-Erweiterung zusätzliche Prüfungen durchgeführt werden müssen, die die vorhandenen Prüfungen ergänzen.
- Hook-Contract-Implementierung – In der Hook-Contract-Implementierung werden die zu implementierenden Hooks und die jeweilige Implementierungsklasse angegeben. Die Hook-Contract-Implementierung bezieht sich immer auf eine Hook-Contract-Definition, in der die implementierbaren Hooks enthalten sind.
- Individuelle Prüfung – Bestimmte Business Entitys bieten Hook-Contracts für die Prüfung an, die mithilfe der System-Skriptsprache und ohne Zugang zu einem Entwicklungssystem implementiert werden können. Diese erweiterten Prüfungen werden in allen Ein- und Ausgabekanälen verwendet, also sowohl in den Dialog-Anwendungen als auch beim Import oder Export.
- System-Skriptsprache – Terme, Bedingungen, Befehle und Deklarationen werden verwendet, um komplexe Zusammenhänge auszudrücken. Alle diese Ausdrücke sind Teil einer gemeinsamen Skriptsprache, die System-Skriptsprache genannt wird. Die Syntax der System-Skriptsprache lehnt sich an SQL, Pascal und Java an. Die System-Skriptsprache wird im Workflow-Management verwendet, um z. B. eine Vorbedingung oder Übergangsbedingung zu formulieren oder um Bearbeiter zu ermitteln, die nicht in einer Workflowrolle zusammengefasst sind.
- Workflow-Engine – Zusammen mit dem Ereignisdienst koordiniert und überwacht die Workflow-Engine die Ausführung von Workflows. Die Workflow-Engine wird in jedem System auf dem Message-Server ausgeführt.
Aufbau und Syntax
Terme, Bedingungen, Befehle, Funktionen und Deklarationen werden verwendet, um komplexe Zusammenhänge auszudrücken. Alle diese Ausdrücke sind Teil einer gemeinsamen Skriptsprache, die System-Skriptsprache genannt wird. Die Syntax der System-Skriptsprache lehnt sich an SQL, Pascal und Java an.
Da im Allgemeinen keine komplexen Algorithmen mit dieser Sprache ausgedrückt werden müssen, sollten Vorkenntnisse in SQL zum Erlernen der Sprache ausreichend sein.
Die System-Skriptsprache umfasst folgende Elemente:
Datentypen
Der Datentyp definiert gültige Wertebereiche und erlaubte Operationen. Die System-Skriptsprache kennt sowohl einfache als auch komplexe Datentypen. Beispiele von einfachen Datentypen sind Zeichenketten und Zahlen. Zu den komplexen Datentypen gehören z. B. Listen, Business Objects und Objektsichten.
Alle Datentypen in der System-Skriptsprache besitzen einen Standardwert (Default). Der Standardwert wird immer dann verwendet, wenn ein neuer, noch undefinierter Wert dieses Datentyps benötigt wird. Beim Parsen (Auswerten) eines Ausdrucks in der System-Skriptsprache werden die Verwendungen der Datentypen als Argumente von Funktionen, Befehlen und Operatoren überprüft. Stimmt ein übergebener Wert nicht mit dem erwarteten Datentyp überein, wird eine Fehlermeldung ausgegeben.
Die System-Skriptsprache kennt die folgenden Datentypen:
- Boolean – Wahrheitswerte (Boolean
Boolean
) können nur die Wertetruetrue
für wahr undfalsefalse
für falsch annehmen. Der Standardwert des Datentyps Boolean istfalsefalse
. - Bytes – Der Datentyp Bytes
Bytes
sind binäre Daten mit beliebigem Inhalt. Dieser Datentyp kann insbesondere bei programmierten Ereignissen und Dateien als Parameter verwendet werden. Der Standardwert des Datentyps Bytes istnullnull
. - Class – Eine Klasse (Class
Class
) ist ein strukturierter Datentyp mit einer Menge von Attributen. Jedes Attribut hat einen Namen und einen Datentyp. Der Standardwert einer Klasse istnullnull
. - CisDate – Ein CisDate
CisDate
ist die Kombination eines Zeitpunkts mit einer Zeitzone. Der Standardwert des DatentypsCisDateCisDate
istnullnull
. - CisObjectReference – Business Objects werden mit den Datentypen CisObject
CisObject
oderCisObjectReferenceCisObjectReference
verwaltet, Parts mit dem DatentypCisObjectCisObject
. Referenzen auf Business Objects enthalten den Schlüssel des Business Objects. Der Standardwert des DatentypsCisObjectReferenceCisObjectReference
istnullnull
. Um eine typisierteCisObjectReferenceCisObjectReference
zu erhalten, geben Sie den Namen eines Business Objects in Klammern an. Wenn Sie keinen Namen angeben, erhalten Sie eine untypisierteCisObjectReferenceCisObjectReference
.HinweisUm Skripte performant auszuwerten und unnötige Datenbankzugriffe zu vermeiden, sind auch alsCisObjectReferenceCisObjectReference
deklarierte Variablen nur als Werte verfügbar, wie beim DatentypCisObjectCisObject
. Möchten Sie den aktuellen Wert eines Business Object auswerten, dann sollten Sie es erneut öffnen, z. B. mithilfe der FunktionengetByPrimaryKeygetByPrimaryKey
odergetByBusinessKeygetByBusinessKey
. - CisObject – Business Objects werden mit den Datentypen CisObject
CisObject
oderCisObjectReferenceCisObjectReference
verwaltet, Parts mit dem DatentypCisObjectCisObject
. Business Objects und ihre Parts sind auch als Werte verfügbar. Der Standardwert des DatentypsCisObjectCisObject
ist null. Um ein typisiertesCisObjectCisObject
zu erhalten, geben Sie den Namen eines Business Objects in Klammern an. Wenn Sie keinen Namen angeben, erhalten Sie ein untypisiertesCisObjectCisObject
. - DataView – Objektsichten (DataView
DataView
) sind eine Sicht auf den Zustand eines komplexen Business Entitys. Objektsichten werden insbesondere in individuellen Prüfungen verwendet. Der Standardwert des DatentypsDataViewDataView
istnullnull
. Um eine typisierteDataViewDataView
zu erhalten, geben Sie den Namen einer Objektsicht in Klammern an. Wenn Sie keinen Namen angeben, erhalten Sie eine untypisierteDataViewDataView
. - Guid – GUIDs werden häufig benötigt, um Business Objects über dessen Primärschlüssel zu identifizieren. Der Standardwert des Datentyps Guid
Guid
istnullnull
. - HashMap – Eine Hash-Tabelle (HashMap
HashMap
) speichert Schlüssel-Wert-Paare. Jedem Schlüssel kann genau ein Wert zugeordnet werden. Mithilfe des Schlüssels kann der Wert immer wieder gefunden werden. Als Schlüssel sind nur Zeichenketten erlaubt. Der Standardwert des DatentypsHashMapHashMap
ist eine leere Hash-Tabelle. - Number – Zahlen (Number
Number
) enthalten immer ein Vorzeichen. Sie können Nachkommastellen haben, die mit einem Punkt zu trennen sind. Der Standardwert des DatentypsNumberNumber
ist00
. - String – Zeichenketten (String
String
) können eine beliebige Länge haben. Der Standardwert des DatentypsStringString
ist eine leere Zeichenkette. - Timestamp – Ein Zeitpunkt (Timestamp
Timestamp
) ist ein auf Millisekunden genauer Punkt in der Zeit. Alle Zeitangaben werden in Zeitpunkten abgebildet. Der Standardwert des DatentypsTimestampTimestamp
ist die KonstanteUNDEFINED_DATEUNDEFINED_DATE
. - Unknown – Dem Datentyp Unknown
Unknown
kann jeder beliebige andere Datentyp zugeordnet werden. Der Standardwert des DatentypsUnknownUnknown
istnullnull
.
Automatische Umwandlung von einfachen Datentypen
Einige einfache Datentypen wie
Number
, Boolean
und Guid
werden bei Bedarf automatisch in Zeichenketten umgewandelt. String
erwartet und ein Wert vom Typ Number
übergeben wird, so wird die Zahl in eine Zeichenkette umgewandelt.Beachten Sie bitte, dass der Datentyp vom ersten Term eines Ausdrucks bestimmt wird.
var t := "UB" + 40;
var t := 101 + "ers";
Weitere Datentypen können mithilfe der Funktion
cast
umgewandelt werden. Weitere Informationen und Beispiele finden Sie in der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Prüfungen bei typisierten CisObject und CisObjectReference
Wenn Ihnen der Typ des Business Objects oder Parts bekannt ist, sollten Sie immer ein typisiertes
CisObject
bzw. CisObjectReference
verwenden. Nur bei einer Typisierung wird die korrekte Verwendung von Attributen und deren Datentypen geprüft.
CisObject (com.cisag.app.general.obj.Partner)
ist ein Business Object vom Typ Partner.
CisObject (com.cisag.app.general.obj.DomesticAmount)
ist ein Part vom Typ Hauswährung.Bei einem untypisierten
CisObject
bzw. CisObjectReference
wird weder geprüft, ob der Attributname auch tatsächlich an dem Objekt definiert ist, noch wird geprüft, ob das Attribut tatsächlich den angeforderten Datentyp hat.
Listen
Eine Liste ist eine geordnete Folge von Werten. Eine Liste besitzt einen Elementdatentyp und optional eine Länge. Alle Listenelemente müssen in diesen Elementdatentyp umwandelbar sein. Wenn der Datentyp einer Liste eine Länge besitzt, so ist diese Länge festgelegt und kann nicht nachträglich verändert werden.
Der Datentyp Liste wird durch die Angabe eines Elementdatentyps, gefolgt von eckigen Klammern, ausgedrückt. In den eckigen Klammern steht optional die feste Länge der Liste.
String[10]
ist eine Liste von Zeichenketten mit 10 Elementen.
Number[]
ist eine Liste von Zahlen mit unbestimmt vielen Elementen.
Unknown[]
ist eine Liste mit beliebigen Objekten mit unbestimmt vielen Elementen.Der Standardwert einer Liste mit vorgegebener Länge ist eine Liste dieser Länge. Wenn die Liste keine Länge hat, so ist der Standardwert eine leere Liste. Eine leere Liste kann mithilfe der Skript-Funktion
isEmpty
geprüft werden.
isEmpty(new(String[]))
gibt den Wahrheitswert true
zurück.Die Skript-Funktion
list
erzeugt eine neue Liste mit Elementen. Der Datentyp des ersten Elements bestimmt dabei den Datentyp der Liste. Wird kein Element angegeben, dann gibt list
eine leere Liste vom Datentyp Unknown[]
zurück.
list("UB", 40)
erzeugt eine Liste vom Datentyp String[]
mit zwei Elementen von Datentyp String
.
list(101, "ers")
ist keine gültige Liste, da die Zeichenkette „ers“ nicht in den Elementdatentyp Number
umgewandelt werden kann.
list()
erzeugt eine neue leere Liste vom Datentyp Unknown[]
.Ein Element kann nur dann einer vorhandenen Liste hinzugefügt werden, wenn der Datentyp des Elements mit dem Datentyp der Liste übereinstimmt oder in diesen umgewandelt werden kann.
add
führt zu einem Fehler, da eine Zeichenkette nicht in eine Zahl umgewandelt werden kann.
var list1 := Number[]; add(list1, "500");
Ist die Liste dagegen als
String[]
deklariert, dann ist der Ausdruck add(list1, 500)
syntaktisch korrekt, da eine Zahl in eine Zeichenkette umgewandelt werden kann.Wenn Sie einer Liste Elemente unterschiedlicher Datentypen zuweisen (z. B. als Parameterliste für den Aufruf einer Hintergrundanwendung), dann sollten Sie das erste Element so wählen, dass die weiteren Elemente in den Datentyp des ersten Elements umgewandelt werden können. Beispielweise können Zahlen in Zeichenketten umgewandelt werden, aber nicht umgekehrt. Ist das nicht möglich, dann können Sie eine Liste vom Datentyp
Unknown[]
deklarieren und mithilfe der Funktion add
Elemente unterschiedlicher Datentypen zuweisen. Einer Liste, die den Datentypen Unknown[]
besitzt, können Elemente beliebiger Datentypen hinzugefügt werden, da alle anderen Datentypen in Unknown
umgewandelt werden können.
Somit lässt sich z. B. eine Parameterliste auch dann für die Funktionen
getCisObjectList
und getResultList
erzeugen, wenn die OQL-Abfrage Parameter unterschiedlicher Datentypen besitzt, die nicht automatisch (in den Datentyp des ersten Parameters) umgewandelt werden können. Das folgende Beispiel erzeugt eine Parameterliste, um mithilfe der Funktion getCisObjectList
die ersten 100 internen Personen zu ermitteln und auf der Konsole auszugeben:
const PartnerType as valueSet(com.cisag.app.general.PartnerType); function create() { var params as Unknown[]; var OQL := "SELECT FROM com.cisag.app.general.obj.Partner p" + " WHERE p:type = ? AND p:human = ?" + " ORDER BY p:number"; add(params, PartnerType.INTERNAL); add(params, true); var pList := getCisObjectList(OQL, params, BlockSize); for (p as CisObject(com.cisag.app.general.obj.Partner) : pList) echo(p:number); }
Besitzt eine Liste Elemente unterschiedlicher Datentypen, dann müssen die Elemente mithilfe der Funktion
cast
ggf. typisiert werden, bevor sie verwendet werden können, wie das folgende Beispiel zeigt.
var myList as Unknown[]; add(myList, 800); add(myList, "°"); var song := cast(String, myList[0]) + cast(String, myList[1]);
Die System-Skriptsprache umfasst viele Funktionen, um Listen zu erzeugen und zu bearbeiten. Weitere Informationen und Beispiele finden Sie im Kapitel Listenfunktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Der Wert null
Zusätzlich zu den Werten der Datentypen existiert der Wert
null
. Der Wert null
ist keinem Datentyp zugeordnet. Wenn ein Wert null
ist, so ist dieser Wert undefiniert. Viele Funktionen und Operatoren in der System-Skriptsprache liefern als Ergebnis null
, wenn einer der Parameter null
ist. Wenn also auf Basis eines undefinierten Wertes etwas berechnet werden soll, so ist auch das Ergebnis undefiniert. Mit den speziellen Funktionen isNull
und first
kann ein Wert null
gesondert behandelt werden.
Eine Übergangsbedingung in einer Aktivitätsdefinition gilt beim Wert
null
als nicht erfüllt (false
). Eine Vorbedingung dagegen gilt beim Wert null
als erfüllt (true
). Prüfen Sie daher besonders optionale Attribute mit Fremdschlüsseln auf den Wert null
. Die Übergangsbedingung
not(contains(resolvePartner(parameters.object:responsible)
, parameters.userGuid))
besitzt den undefinerten Wert null
, wenn kein zuständiger Mitarbeiter im Vertriebsauftrag hinterlegt ist. Daher wird in diesem Fall keine Aktivität erzeugt.
Die Übergangsbedingungen
isNull(parameters.object:responsible) or not(contains(resolvePartner(parameters.object:responsible)
,parameters.userGuid))
und
not(contains(resolvePartner(cast(Guid, first(parameters.object:responsible, ZERO_GUID))
,
parameters.userGuid))
besitzen auch dann einen gültigen Wert, wenn kein zuständiger Mitarbeiter im Vertriebsauftrag hinterlegt ist.Auch ein Ausdruck, der eine Beziehung über ein Attribut mit dem Wert
null
verfolgt, führt zu einem undefinierten Ergebnis.
parameters.object->Responsible:number
besitzt den undefinerten Wert null
, wenn im dem von parameters.object
referenzierten Business Object kein zuständiger Mitarbeiter hinterlegt ist.Die System-Skriptsprache umfasst zwei Funktionen
isNull
und first
, um Null-Werte zu behandeln. Weitere Informationen und Beispiele finden Sie im Kapitel Listenfunktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Feste Konstanten
Eine Konstante kann nur einen einzigen vorbestimmten Wert annehmen. Konstanten werden u. a. dazu verwendet, um die Verwendung der System-Skriptsprache verständlicher und kompakter zu machen. Folgende Konstanten sind fest definiert und immer verfügbar:
- INVALID_GUID – Die INVALID_GUID
INVALID_GUID
stellt einen ungültigen Wert für den DatentypGuidGuid
dar. - MAX_DATE – Der größte darstellbare Zeitpunkt (Timestamp
Timestamp
). DasMAX_DATEMAX_DATE
kann z. B. für Gültigkeitsbereiche verwendet werden, die nach oben offen sind.MAX_DATEMAX_DATE
entspricht dem konstantenMAX_TIME_STAMPMAX_TIME_STAMP
einer OQL-Abfrage. - MIN_DATE – Der kleinste darstellbare Zeitpunkt (Timestamp
Timestamp
). DasMIN_DATEMIN_DATE
kann z. B. für Gültigkeitsbereiche verwendet werden, die nach unten offen sind.MIN_DATEMIN_DATE
entspricht dem konstantenMIN_TIME_STAMPMIN_TIME_STAMP
einer OQL-Abfrage. - UNDEFINED_DATE – Ein undefinierter Zeitpunkt (Timestamp
Timestamp
). DasUNDEFINED_DATEUNDEFINED_DATE
wird z. B. für Zeitpunkte verwendet, bevor ein konkreter Wert zugewiesen wurde. Zum Beispiel der Zeitpunkt der letzten Änderung eines Business Objects (im AttributupdateInfo.updateTimeupdateInfo.updateTime
), welches seit dem Erfassen nicht mehr geändert wurde.UNDEFINED_DATEUNDEFINED_DATE
entspricht dem konstantenUNDEFINED_TIME_STAMPUNDEFINED_TIME_STAMP
einer OQL-Abfrage. - ZERO_GUID – Die ZERO-GUID
ZERO-GUID
wird immer dann verwendet, wenn eine GUID nicht null sein darf, aber dennoch undefiniert ist. Dies ist in z. B. dann der Fall, wenn die GUID Bestandteil eines Primärschlüssels ist.ZERO_GUIDZERO_GUID
entspricht dem KonstantenZEROGUIDZEROGUID
einer OQL-Abfrage.
CisDate
den kleinsten bzw. den größten darstellbaren Wert besitzt, können Sie die Funktionen isMinDate
und isMaxDate
verwenden.Kommentare
Kommentare werden mit
/*
eingeleitet und mit */
abgeschlossen. Kommentare können mehrere Zeilen umfassen.
Bei komplexeren Workflow-Prozessen ist es ratsam, ausreichend Kommentare in den Aktivitätsdefinitionen zu erfassen, um die Anpassung und Pflege zu erleichtern. Folgender beispielhafter Kommentar aus einer Prozessdefinition beschreibt den Prozess.
/** * This process exports changes to the Partner object every 15 * minutes. The process ends automaticallly when the processing * duration has been exceeded. * * Start: Manual process without event definition * * Owner: If the process owner is not defined in the process * definition then the start node automatically sets the owner to * the initiator (user who triggered the event) so that he or she * can display the process and be notified in case of errors. * Number1: Total number of export runs * Number2: Total number of Partners exported * Timestamp1: Begin time of Partner query of the last export run * Timestamp2: End time of Partner query of the last export run */
Es ist auch ratsam, globale Konstanten in Prozessdefinitionen zu deklarieren und zu kommentieren, um die Konfiguration von Workflow-Prozessen zu vereinfachen.
/** * JOB_QUEUE is the name of the job queue for the batch job. * If no job queue is specified in this constant then the default * job queue from the Customizing function 'Workflow Management' * is used. */ const JOB_QUEUE := "";
Ein leerer Ausdruck in einem Bedingungsfeld gilt als erfüllt (
true
). Da eine Bedingung, die aus nur einem Kommentar besteht, nicht leer ist, gilt folgende Übergangsbedingung als nicht erfüllt (false
), auch wenn sie keinen auswertbaren Ausdruck enthält, und erzeugt somit keine Aktivität.
/* parameters.object:status = OrderStatus.RELEASED */
Wenn Sie z. B. im Ramen einer Fehlersuche erreichen möchten, dass eine Aktivität unabhängig von der Übergangsbedingung immer erzeugt wird, aber die Übergangsbedingung nicht löschen möchten, dann können Sie stattdessen die Übergangsbedingung auskommentieren und durch den Wert
true
ersetzen.
true /* parameters.object:status = OrderStatus.RELEASED */
Terme und Bedingungen
Ein Term ist ein Ausdruck oder eine Formel, die einen Wert berechnet.
Beispiele von Termen:
a * a + b * b max(a, b) * min(c, d)
Eine Bedingung ist ein Ausdruck, der einen Wahrheitswert zurückgibt und somit eine Ja/Nein-Entscheidung ermöglicht.
Beispiele von Bedingungen:
a * a + b * b = c * c max(a, b) > 0 parameters.object:updateInfo.createUser <> parameters.userGuid
Die Syntax der Terme und Bedingungen ist ähnlich der in SQL. Wenn einer der Operanden nicht dem erwarteten Datentyp entspricht, so ist das Ergebnis der Operation
null
. Ist einer der Operanden null
, so ist das Ergebnis der Operation ebenfalls null
.
Arithmetische Operatoren
Für Zahlen sind die folgenden Operatoren definiert:
Operator | Beschreibung |
a * b | Multiplikation der Zahlen a und b. |
a / b | Division der Zahl a durch die Zahl b. |
a % b | Rest der ganzzahligen Division der Zahl a durch die Zahl b. |
a + b | Addition der Zahlen a und b. |
a – b | Subtraktion der Zahl b von der Zahl a. |
Arithmetische Operatoren, auch unterschiedlicher Art, können beliebig kombiniert werden. Wie üblich haben dabei die Operatoren
*
,/
und %
eine höhere Bindung als die Operatoren +
und -
. Operatoren mit gleicher Bindung werden von links nach rechts ausgeführt.
1 + 3
und 3 * 4 - 8
sind gültige Terme mit diesen Operatoren und liefern beide das Ergebnis 4
zurück.
1 * "a"
liefert null
zurück.Die System-Skriptsprache umfasst auch viele arithmetische Funktionen. Weitere Informationen und Beispiele finden Sie im Kapitel Arithmetische Funktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Operatoren auf Zeichenketten
Für Zeichenketten sind die folgenden Operatoren definiert:
Operator | Erläuterung |
a + b | Verknüpfung der Strings a und b. |
Beliebig viele Strings können zu einem Term verknüpft werden.
"Hello" + " " + "world"
ist ein gültiger Term mit diesem Operator.Die System-Skriptsprache umfasst auch viele Funktionen für Zeichenketten. Weitere Informationen und Beispiele finden Sie im Kapitel Funktionen für Zeichenketten der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Vergleichsoperatoren
Vergleichsoperatoren (Komparatoren) sind:
Operator | Erläuterung |
a = b | Vergleicht, ob die Werte der Terme a und b gleich sind. |
a < b | Vergleicht, ob der Wert des Terms a kleiner als der Wert des Terms b ist. |
a <= b | Vergleicht, ob der Wert des Terms a kleiner gleich dem Wert des Terms b ist. |
a > b | Vergleicht, ob der Wert des Terms a größer als der Wert des Terms b ist. |
a >= b | Vergleicht, ob der Wert des Terms a größer gleich dem Wert des Terms b ist. |
a <> b | Vergleicht, ob die Werte der Terme a und b ungleich sind. Alle Datentypen können mit <> verglichen werden. |
Alle Datentypen können mit den Operatoren
=
und <>
verglichen werden. Bei Business Objects werden dabei die vollständigen Inhalte verglichen. Ein Vergleich mit den anderen Operatoren ist nur für die Datentypen Number
, String
, CisDate
, Timestamp
und Boolean
möglich.
Die linke Seite einer Vergleichsoperation bestimmt den verglichenen Datentyp.
3 <= 1 + 2
ist eine wahre Bedingung.
"a" < "b"
ist eine wahre Bedingung.
"a" > 1
ist eine wahre Bedingung, da die Zahl 1 in eine Zeichenkette umgewandelt werden kann.
1 > "a"
liefert null zurück, da die Zeichenkette „a“ nicht in eine Zahl umgewandelt werden kann.
Das Ergebnis einer Vergleichsoperation ist vom Datentyp Wahrheitswert.
(1 = 3) = false
ist eine wahre Bedingung.
today() < addDays(today(), 1)
ist eine wahre Bedingung.
true = false
ist eine falsche Bedingung.Werden zwei CisDates mit einander verglichen, dann wird die Zeitzone mit berücksichtigt.
("CET", 2020, 1, 1, 0,0,0,0) < createCisDate("NST", 2019, 12, 31, 23,0,0,0)
ist eine wahre Bedingung, da sich die Zeitzone NST mehr als eine Stunde nach der Zeitzone CET. befindet.
Um ein CisDate mit einem Zeitpunkt zu vergleichen, können Sie mithilfe der Skript-Funktion
toTimestamp
das CisDate in einen Zeitpunkt umwandeln.
toTimestamp(today()) <= now()
ist eine wahre Bedingung.Bedingungen
Bedingungen können beliebig mit den logischen Operatoren
AND
und OR
verknüpft werden:
Operator | Erläuterung |
a AND b | AND AND ist eine Und-Verknüpfung von zwei Bedingungen. Das Ergebnis ist wahr, wenn sowohl die Bedingung a als auch die Bedingung b wahr sind. |
a OR b | OR OR ist eine Oder-Verknüpfung von zwei Bedingungen. Das Ergebnis ist wahr, wenn entweder die Bedingung a oder die Bedingung b oder a und b wahr sind. |
NOT a | NOT NOT ist eine Negierung einer Bedingung. Das Ergebnis ist wahr, wenn die Bedingung a falsch ist, und falsch, wenn die Bedingung a wahr ist. |
Die Operatoren
AND
und OR
können beliebig kombiniert werden. Wie üblich besitzt dabei der Operator AND
eine höhere Bindung als der Operator OR
.
1 = 1 AND 3 = 3
ist eine wahre Bedingung.
1 = 1 OR 2 = 2 AND 3 = 4
ist eine wahre Bedingung.
1 = 0 OR 2 = 2 AND 3 = 4
ist falsche Bedingung.a AND b
und a und b
sind syntaktisch identische und gültige Bedingungen.Klammerung
Terme und Bedingung können beliebig geklammert werden:
Operator | Erläuterung |
(a) | Klammerungen von Termen und Bedingungen. |
Ein geklammerter Term wird immer als Einheit ausgeführt, unabhängig von den Unterschieden der Bindungen der Operatoren.
(2 + 3) * 2 = 10
ist eine wahre Bedingung.
(2 * (7 - 6) + 1) = 3
ist eine wahre Bedingung.
(1 = 1 OR 3 < 1) AND 2 = 2
ist eine wahre Bedingung.Zugriff auf Listen und Hash-Tabellen
Für den Zugriff auf Listen und Hash-Tabellen existieren die folgenden Operatoren:
Operator | Erläuterung |
b[a] | Zugriff auf das Element mit dem Index a der Liste b, beginnend beim Index 0. Der Index a muss eine Zahl sein. Ist a keine Ganzzahl, so wird nur der ganzzahlige Anteil berücksichtigt. Liegt der Index außerhalb des gültigen Bereiches für die Liste, so ist das Ergebnis null null . |
b.a | Zugriff auf den Wert mit dem Schlüssel a in der Hash-Tabelle b. Wenn zu dem Schlüssel kein Wert existiert, so ist das Ergebnis null null . |
b[“a”] | Zugriff auf den Wert mit dem Schlüssel a in der Hash-Tabelle b. Wenn zu dem Schlüssel kein Wert existiert, so ist das Ergebnis null null . |
Beide Arten des Zugriffs auf Hash-Tabellen sind äquivalent. Der Zugriff mit Punkt (
b.a
) ist kompakter und eignet sich insbesondere dann, wenn die Einträge der Hash-Tabelle zu dem Zeitpunkt, zu dem der Ausdruck geschrieben wird, bekannt sind. Wenn die Einträge sich dynamisch während der Laufzeit berechnen, so ist der Zugriff mit eckigen Klammern (b["a"]
) sinnvoller.
h = {("a" ,1), ("x1", 11), ("x2", 12) , ("x3", 13)}
h.a = 1
ist eine wahre Bedingung.
h["a"] = 1
ist eine wahre Bedingung.
h["x" + (3 - 2)] = 11
ist eine wahre Bedingung.
h.x = 1
liefert den Wert null
zurück.l = {"a", "b", "c"}
l[0] = "a"
ist eine wahre Bedingung.
l[2] = "c"
ist eine wahre Bedingung.
l[2 * 3] = "a"
liefert den Wert null
zurück.Zugriff auf Business Objects, Parts und Objektsichten
Für Business Objects und Parts sind die folgenden Operatoren verfügbar:
Operator | Erläuterung |
o:a | Zugriff auf das Attribut a des Business Objects, Parts oder der Objektsicht o. Wenn das Attribut a in dem Objekt o nicht existiert oder einen nicht unterstützten Datentyp enthält, so ist das Ergebnis null null .
Das Attribut a kann ein komplexer Zugriffspfad auf die Attribute von den in das Objekt o eingebetteten Parts und Feldern sein. |
o->R | Zugriff auf die 1:1-Beziehung R eines Business Objects, Parts oder der Objektsicht o. Wenn die Beziehung nicht existiert oder auf kein Objekt zeigt, so ist das Ergebnis null null . Das Ergebnis des Zugriffs auf eine Beziehung ist ein Business Object als Wert. |
Der Zugriff auf Business Objects, Parts und Objektsichten wird häufig benötigt, da diese Objekte die wichtigsten Datencontainer im System sind.
loadPartner("10010"):address.city
ist ein gültiger Zugriff auf das Attribut city
in dem komplexen Attribut address
des Business Objects Partner mit der Identifikation 10010.
loadPartner("10010"):organizationalUnit.name[1]
ist ein gültiger Zugriff auf das Feld mit dem Index 1 in dem Feld-Attribut name
in dem komplexen Attribut organizationalUnit
des Business Objects Partner mit der Identifikation 10010.
loadPartner("10010")->Language:isoCode
ist ein gültiger Zugriff auf das Attribut isoCode
desjenigen Business Objects, das durch die Beziehung Language
von dem Business Object Partner mit der Identifikation 10010 referenziert wird.Um Attribute, deren Namen mit einem Unterstrich beginnen, auszuwerten, können Sie die Funktion
getAttribute
verwenden. Bevor Sie das Ergebnis verwenden, sollten Sie es in einen zum Attribut passenden Datentyp umwandeln.
loadCurrency(getCorporateCurrency(cast(Guid, getAttribute(parameters.object, "_organization")))):isoCode
gibt den ISO-Code der Leitwährung der Organization zurück, in dessen Kontext das vom parameters.object
referenzierte Business Object erfasst wurde.Aktivitätsdefinitionen aufrufen
Sie können Aktivitätsdefinitionen mit der Kategorie Funktionsaufruf wie Funktionen aufrufen. Der Name der Aktivitätsdefinition darf für den Aufruf nur Buchstaben, Zahlen und die Sonderzeichen Punkt (
.
), Unterstrich (_
), Dollarzeichen ($
) oder Raute (#
) enthalten. Falls der Name andere Zeichen enthält, muss die Aktivitätsdefinition mit der Funktion call
aufgerufen werden. Siehe auch Kapitel Sonstige Funktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Um den Aufruf einer Aktivitätsdefinition von einem Funktionsaufruf zu unterscheiden, wird dem Namen der Aktivitätsdefinition das At-Zeichen (
@
) vorangestellt. Bei dem Aufruf muss jedem Parameter der Aktivitätsdefinition ein Wert zugeordnet werden. Die Parameter werden alphabetisch sortiert. Die Rückgabewerte der Aktivitätsdefinition werden als Klasse zurückgegeben. Die einzelnen Rückgabewerte sind Attribute dieser Klasse.
isPythagorean
besitzt die Parameter A
, B
und C
vom Typ Number
sowie den Rückgabewert RESULT
vom Typ Boolean
. Die Aktivitätsdefinition wird wie folgt aufgerufen:
var result := @isPythagoreanTheorem(A:=3, B:=4, C:=5).RESULT;
Die maximale Rekursionstiefe ist beschränkt. Weitere Informationen finden Sie in dem Kapitel Komplexität von Ausdrücken beschränken.
Befehle
Ein Befehl ist ein Ausdruck, der eine Operation ausführt, die kein Ergebnis liefert. In der System-Skriptsprache werden Befehle durch ein Strichkomma (
;
) getrennt.
echo(definition:code); setMailRecipientsTo("somebody@localhost.local");
Abhängig vom Verwendungskontext können unterschiedliche Befehle definiert sein. In den folgenden Abschnitten werden die Befehle gruppiert nach den Verwendungskontexten beschrieben.
Kontrollfluss und Variablenzuweisung
Die Befehle zum Steuern des Kontrollflusses und die Variablenzuweisung sind in die System-Skriptsprache fest eingebaut.
Beschreibung | Syntax |
Variablendeklaration (Typ) | var <VariableName> as <Type> var <VariableName> as <Type> |
Variablendeklaration (Term) | var <VariableName> := <Expression> var <VariableName> := <Expression> |
Konstantendeklaration | const <VariableName> := <Expression> const <VariableName> := <Expression> |
Value-Set-Deklaration | const <VariableName> as valueSet(<Name>) const <VariableName> as valueSet(<Name>) |
Typdefinition | type <TypeName> as <Type> type <TypeName> as <Type> |
Typdefinition (class) |
type <TypeName> as class { <AttributeName> as <Type>; ... <AttributeName> as <Type>; } type <TypeName> as class {
<AttributeName> as <Type>;
...
<AttributeName> as <Type>;
} type <TypeName> as class { <AttributeName> as <Type>; ... <AttributeName> as <Type>; } |
Zuweisung | <VariableName> := <Expression> <VariableName> := <Expression> |
Bedingter Befehl | if (<Condition>) <Command> if (<Condition>) <Command> |
Bedingter Befehl mit Alternative | if (<Condition>) <Command> else <Command> if (<Condition>) <Command> else <Command> |
Schleife mit Bedingung | while (<Condition>) <Command> while (<Condition>) <Command> |
Schleife über alle Elemente | for (<VariableName> : <List>) <Command> for (<VariableName> : <List>) <Command> |
Schleife über alle Elemente mit Typisierung |
for (<VariableName> as <Type> : <List>) <Command> for (<VariableName> as <Type> : <List>)
<Command> for (<VariableName> as <Type> : <List>) <Command> |
Befehl beenden | return return |
Funktion beenden | return <Expression> return <Expression> |
Anweisungsblock |
{ <Command> ... <Command> } {
<Command>
...
<Command>
} { <Command> ... <Command> } |
Die System-Skriptsprache umfasst auch die Funktion
if
, um den Kontrollfluss innerhalb eines Ausdrucks zu bestimmen. Weitere Informationen und Beispiele finden Sie im Kapitel Sonstige Funktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Konstanten
Eine Konstante kann nur einen einzigen vorbestimmten Wert annehmen. Konstanten werden u. a. dazu verwendet, um die Verwendung der System-Skriptsprache verständlicher und kompakter zu machen.
Konstanten werden wie Variablen mit einem Term deklariert. Im Unterschied zu Variablen kann der Wert einer Konstante nach deren Deklaration nicht mehr verändert werden.
Bei komplexeren Workflow-Prozessen ist es ratsam, globale Konstanten in der Prozessdefinition zu deklarieren, mit denen der Workflow-Prozess zentral konfigurieren lässt, damit die Aktivitätsdefinitionen der einzelnen Prozessschritte möglichst nicht angepasst werden müssen.
/** * JOB_QUEUE is the name of the job queue for the batch job. * If no job queue is specified in this constant then the * default job queue from the Customizing function 'Workflow * Management' is used. */ const JOB_QUEUE := "";
Variablen
Alle verwendeten Variablen und Konstanten müssen deklariert werden. Variablen können mit einem Typ oder einem Initialwert deklariert werden. Wenn ein Typ angegeben wird, so besitzt die Variable den Standardwert des Typs als Initialwert. Wenn eine Variable über einen Term deklariert wird, so hat diese den Ergebniswert des Terms als Wert und dessen Datentypen als Datentyp.
var n as Number;
Nach der Deklaration von m besitzt m den numerischen Wert 6:
var m := 1 + 5;
Um Konstanten von Variablen besser unterscheiden zu können, wird empfohlen, Konstanten, die in Prozessdefinitionen definiert sind, durchgehend mit Großbuchstaben zu deklarieren, Konstanten, die in Aktivitätsdefinitionen definiert sind, mit einem Großbuchstaben und Variablen mit einem Kleinbuchstaben anfangen zu lassen.
ValueSets
Um ein Valueset zu verwenden, müssen Sie dieses mit der Anweisung
const <VariableName> as valueSet(<Name>)
deklarieren, um später auf dessen Einträge zugreifen zu können. Die Deklaration erzeugt eine Variable vom Typ Class
und darin für jeden Valueset-Eintrag eine Konstante mit dem technischen Namen des Eintrags und dessen ID.
parameters.object
referenzierter Vertriebsauftrag freigegeben, dann wird die Zeichenkette RELEASED ins Protokoll ausgegeben:
const OrderStatus as valueSet(com.cisag.app.general.OrderStatus); function create() { if (parameters.object:status = OrderStatus.RELEASED) echo(valueSetName(OrderStatus, parameters.object:status); }
Typdefinitionen
Zur Vereinfachung können Sie in der System-Skriptsprache eigene Datentypen deklarieren und verwenden. Die Verwendung von Typen erleichtert durch die besseren Abstraktionsmöglichkeiten das Verständnis des Programms. Für jede Verwendung von Klassen muss ein Typ definiert werden. Das Schlüsselwort
class
kann nur bei einer Typdeklaration verwendet werden.
type PartnerCode as String; type PartnerCodeList as PartnerCode[]; type WeekdaySum as Number[7]; var code as PartnerCode; code := "4711";
Definition und Verwendung einer Klasse:
type Bike as class { name as String; weight as Number; chainset as String; } var myBike := new(Bike); myBike.name := "Niner RLT"; myBike.weight := 9250; myBike.chainset := "Shimano 105";
Zuweisungen
Bei der Zuweisung kann einer Variablen, einem Attribut einer Klasse, einem Eintrag in einer Liste oder einer Hash-Tabelle ein Wert zugewiesen werden. Das Element, wlechem etwas zugewiesen wird, steht auf der linken Seite der Zuweisung. Der zugewiesene Wert wird aus dem Term auf der rechten Seite der Zuweisung berechnet.
Jede verwendete Variable muss deklariert sein und besitzt somit einen festen Typ. Einer Variablen können nur Werte dieses Typs zugewiesen werden.
Nachfolgend einige Beispiele für die Zuweisung eines Wertes zu einer Variablen.
x := 2;
Nach dem Ausführen dieses Befehls hat die Variable x den Wert 7:
x := x * x + 3;
Nach dem Ausführen dieser Befehle enthält die Variable l ein Feld mit den Elementen Hallo und Welt
var l as String[2]; l[0] := "Hallo"; l[1] := "Welt";
Die folgenden beiden Befehle sind äquivalent und weisen in der Hash-Tabelle c dem Schlüssel a den Wert X zu:
var c as HashMap; c.a := "X"; c["a"] := "X";
Anweisungsblöcke
Mit geschweiften Klammern kann eine Folge von Befehlen zu einem Befehl in einem Anweisungsblock zusammengefasst werden. Alle Befehle in einem Anweisungsblock werden in der Reihenfolge ausgeführt, die in dem Block vorgegeben ist. Wenn ein Befehl bei der Ausführung einen Fehler meldet, so bricht der gesamte Anweisungsblock mit einem Fehler ab. Viele Befehle und Funktionen melden einen Fehler, wenn sie den Wert
null
als Parameter bekommen.
{ x := 2; x := x * x + 3; }
Bedingter Befehl (if)
Der bedingte Befehl
if
führt einen Befehl abhängig von dem Ergebnis einer Bedingung aus. Wenn die Bedingung wahr ist, dann wird der Befehl ausgeführt. Wenn die Bedingung nicht wahr ist, wird der Befehl übersprungen.
x := -13; if (x < 0) x := 0;
Bedingter Befehl mit Alternative (if … else)
Der bedingte Befehl mit Alternative
if else
führt abhängig von dem Ergebnis einer Bedingung einen von zwei alternativen Befehlen aus. Wenn die Bedingung wahr ist, dann wird der Befehl vor dem else
ausgeführt. Wenn die Bedingung nicht wahr ist, so wird der Befehl vor dem else
übersprungen und der Befehl nach dem else
ausgeführt.
x := 13; if (x < 0) { x := -1; } else if (x > 0) { x := 1; }
Schleife mit Bedingung (while)
Die Schleife mit Bedingung
while
führt solange einen Befehl aus, wie eine Bedingung erfüllt ist. Die Bedingung wird vor jeder Ausführung des Befehls geprüft, das bedeutet insbesondere auch, vor der ersten Ausführung. Wenn die Bedingung nicht erfüllt ist, wird der Befehl nicht ausgeführt.
var i := 10; var r := 0; while (i > 0) { r := r + i: i := i - 1; }
Die Anzahl der Durchläufe in einer while-Schleife ist beschränkt. Weitere Informationen finden Sie im Kapitel Komplexität von Ausdrücken beschränken.
Schleife über alle Elemente (for)
Die
for
-Schleife führt einen Befehl für alle Elemente einer Liste aus. Die Reihenfolge der Elemente in der Liste wird dabei eingehalten. Wenn die Liste keine Elemente hat, wird der Befehl nicht ausgeführt.
var l := list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); var r := 0; for (e : l) { r := r + e: }
Schleife über alle Elemente (for … as)
Die
for
-Schleife führt einen Befehl für alle Elemente einer Liste aus. Die Reihenfolge der Elemente in der Liste wird dabei eingehalten. Das Element kann mit as
in einen bestimmten Typ umgewandelt werden.
var objects := getCisObjectList( "SELECT FROM com.cisag.app.general.obj.Item o", list(), 10); for (item as CisObject(com.cisag.app.general.obj.Item) : objects) { echo(item:number); }
Befehl beenden (return)
Der Befehl
return
beendet die aktuell ausgeführte Funktion.
function validate(state as Number) { if (state = State.CANCELED) return; if (results.COMMENT = "") { sendMessage(results.COMMENT_id, "ERROR", "Comment is missing."); return; } if (length(results.COMMENT) < 20) { sendMessage(results.COMMENT_id, "WARNING", "Comment should be at least 20 characters."); return; } }
Funktion beenden (return mit Rückgabewert)
Der Befehl
return
beendet die aktuell ausgeführte Funktion und gibt den Rückgabewert als Funktionsergebnis zurück.
r_text
beendet die Funktion und übergibt das Ergebnis an den Aufrufer.
function join(p_textList as String[], p_separator as String) as String { var r_text as String; for (word as String : p_textList) r_text := r_text + p_separator + word; if (r_text <> "") r_text := substring(r_text, length(p_separator)); return r_text; }
Funktionen
Funktionen der System-Skriptsprache
Die System-Skriptsprache stellt viele Funktionen zur Verfügung. Um korrekt zu funktionieren, benötigen Funktionen die geeignete Umgebung, d. h. bestimmte Rahmenbedingungen müssen erfüllt sein. Unterschieden wird zum einen die Datenbank und zum anderen, ob eine Aktivität benötigt wird oder nicht. Soll die Funktion z. B. in der Übergangsbedingung (Transition) der Aktivitätsdefinition genutzt werden, so kann die Funktion nicht auf die Aktivität zugreifen, da diese erst zu einem späteren Zeitpunkt erzeugt wird.
Die Festlegung des Gültigkeitsbereichs einer Funktion erfolgt im Konstruktor der Funktion. In der Klasse
ParserFunctions
sind die möglichen Gültigkeitsbereiche in Form von Konstanten definiert.
Verwendungskontext | Beschreibung |
SYS_SCRIPT_OLTP SYS_SCRIPT_OLTP |
Verwendbar in Skript-Objekten, individuellen Prüfungen und individuellen Hook-Implementierungen im Kontext einer OLTP-Datenbank. |
WF_TRANSITION_REPOSITORY WF_TRANSITION_REPOSITORY |
Verwendbar in Übergangsbedingungen und in der Funktion create create von Aktivitätsdefinitionen für Aktivitäten in der Repository-Datenbank. |
WF_TRANSITION_OLTP WF_TRANSITION_OLTP |
Verwendbar in Übergangsbedingungen und in der Funktion create create von Aktivitätsdefinitionen für Aktivitäten in einer OLTP-Datenbank. |
WF_ACTIVITY_REPOSITORY WF_ACTIVITY_REPOSITORY |
Verwendbar in Ausdrücken und Deklarationen, aber nicht in Übergangsbedingungen von Aktivitätsdefinitionen für Aktivitäten in der Repository-Datenbank. |
WF_ACTIVITY_OLTP WF_ACTIVITY_OLTP |
Verwendbar in Ausdrücken und Deklarationen, aber nicht in Übergangsbedingungen von Aktivitätsdefinitionen für Aktivitäten in einer OLTP-Datenbank. |
WF_REPOSITORY WF_REPOSITORY |
Entspricht den Verwendungskontexten WF_TRANSITION_REPOSITORY WF_TRANSITION_REPOSITORY und WF_ACTIVITY_REPOSITORY WF_ACTIVITY_REPOSITORY . Verwendbar in Aktivitätsdefinitionen für Aktivitäten in der Repository-Datenbank. |
WF_OLTP WF_OLTP |
Entspricht den Verwendungskontexten WF_TRANSITION_OLTP WF_TRANSITION_OLTP und WF_ACTIVITY_OLTP WF_ACTIVITY_OLTP . Verwendbar in Aktivitätsdefinitionen für Aktivitäten in einer OLTP-Datenbank. |
OLTP OLTP |
Entspricht den Verwendungskontexten WF_SYS_SCRIPT_OLTP WF_SYS_SCRIPT_OLTP und WF_OLTP WF_OLTP . D. h. der Verwendungskontext setzt keine Aktivitätsdefinition, aber eine OLTP-Datenbank voraus. Hierzu gehören Funktionen wie z. B. loadPartner loadPartner und loadItem loadItem . Verwendbar in Aktivitätsdefinitionen für Aktivitäten in einer OLTP-Datenbank sowie in Skript-Objekten, individuellen Prüfungen und individuellen Hook-Implementierungen im Kontext einer OLTP-Datenbank. |
ALL ALL |
Verwendbar in allen Kontexten, d. h. weder eine Aktivitätsdefinition noch eine OLTP-Datenbank wird vorausgesetzt. Hierzu gehören Funktionen wie z. B. createCisDate createCisDate , getByPrimaryKey getByPrimaryKey und getCisObjectList getCisObjectList . |
Weitere Informationen und Beispiele zu den Funktionen und Befehlen finden Sie in folgenden Dokumentationen:
- System-Skriptsprache: Allgemeine Funktionen
Funktionen des VerwendungskontextsALLALL
.
- System-Skriptsprache: OLTP-Funktionen
Funktionen des VerwendungskontextsOLTPOLTP
oderSYS_SCRIPT_OLTPSYS_SCRIPT_OLTP
.
- System-Skriptsprache: Workflow-Funktionen
Funktionen des VerwendungskontextsWF_REPOSITORYWF_REPOSITORY
,WF_OLTPWF_OLTP
,WF_ACTIVITY_REPOSITORYWF_ACTIVITY_REPOSITORY
,WF_ACTIVITY_OLTPWF_ACTIVITY_OLTP
,WF_TRANSITION_REPOSITORYWF_TRANSITION_REPOSITORY
oderWF_TRANSITION_OLTPWF_TRANSITION_OLTP
.
Eigene Funktionsdeklarationen
Funktionen fassen unterschiedliche Elemente der System-Skriptsprache zusammen, um komplexe Zusammenhänge auszudrücken. Liefert eine Funktion keinen Wert zurück, dann ist der Wert der Funktion
null
.
function isPythagoreanTheorem(a as Number, b as Number, c as Number) as Boolean { return a * a + b * b = c * c; } function create() { var tryPythagoreanTheorem := isPythagoreanTheorem(3, 4, 5) }
In den Termen können Funktionen aufgerufen werden. Funktionen berechnen aufgrund ihrer Eingangsparameter ein Ergebnis. Abhängig von der jeweiligen Funktion existieren Voraussetzungen an die Anzahl und den Typ der Eingangsparameter. Diese Voraussetzungen werden wie folgt ausgedrückt:
R f(D1 p1, ..., Dn pn)
Wenn der Datentyp völlig frei ist, so wird der Datentyp
Unknown
verwendet.Deklarationen
In diesem Kapitel wird beschrieben, wo Deklarationen erfasst und verwendet werden können, welche vorbelegten Funktionen dabei jeweils zur Verfügung stehen, sowie die Reihenfolge der Auswertung.
Deklarationen in Aktivitätsdefinitionen
Die Deklarationen einer Aktivitätsdefinition besitzen folgende vorbelegte Funktionen:
Funktion | Beschreibung |
create create |
Die Funktion create create wird beim Erzeugen der Aktivität aufgerufen.Da zum Zeitpunkt des Aufrufs die Aktivität noch nicht erzeugt ist, stehen in der Funktion create create die Informationen zur Aktivität nur eingeschränkt zur Verfügung. |
applyDefaults applyDefaults |
Die Funktion applyDefaults applyDefaults wird beim Öffnen des Dialogs Aktivitätsergebnisse aufgerufen. Bei einem Startknoten mit einem Aktivitätsergebnis, wird der Dialog und somit auch die Funktion applyDefaults applyDefaults vor der Funktion create create aufgerufen. Bei allen anderen Aktivitäten erfolgt der Aufruf erst, nachdem die Funktion create create aufgerufen wurde.
Da der Zweck der Funktion applyDefaults applyDefaults ist, die Felder des Dialogs Aktivitätsergebnisse zu initalisieren und mit Werten vorzubelegen, wird die Umgebung am Ende des Aufrufs nicht persistent gespeichert. Eventuelle Zuweisungen von Variablen innerhalb der Funktion applyDefaults applyDefaults stehen anderen Funktionen somit nicht zur Verfügung. |
validate validate |
Die Funktion validate validate wird vor dem Übernehmen der Aktivitätsergebnisse im Dialog Aktivitätsergebnisse aufgerufen. Die Funktion wird auch dann aufgerufen, wenn die Aktivität in der Anwendung Aktivitäten gespeichert wird.Der Parameter state state gibt den künftigen Status der Aktivität wieder.Die Funktion validate validate liefert einen Rückgabewert vom Datentyp Boolean Boolean zurück. Ist der Rückgabewert false false , dann können die Aktivitätsergebnisse nicht übernommen werden. In einem Startknoten verhindert die Ausgabe einer Fehlermeldung mithilfe des Befehls sendMessage sendMessage die Übernahme der Aktivitätsergebnisse. Schließt der Benutzer den Dialog Aktivitätsergebnisse mithilfe des Buttons [Abbrechen], wird keine Aktivität erzeugt. Da der Zweck der Funktion validate validate ist, die Benutzereingaben im Dialog Aktivitätsergebnisse zu überprüfen, wird die Umgebung am Ende des Aufrufs nicht persistent gespeichert. Eventuelle Zuweisungen von Variablen innerhalb der Funktion validate validate stehen anderen Funktionen somit nicht zur Verfügung. |
validatePrecondition validatePrecondition |
Die Funktion validatePrecondition validatePrecondition wird bei einem Statuswechsel der Aktivität aufgerufen, wenn im Feld Vorbedingung der Wert Deklaration ausgewählt ist. Die Funktion wird auch dann aufgerufen, wenn die Aktivität gespeichert wird, auch wenn sich der Status nicht ändert.
Der Parameter state gibt den künftigen Status der Aktivität wieder. Die Funktion validatePrecondition validatePrecondition liefert einen Rückgabewert vom Datentyp Boolean Boolean zurück. Ist die Vorbedingung false false , dann wird die Aktivität automatisch unbearbeitet erledigt. In einem Startknoten wird keine Aktivität erzeugt, wenn die Funktion mithilfe des Befehls sendMessage sendMessage eine Fehlermeldung ausgibt. |
validatePostcondition validatePostcondition |
Die Funktion validatePostcondition validatePostcondition wird vor dem Erledigen der Aktivität aufgerufen, wenn im Feld Nachbedingung der Wert Deklaration ausgewählt ist.
Der Parameter state state gibt den künftigen Status der Aktivität wieder.
Die Funktion validatePostcondition validatePostcondition liefert einen Rückgabewert vom Datentyp Boolean Boolean zurück. Ist die Nachbedingung false false , dann kann die Aktivität nicht erledigt werden. Die Aktivität kann auch dann nicht erledigt werden, wenn die Funktion mithilfe des Befehls sendMessage sendMessage eine Fehlermeldung ausgibt.
Die Funktion validatePostcondition validatePostcondition wird nur aufgerufen, wenn der Bearbeiter ein Benutzer ist. Bei Aktivitäten, die vom System oder von einem Verarbeitungsauftrag bearbeitet werden, erfolgt kein Aufruf. |
validateSeriesCondition validateSeriesCondition |
Die Funktion validateSeriesCondition validateSeriesCondition wird gemäß des in der Serienvorlage hinterlegten Serienmusters aufgerufen, wenn im Feld Serienbedingung der Wert Deklaration ausgewählt ist.
Die Funktion validateSeriesCondition validateSeriesCondition liefert einen Rückgabewert vom Datentyp Boolean Boolean zurück. Ist die Serienbedingung false false , dann bricht die Serie ab und keine weiteren Serienaktivitäten werden erzeugt. |
validateSelection validateSelection |
Die Funktion validateSelection validateSelection wird in einer Aktivität des Typs Auswahlknoten aufgerufen, wenn der Benutzer ein Business Object mit der Aktivität verknüpft.
Die Funktion validateSelection validateSelection liefert einen Rückgabewert vom Datentyp Boolean Boolean zurück. Ist die Auswahlbedingung false false , dann wird die Verknüpfung mit einer Fehlermeldung abgewiesen. Die Verknüpfung wird auch dann abgewiesen, wenn die Funktion mithilfe des Befehls sendMessage sendMessage eine Fehlermeldung ausgibt. |
close close |
Die Funktion close close wird beim Erledigen bzw. Erledigen ohne Bearbeitung der Aktivität aufgerufen.
Der Parameter state gibt den künftigen Status der Aktivität wieder. |
Deklarationen in Prozessdefinitionen
Die Deklarationen einer Prozessdefinition werden den globalen Deklarationen der Aktivitätsdefinitionen hinzugefügt, bevor sie ausgewertet werden. Aus diesem Grund dürfen die Deklarationen einer Prozessdefinition nur Deklarationen enthalten, die auch außerhalb der Deklarationen der Aktivitätsdefinition deklariert werden können.
const MaxAmount := "123"; function helloWorld () as String { return "Hello World!"; }
Die Konstante
MaxAmount
und die Funktion helloWorld
können uneingeschränkt in allen Aktivitätsdefinitionen der Prozessdefinition verwendet werden, die die gleiche Skriptsprache wie die Prozessdefinition verwenden.Beachten Sie bitte, dass je nach verwendeter Skript-Engine weitere Einschränkungen vorliegen können. Beispielsweise erlaubt die JavaScript-Engine Nashorn keine Deklaration von Konstanten.
Beachten Sie bitte auch, dass eine eigene Typdefinition (
Class
), die in einer Prozessdefinition deklariert ist, nicht in den Aktivitätsdefinitionen verwendet werden kann.
Reihenfolge der Auswertung in Aktivitätsdefinitionen
Wenn eine neue Aktivität aufgrund eines Ereignisses erzeugt wird, dann wird die Umgebung, in der die Bedingungen, Befehle und Terme ausgeführt werden, mit den durch das Ereignis vorgegebenen Variablenwerten initialisiert. Wenn eine aktivierte Aktivitätsdefinition ein Ereignis empfängt, dann werden die Ausdrücke dieser Aktivitätsdefinition in der unten beschriebenen Reihenfolge ausgewertet.
In einem Startknoten
Beim Erzeugen einer Aktivität für einen Startknoten werden die Funktionen in der folgenden Reihenfolge aufgerufen:
- Globale Deklarationen der Prozessdefinition
- Globale Deklarationen der Aktivitätsdefinition (außerhalb der Funktionen)
- applyDefaults
- validate
- create
- validatePrecondition
- close
Die Funktionen
applyDefaults
und validate
werden nur dann aufgerufen, wenn die Aktivitätsdefinition ein Aktivitätsergbnis besitzt und der Prozess manuell gestartet wird, d. h. beim Ereignistyp Benutzeraktion oder bei Startknoten ohne eine Ereignisdefinition. Bei den Ereignistypen Programmiertes Ereignis und Business Entity werden die beiden Funktionen nicht aufgerufen.
Allgemein
Handelt es sich nicht um einen Startknoten, werden die Funktionen in der folgenden Reihenfolge aufgerufen:
- Globale Deklarationen der Prozessdefinition
- Globale Deklarationen der Aktivitätsdefinition (außerhalb der Funktionen)
- Übergangsbedingung
- create
- Anwendungsparameter
- Ausdruck für Bearbeiter
- validatePrecondition
- applyDefaults
- validate
- validatePostcondition
- close
Die Funktion
validatePrecondition
wird bei jedem Statuswechsel der Aktivität aufgerufen, d. h. der Aufruf erfolgt in der Regel mehrmals.
Die Funktionen
applyDefaults
und validate
werden nur dann aufgerufen, wenn die Aktivitätsdefinition ein Aktivitätsergbnis besitzt und der Bearbeiter ein Benutzer ist. Wird die Aktivität durch eine Cockpit-Anwendung erledigt, dann wird der Dialog Aktivitätsergebnisse nicht geöffnet und beiden Funktionen nicht aufgerufen.
Ist der Bearbeiter der Aktivität kein Benutzer, sondern das System oder ein Verarbeitungsauftrag, wird die Funktion
validatePostcondition
nicht aufgerufen.
Befehle
Aktivitätsdefinitionen, die im Release 5.1 oder früher erfasst sind, können Befehle statt Deklarationen besitzen. Die Befehle werden beim Erzeugen der Aktivität ausgeführt und entsprechen in etwa der Funktion
create
. Aktivitätsdefinitionen, die Befehle verwenden, können keine Skripte beim Eingeben von Ergebnissen und beim Erledigen der Aktivität ausführen. Daher wird empfohlen, Befehle in Deklarationen zu überführen.
Dazu kopieren Sie das Skript von dem Karteireiter Befehle in die Funktion
create
auf dem Karteireiter Deklarationen und löschen das Skript auf dem Karteireiter Befehle. Nachdem Sie die Aktivitätsdefinition gespeichert haben, wird der Karteireiter Befehle ausgeblendet, sobald dessen Editorfeld leer ist.
Da Konstanten und Variablen, die auf dem Karteireiter Befehle deklariert sind, in allen Feldern der Aktivitätsdefinition zur Verfügung stehen, müssen Sie zusätzlich alle Konstanten, Variablen und Typdefinitionen, die in anderen Feldern der Aktivitätsdefinition verwendet werden, z. B. in der Vorbedingung oder in einem Feld für die Anwendungsparameter, außerhalb der Funktion
create
deklarieren.
Auf dem Karteireiter Befehle ist folgendes Skript hinterlegt:
var editors as Guid[]; var customer := parameters.object->CustomerData->CustomerPartner; var responsible := loadTargetsOfPartnerRelations(customer:guid, parameters.object->DeliveryPartnerData->Organization:guid, "Responsible"); for (r : responsible) { editors := union(editors, resolvePartner(r:guid)); }
Die Variable
editors
wird im Feld Ausdruck für Bearbeiter verwendet. Die Variable customer
wird als Wert für den Parameter Partner der Anwendung com.cisag.app.general.partner.ui.PartnerMaintenance
verwendet.
Um die Befehle in Deklarationen zu überführen, werden die Deklaration der Variablen
editors
und customer
außerhalb der Funktion create
platziert.
const State as valueSet(com.cisag.sys.workflow.ActivityState); var editors as Guid[]; var customer := parameters.object->CustomerData->CustomerPartner; function create() { var responsible := loadTargetsOfPartnerRelations(customer:guid, parameters.object->DeliveryPartnerData->Organization:guid, "Responsible"); for (r : responsible) { editors := union(editors, resolvePartner(r:guid)); } }
Skript-Objekte und Bibliotheken
Eigene Deklarationen von Funktionen, Variablen und Konstanten können in Kundensystemen als Skript-Objekte erfasst werden. Verwenden Sie dazu die Anwendung Entwicklungsobjekte. Das Einbinden von Skript-Objekten hat den Vorteil, dass eigene Deklarationen zentral verwaltet werden können; Änderungen zu den Skript-Objekten wirken sich unmittelbar auf die Skripte aus, in denen sie eingebunden sind.
Als Entwicklungsobjekt unterliegen Skript-Objekte der Versionierung. Mithilfe der Anwendung Cockpit: Produktivsystem-Entwicklungsobjekte lassen sich die auf einem Testsystem erfassten Skript-Objekte (ähnlich wie die Workflow-Vorlagen) auf ein Produktivsystem übertragen.
Eigene Deklarationen können Sie auch in der Anwendung Bibliotheken erfassen und zu einer Bibliothek zusammenfassen. Wie die Workflow-Vorlagen werden auch Bibliotheken in der Repository-Datenbank gespeichert und stehen somit in allen OLTP-Datenbanken eines Systems zur Verfügung.
Um eingebunden werden zu können, muss das Skript-Objekt bzw. die Bibliothek die gleiche Skriptsprache wie das Skript verwenden. Ist das Skript in der System-Skriptsprache erfasst, dann verwenden Sie den Befehl
import
, um das Skript-Objekt bzw. die Bibliothek einzubinden. Ist das Skript in JavaScript erfasst, dann verwenden Sie den Befehl load
. Weitere Informationen und Beispielen zu den beiden Befehlen finden Sie im Kapitel Sonstige Funktionen der Dokumentation System-Skriptsprache: Allgemeine Funktionen.
Individuelle Prüfungen
Eine individuelle Prüfung erweitert die Prüfung eines bestimmten Business Entitys. Diese erweiterte Prüfung wird in allen Ein- und Ausgabekanälen verwendet, also sowohl in den Dialog-Anwendungen als auch beim Import oder Export. Sie können das Ergebnis dieser individuellen Prüfungen als individuelle Meldung ausgeben. Diese individuelle Meldung wird gemeinsam mit den Meldungen, die in der Repository-Datenbank erfasst sind, im jeweiligen Kontext angezeigt.
Die Anwendung Individuelle Prüfungen zeigt die Funktionen des ausgewählten Hook-Contracts an. So besitzt z. B. das Hook-Contract für Vertriebsaufträge folgende Funktionen.
function validateHeader( persistent as DataView(com.cisag.app.sales.order.model.SalesOrder), current as DataView(com.cisag.app.sales.order.model.SalesOrder)) { } function validateDetail( persistent as DataView(com.cisag.app.sales.order.model.SalesOrderDetail), current as DataView(com.cisag.app.sales.order.model.SalesOrderDetail)) { } function validateDeleteHeader( persistent as DataView(com.cisag.app.sales.order.model.SalesOrder)) { } function validateDeleteDetail( persistent as DataView(com.cisag.app.sales.order.model.SalesOrderDetail)) { }
Mithilfe der übergebenen Objektsichten
persistent
und current
können Sie die zu validierenden Änderungen in current
mit dem persistent gespeicherten Zustand des Business Objects in persistent
vergleichen. Bei manchen Hook-Contracts (wie z. B. Kampagnen) haben die Funktionen keinen Parameter current
. Um auch in solchen Fällen den gespeicherten Zustand des Business Entitys auszuwerten, können Sie das Business Entity mithilfe z. B. der Skriptfunktion getByPrimaryKey
öffnen, da viele der Attribute der Objektsicht auch im Business Entity vorhanden sind.
Besitzt ein Business Entity ein weiteres Feld, dann können Sie dessen Wert mithilfe einer weiteren Funktion mit dem gleichen Namen aber mit dem Suffix Extension_ gefolgt vom Schemanamen prüfen. Die Funktion umfasst einen zusätzlichen Parameter
extension
, der eine Hash-Tabelle mit den Namen und Werten aller weiteren Felder des Business Entity zur Verfügung stellt. Besitzt der Artikel ein weiteres Feld in der Basisansicht mit dem Namen EXTNUM und dem Feldtyp Text, dann könnte die Hash-Tabelle den Inhalt {EXTNUM_val=[S=], EXTNUM_id=[N=707070]}
haben.
Folgende Individuelle Prüfung gibt eine Fehlermeldung aus, wenn das weitere Feld EXTNUM leer ist:
function validate( view as DataView(com.cisag.app.general.item.model.Item)) { } function validateExtension_EXTItem( view as DataView(com.cisag.app.general.item.model.Item), extension as Extension_EXTItem) { if (extension.EXTNUM_val = "") sendMessage(extension.EXTNUM_id, "ERROR", list("No value.")); }
Wenn Sie das erste weitere Feld eines Business Entitys anlegen, nachdem Sie die individuelle Prüfung bereits erfasst haben, dann können Sie die individuelle Prüfung erneut erfassen, damit ein Muster für die zusätzliche Funktion mit dem Parameter
extension
automatisch generiert wird.
Informationsauswertung
Abhängig vom Initialisierungsstatus der neuen Aktivität werden die unterschiedlichen Variablen gefüllt. Beispielsweise ist zum Zeitpunkt der Auswertung der Übergangsbedingung und der Funktion
create
noch keine Aktivität vorhanden. Daher stehen die Werte der Variablen activity
nicht bzw. nur eingeschränkt zur Verfügung.
In den folgenden Kapiteln wird die Verwendung der zur Verfügung stehenden Variablen näher erläutert:
- Ereignis (event)
- Parameter (parameters)
- Prozess (process)
- Aktivität (activity)
- Aktivitätsdefinition (definition)
- Aktionsparameter (actionParameters)
- Aktivitätsergebnisse (results)
- Dialogsteuerung (dialog)
- Funktionsaufrufe (parameters und result)
- Hintergrundanwendungen (getJobResult)
- Webservices (getServiceResponse)
- Individuelle Prüfungen (environment)
Ereignis (event)
Besitzt die Aktivitätsdefinition einer Ereignisdefinition, dann enthält die Variable
event
eine Hash-Tabellle mit Informationen zum ausgelösten Ereignis.
Variable | Wert |
type type |
Die Variable type enthält den Ereignistyp. Die möglichen Werte sind im ValueSet com.cisag.sys.workflow.EventTypeLimited com.cisag.sys.workflow.EventTypeLimited definiert. Folgende Werte sind hier relevant:
|
subtype subtype |
Die Variable subtype subtype enthält den Subtyp des Ereignisses. Bei programmierten Ereignissen ist dies der Wert des ValueSet-Eintrags. Ist kein ValueSet dem Ereignis zugeordnet, dann ist der Wert null null . Beim Ereignistyp Business Entity sind die möglichen Wert im ValueSet com.cisag.sys.kernel.ObjectChangeType com.cisag.sys.kernel.ObjectChangeType definiert:
Beachten Sie bitte, dass das Setzen einer Löschmarkierung für ein Business Object als eine Änderung gilt. Erst beim Reorganisieren wird das Business Object aus der Datenbank gelöscht. var itemNumber := String; if (event.subtype = 3) itemNumber := parameters.oldObject:number; else itemNumber := parameters.newObject:number; format("itemNumber", itemNumber); var itemNumber := String;
if (event.subtype = 3)
itemNumber := parameters.oldObject:number;
else
itemNumber := parameters.newObject:number;
format("itemNumber", itemNumber); var itemNumber := String; if (event.subtype = 3) itemNumber := parameters.oldObject:number; else itemNumber := parameters.newObject:number; format("itemNumber", itemNumber); Wenn das Script beim Subtyp 3 parameters.object parameters.object oder parametrers.newObject parametrers.newObject auswertet, würde ein Laufzeitfehler entstehen, da das Business Object nicht mehr existiert. |
guid guid |
Die Variable guid guid enthält die GUID des programmierten Ereignisses oder die GUID des Business Objects beim Ereignis Business Entity.Um den vollständigen technischen Namen des Business Objects beim Ereignistyp Business Entity zu bestimmen, können Sie den Ausdruck objectName(event.guid) objectName(event.guid) verwenden. |
database database |
Die Variable database database enthält die GUID der Datenbank, in der das Ereignis ausgelöst wurde.Um den Namen der Datenbank zu bestimmen, können Sie den Ausdruck databaseName(event.database) databaseName(event.database) verwenden.Um den Namen des Systems zu ermitteln, können Sie in einer Deklaration, die JavaScript verwendet, Java.type('com.cisag.pgm.util.ServerInfo').getSystemName() Java.type('com.cisag.pgm.util.ServerInfo').getSystemName() aufrufen. Die Java-Methode Java.type('com.cisag.pgm.util.ServerInfo').getSVMName() Java.type('com.cisag.pgm.util.ServerInfo').getSVMName() gibt den den Namen des Servers zurück. |
parameters parameters |
Die Variable parameters parameters enthält eine Hash-Tabelle mit weiteren Informationen zum ausgelösten Ereignis. Welche Informationen parameters parameters enthält, ist je nach Typ und Subtyp des Ereignisses unterschiedlich:
Die Variable parameters parameters wird in Kapitel Parameter (parameters) näher erläutert. |
Parameter (parameters)
In Abhängigkeit des Typs und Subtyps des Ereignisses enthält die Variable
parameters
eine Hash-Tabelle mit weiteren Informationen zum ausgelösten Ereignis. Die Variable parameters
ist nur in Aktivitätsdefinitionen ohne Bezug zu einer Prozessdefinition sowie in Ereignisknoten verfügbar. Daher sollten Sie im Startknoten diejenigen Parameter, die Sie später im Prozess brauchen, in Prozessvariablen speichern.
Ereignistyp Programmiertes Ereignis
Programmierte Ereignisse besitzen genau diejenigen Parameter, die in der Anwendung Entwicklungsobjekte für das Ereignis eingetragen sind.
com.cisag.pgm.workflow.GenericOLTPEvent
besitzt die beiden Parameter name
und parameters
, die als String
bzw. HashMap
übergeben werden.
Soll nur dann eine Aktivität erzeugt werden, wenn der Name den gleichen Wert wie die Aktivitätsdefinition hat, dann kann die Übergangsbedingung
parameters.name = definition:code
verwendet werden.
Folgende Zuweisung übernimmt den Wert des Hash-Tabellen-Eintrags
user
als Prozessauslöser:
process.Initiator := cast(String, parameters.parameters.user);
Da die Hash-Tabelle untypisiert ist, müssen die Einträge mithilfe der Funktion
cast
in den korrekten Datentypen umgewandelt werden, bevor sie in den Deklarationen verwendet werden können.Ereignistyp Business Entity
Ein Ereignis des Typs Business Entity ist für Business Objects in der Repository-Datenbank oder der OLTP-Datenbank möglich. Welche Parameter das Ereignis besitzt, hängt vom Subtyp Einfügen, Ändern oder Löschen und vom Typ des überwachten Business Objects ab.
Variable | Wert |
userGuid userGuid |
Die Variable userGuid userGuid enthält die GUID des Benutzers, der das Business Object verändert hat.
Bei einem Ereignis des typs Business Entity ist der Prozessauslöser in process.Initiator process.Initiator automatisch vorbelegt. Folgende Zuweisung legt den Prozessauslöser auch als Prozessverantwortlicher fest:
process.Owner := userName(parameters.userGuid); process.Owner := userName(parameters.userGuid); |
object object |
Die Variable object object enthält eine Referenz auf das veränderte Business Object. Die Variable object object gibt den aktuellen Zustand des Business Objects zum Zeitpunkt der Auswertung wider. Beim Subtyp Löschen hat object object den Wert null null .Die Variable object object kann z. B. dazu verwendet werden, um den aktuellen Zustand des veränderten Business Objects beim Beginn des Bearbeitungszeitraumes auszuwerten.Folgende Vorbedingung prüft, ob der Beleg, für den das Ereignis ausgelöst wurde, freigegeben ist. Ist dies nicht der Fall, dann ist die Vorbedingung false und die Aktivität wird automatisch unbearbeitet erledigt: parameters.object:status = 2 /* ORDER_RELEASED */ parameters.object:status = 2 /* ORDER_RELEASED */ |
oldObject oldObject |
Die Variable oldObject oldObject enthält den Wert des veränderten Business Objects unmittelbar vor dem Auslösen des Ereignisses. Beim Subtyp Einfügen hat oldObject oldObject den Wert null null .
Folgende Übergangsbedingung prüft, ob das Attribut number number geändert wurde:
parameters.oldObject:number <> parameters.newObject:number parameters.oldObject:number <> parameters.newObject:number |
newObject newObject |
Die Variable newObject newObject enthält den Wert des veränderten Business Objects unmittelbar nach der Änderung. Beim Subtyp Löschen hat newObject newObject den Wert null null .
Folgende Vorbedingung prüft, ob zwischen dem Auslösen des Ereignisses und dem Beginn des Bearbeitungszeitraumes der Beleg bzw. das Business Object erneut verändert wurde: parameters.object:updateInfo.updateTime = parameters.newObject:updateInfo.updateTime parameters.object:updateInfo.updateTime = parameters.newObject:updateInfo.updateTime |
entity entity |
Ist das veränderte Business Object ein Dependent, dann enthält die Variable entity entity eine Referenz auf das mit dem Business Object über die Beziehung _entity _entity verküpfte Business Entity. Ob ein Business Object ein Dependent ist, können Sie in der Anwendung Entwicklungsobjekte sehen. Ist im Feld Typ der Wert Dependent ausgewählt, dann ist das Business Object ein Dependent.
Ein Beispiel für ein Dependent ist die Vertriebsauftragsposition. Besitzt eine Aktivitätsdefinition eine Ereignisdefinition für eine Vertriebsauftragsposition, dann referenziert parameters.object parameters.object das Business Object com.cisag.app.sales.obj.SalesOrderDetail com.cisag.app.sales.obj.SalesOrderDetail (Vertriebsauftragsposition) und parameters.entity parameters.entity das Business Object com.cisag.app.sales.obj.SalesOrder com.cisag.app.sales.obj.SalesOrder (Vertriebsauftrag).
Ist das Business Object kein Dependent, dann ist entity entity nicht definiert. Beim Subtyp Löschen hat entity entity den Wert null null . |
oldEntity oldEntity |
Ist das veränderte Business Object ein Dependent, dann enthält die Variable oldEntity oldEntity den Wert des mit dem Business Object über die Beziehung_entity _entity verküpften Business Entitys unmittelbar vor der Änderung.
Ist das Business Object kein Dependent, dann ist oldEntity oldEntity nicht definiert. Beim Subtyp Einfügen hat oldEntity oldEntity den Wert null null . |
newEntity newEntity |
Ist das veränderte Business Object ein Dependent, dann enthält die Variable newEntity newEntity den Wert des mit dem Business Object über die Beziehung _entity _entity verküpften Business Entitys unmittelbar nach der Änderung.
Ist das Business Object kein Dependent, dann ist newEntity newEntity nicht definiert. Beim Subtyp Einfügen hat newEntity newEntity den Wert null null . |
Ereignistyp Benutzeraktion
Ein Ereignis des Typs Benutzeraktion ist für Business Entitys in der Repository-Datenbank oder der OLTP-Datenbank möglich. Ereignisse für Dependents werden nicht unterstützt. Das Ereignis besitzt folgende Parameter.
Variable | Wert |
userGuid userGuid |
Die Variable userGuid userGuid enthält die GUID des Benutzers, der das Business Entity verändert hat.
Bei einem Ereignis des typs Benutzeraktion ist der Prozessauslöser in process.Initiator process.Initiator automatisch vorbelegt. Folgende Zuweisung legt den Prozessauslöser auch als Prozessverantwortlicher fest:
process.Owner := userName(parameters.userGuid); process.Owner := userName(parameters.userGuid);
Folgende Übergangsbedingung prüft, ob der Benutzer der zuständige Mitarbeiter des Belegs ist. Ist dies nicht der Fall, dann ist die Übergangsbedingung false false und die Benutzeraktion ist im Kontextmenü des Belegs für den Benutzer deaktiviert:
parameters.userGuid = cast(Guid, first(parameters.object:responsible, parameters.userGuid)) parameters.userGuid = cast(Guid, first(parameters.object:responsible, parameters.userGuid)) Hat der Beleg keinen zuständigen Mitarbeiter, dann bleibt die Benutzeraktion im Kontextmenü aller Benutzer aktiviert. |
object object |
Die Variable object object enthält eine Referenz auf das Business Entity, für das die Benutzeraktion ausgelöst wurde. Die Variable object object gibt den aktuellen Zustand des Business Entitys zum Zeitpunkt der Auswertung wider.
Folgende Übergangsbedingung prüft, ob ein Beleg in Bearbeitung ist. Ist dies nicht der Fall, dann ist die Übergangsbedingung false false und die Benutzeraktion ist im Kontextmenü des Belegs deaktiviert:
parameters.object:status = 1 /* ORDER_ENTERED */ parameters.object:status = 1 /* ORDER_ENTERED */ |
Ohne Ereignisdefinition
Ein Prozess ohne Ereignisdefinition im Startknoten kann nur manuell gestartet werden. Um im Startknoten entscheiden zu können, ob der Benutzer berechtigt ist, den Prozess zu starten, stellt die Variable
parameters
auch dann relevante Informationen zur Verfügung, wenn kein Ereignis vorliegt.
Variable | Wert |
userGuid userGuid |
Die Variable userGuid userGuid enthält die GUID des Benutzers, der den Prozess manuell startet.
Folgender Ausdruck im Feld Ausdruck für Vorbedingung unterbindet den Prozessstart, wenn der Benutzer der Workflowrolle MANAGERS nicht zugeordnet ist. contains(resolveRole("MANAGERS", parameters.userGuid) contains(resolveRole("MANAGERS", parameters.userGuid) |
database database |
Die Variable database database enthält die GUID der Datenbank, in der der Prozess gestartet wird. Siehe Kapitel Ereignis (event) für Anwendungsbeispiele. |
organization organization |
Die Variable organization organization enthält bei einem manuell gestarteten Prozess die GUID der in der Anwendung ausgewählten Organisation, aus welcher der Prozess gestartet wurde. |
Prozess (process)
Ist die Aktivitätsdefinition mit einer Prozessdefinition verknüpft dann enthält die Variable
process
eine Hash-Tabellle mit Informationen zum Prozess.
Variable | Beschreibung |
Code Code |
Die Variable Code Code enthält die Identifikation des Prozesses. |
Database Database |
Die Variable Database Database enthält die GUID der Datenbank. Diese Variable ist nur in der Funktion create create eines Startknotens verfügbar. |
Description Description |
Die Variable Description Description enthält die Bezeichnung des Prozesses. |
EndTime EndTime |
Die Variable EndTime EndTime enthält den Zeitpunkt für das Ende des Bearbeitungszeitraums. |
ErrorCode ErrorCode |
Die Variable ErrorCode ErrorCode enthält den Fehlercode, nachdem ein Fehler im Prozess aufgetreten ist. Eine Auswertung ist daher nur im Fehlerknoten sinnvoll.
Der Fehlercode und die Fehlerbeschreibung können per Zuweisung gesetzt werden. Anschließend kann der Befehl abortProcess abortProcess verwendet werden, um den Prozess über den Fehlerknoten zu beenden.
process.ErrorCode := "USER_ERROR"; process.ErrorDescription := "Error raised by user in create() of activity " + activity:code + "."; abortProcess(); process.ErrorCode := "USER_ERROR";
process.ErrorDescription := "Error raised by user in create() of activity " + activity:code + ".";
abortProcess(); process.ErrorCode := "USER_ERROR"; process.ErrorDescription := "Error raised by user in create() of activity " + activity:code + "."; abortProcess(); |
ErrorDescription ErrorDescription |
Die Variable ErrorDescription ErrorDescription enthält die zum Fehlercode zugehörige Fehlerbezeichnung, nachdem ein Fehler im Prozess aufgetreten ist. Eine Auswertung ist daher nur im Fehlerknoten sinnvoll. |
FinishTime FinishTime |
Die Variable FinishTime FinishTime enthält den Erledigungszeitpunkt des Prozesses. |
Initiator Initiator |
Die Variable Initiator Initiator enthält den Prozessauslöser. Der Prozessauslöser steht erst ab der Funktion close close des Startknotens zur Verfügung. Der Prozessauslöser wird bei Ereignissen des Typs Business Entity und Benutzeraktion automatisch gesetzt. Beim Ereignistyp Programmiertes Ereignis sowie bei Prozessen ohne Ereignisdefinition kann der Prozessauslöser nur per Zuweisung eines Benutzernamens festgelegt werden.
process.Initiator := userName(getByBusinessKey(CisObject(com.cisag.app.inventory.obj.InventoryTransaction), parameters.internalNumber):updateInfo.createUser) process.Initiator := userName(getByBusinessKey(CisObject(com.cisag.app.inventory.obj.InventoryTransaction), parameters.internalNumber):updateInfo.createUser) weist dem Prozess denjenigen Benutzer als Auslöser zu, der die Materialbuchung erfasst bzw. erzeugt hat, welche das programmierte Ereignis com.cisag.app.inventory.MinimumOnhand com.cisag.app.inventory.MinimumOnhand ausgelöst hat.
Der Auslöser kann während der Ausführung des Prozesses beliebig geändert werden. |
Number1 Number1 |
Die Variable Number1 Number1 enthält das erste allgemeine numerische Ergebnisattribut. Der Wert kann durch Zuweisung beliebig geändert werden.
process.Number1 := parameters.object:totalValues.grossValue.amount process.Number1 := parameters.object:totalValues.grossValue.amount weist dem Attribut Number1 Number1 den Brutto-Gesamtbetrag eines von parameters.object parameters.object referenzierten Beschaffungsauftrags zu. |
Number2 Number2 |
Die Variable Number2 Number2 enthält das zweite allgemeine numerische Ergebnisattribut. Der Wert kann durch Zuweisung beliebig geändert werden. |
OrganizationalUnit OrganizationalUnit |
Die Variable OrganizationalUnit OrganizationalUnit enthält die GUID der Organisation. Der Organisationskontext des Ereignisses kann per Zuweisung auf den Prozess übertragen werden. Die zugeordnete Organisation hat u. a. Auswirkungen auf die Berechtigung unbeteiligter Benutzer. Ist in der Prozessdefinition die Fähigkeit Standard für unbeteiligte Benutzer ausgewählt und die Aktivität ist einer Organisation zugeordnet, dann können nur solche unbeteiligte Benutzer den Prozess anzeigen, die derselben Organisation zugeordnet sind. |
Owner Owner |
Die Variable Owner Owner enthält den Prozessverantwortlichen. Der Prozessverantwortliche steht erst in der Funktion close close des Startknotens zur Verfügung. Bei einem manuellen Prozess mit Aktivitätsergbnissen im Startknoten, kann der Owner in den Funktionen applyDefaults applyDefaults und validate validate nicht ausgewertet werden.
Der Wert kann durch Zuweisung eines Benutzernamens oder der Identifikation einer Workflowrolle geändert werden. process.Owner := process.Initiator process.Owner := process.Initiator weist dem Prozess den Auslöser auch als Verantwortlicher zu.
Die Herkunft des Prozessverantwortlichen kann im Attribut activity->Process:processData.sourceOfOwner activity->Process:processData.sourceOfOwner abgefragt werden. Der Wert 1 steht für Benutzer und der Wert 2 für Workflowrolle. |
previousStep previousStep |
Wenn die Aktivität nur eine einzige Vorgängeraktivität hat, dann enthält die Variable previousStep previousStep eine Referenz auf die Vorgängeraktivität. Wenn die Aktivität keine Vorgängeraktivität hat, was z. B. für den Startknoten der Fall ist, oder mehrere Vorgängeraktivitäten hat, dann besitzt die Variable den Standardwert null null .
Der Ausdruck process.previousStep:completeUser process.previousStep:completeUser gibt die GUID desjenigen Benutzers zurück, der mit seiner Aufgabe die Vorgängeraktivität erledigt hat. Beachten Sie bitte, dass der Name dieses Attributs mit einem Kleinbuchstaben anfängt. |
previousSteps previousSteps |
Wenn die Aktivität mehrere Vorgängeraktivitäten hat, z. B. durch die Verwendung eines Zusammenführungsknotens, enthält die Variable previousSteps previousSteps eine Liste mit einer Referenz für jede Vorgängeraktivität. Wenn die Aktivität keine oder nur eine einzige Vorgängeraktivität hat, dann hat die Variable den Standardwert null null .
Folgendes Skript weist der Variable users users eine Liste mit den GUIDs aller Benutzer zu, die mit ihrer Aufgabe eine Vorgängeraktivität erledigt haben.
var users as Guid[]; for (a : process.previousSteps) users := union(users, list(a:completeUser)); var users as Guid[];
for (a : process.previousSteps)
users := union(users, list(a:completeUser)); var users as Guid[]; for (a : process.previousSteps) users := union(users, list(a:completeUser)); Beachten Sie bitte, dass der Name dieses Attributs mit einem Kleinbuchstaben anfängt. |
StartTime StartTime |
Die Variable StartTime StartTime enthält den Zeitpunkt für den Beginn des Bearbeitungszeitraums. |
State State |
Die Variable State State enthält den Prozessstatus. |
Result Result |
Die Variable Result Result enthält das allgemeine Prozessergebnis. Der Wert kann durch Zuweisung beliebig geändert werden, ist aber auf 80 Zeichen limitiert.
Folgende Zuweisung in der Funktion close close fasst viele Einzelergebnisse eines Genehmigungsprozesses für den in der Prozessvariablen „PO“ referenzierten Beschaffungsauftrag zu einem allgemeinen Prozessergebnis zusammen:
process.result := process.PO:number + " submitted by " + process.Initiator + " was " + results.approvalResult + " by " + userName(activity:completeUser); process.result := process.PO:number + " submitted by " + process.Initiator + " was " + results.approvalResult + " by " + userName(activity:completeUser); Das Ergebnis der Prüfung befindet sich im Aktivitätsergebnis approvalResult approvalResult . |
Text1 Text1 |
Die Variable Text1 Text1 enthält das erste allgemeine Ergebnisattribut für Zeichenketten. Der Wert kann durch Zuweisung beliebig geändert werden.
process.Text1 := "APPROVED" process.Text1 := "APPROVED" |
Text2 Text2 |
Die Variable Text2 Text2 enthält das zweite allgemeine Ergebnisattribut für Zeichenketten. Der Wert kann durch Zuweisung beliebig geändert werden. |
Text3 Text3 |
Die Variable Text3 Text3 enthält das dritte allgemeine Ergebnisattribut für Zeichenketten. Der Wert kann durch Zuweisung beliebig geändert werden. |
Text4 Text4 |
Die Variable Text4 Text4 enthält das vierte allgemeine Ergebnisattribut für Zeichenketten. Der Wert kann durch Zuweisung beliebig geändert werden. |
Text5 Text5 |
Die Variable Text5 Text5 enthält das fünfte allgemeine Ergebnisattribut für Zeichenketten. Der Wert kann durch Zuweisung beliebig geändert werden. |
Timestamp1 Timestamp1 |
Die Variable Timestamp1 Timestamp1 enthält das erste allgemeine Ergebnisattribut für Zeitpunkte. Der Wert kann durch Zuweisung beliebig geändert werden.
process.Timestamp1 := now(); process.Timestamp1 := now(); |
Timestamp2 Timestamp2 |
Die Variable Timestamp2 Timestamp2 enthält das zweite allgemeine Ergebnisattribut für Zeitpunkte. Der Wert kann durch Zuweisung beliebig geändert werden. |
Je nach Ausführungskontext und Aktivitätsstatus stehen unterschiedliche Attribute zur Verfügung. In den Funktionen
applyDefaults
und validate
eines Startknotens besitzen alle Attribute noch ihre Standardwerte. Da der Startknoten keinen Vorgänger hat, besitzen die Attribute previousStep
und previousSteps
immer den Standardwert null
in einem Startknoten.
In der Funktion
create
eines Startknotens besitzen die Attribute OrganizationalUnit
und Database Werte aus dem aktuellen Kontext. Um diese Attribute auch in den Funktionen applyDefaults
und validate
eines Startknotens abzufragen, können Sie stattdessen die Variablen event
und parameters
auswerten.
In der Funktion
close
eines Startknotens sowie in allen Funktionen der darauf folgenden Aktivitäts- und Ereignisknoten besitzen sämtliche Attribute außer OrganizationalUnit
und Database
Werte aus dem aktuellen Kontext. Möchten Sie diese beiden Werte zu einem späteren Zeitpunkt im Prozess auswerten, sollten Sie sie in der Funktion close
in Prozessvariablen speichern.
Aktivität (activity)
Wenn die Übergangsbedingung erfüllt ist und die Funktion
create
ausgeführt wurde, wird die neue Aktivität erzeugt. Ab diesem Zeitpunkt stellt die Variable activity
eine Referenz auf die erzeugte Aktivität zur Verfügung.
Um die Auswertung zu vereinfachen, stehen einige Attribute bereits in der Funktion
create
zur Verfügung. So können Sie z. B. die Identifikation und den Status der Aktivität auswerten. Andere Informationen, wie z. B. Beziehungen zu anderen Business Objects, lassen sich erst nach dem Ausführen der Funktion create
auswerten.
Aus dem gleichen Grund stehen einige Attribute in der Funktion
close
zur Verfügung, die erst nach dem Erledigen der Aktivität persistent gespeichert werden. So können Sie z. B. mithilfe des Attributs activity:completeUser
auswerten, welcher Benutzer die Aktivität gerade erledigt.
Nach der Ausführung der Funktion
create
können Sie den Prozess über die Beziehung Process auswerten. So bestimmt z. B. der Ausdruckactivity->Process:code
die Identifikation des Prozesses.
Aktivitätsdefinition (definition)
Die Variable
definition
enthält eine Referenz auf die Aktivitätsdefinition, die das Ereignis empfangen hat und mit der die neue Aktivität erzeugt werden soll. Diese Variable steht überall in einer Aktivitätsdefinition zur Verfügung.
Mithilfe der Übergangsbedingung
parameters.name = definition:code
in einer Aktivitätsdefinition für das programmierte Ereignis com.cisag.pgm.workflow.GenericOLTPEvent
kann das programmierte Ereignis mit der Identifikation derjenigen Aktivitätsdefinition als Name ausgelöst werden, die zum Generieren der Aktivität verwendet werden soll.
Über die Variable
definition
kann auch die mit der Aktivitätsdefinition verknüpfte Prozessdefinition ausgewertet werden. So bestimmt z. B. der Ausdruckdefinition->ProcessDefinition:code
die Identifikation der Prozessdefinition.
Aktionsparameter (actionParameters)
Wenn die Funktion
create
ausgeführt und die Aktivität erzeugt wurde, dann enthält die die Variable actionParameters
eine Hash-Tabelle mit den Werten aller Anwendungsparameter. Diese Variable kann z. B. in einer Vorbedingung oder in der Funktion close
ausgewertet werden.
Aktivitätsergebnisse (results)
Wenn die Funktion
create
ausgeführt und die Aktivität erzeugt wurde, dann enthält die die Variable results
eine Hash-Tabelle mit den Werten aller Aktivitätsergebnisse. Die Variable results
wird oft in der Funktion close
verwendet, um die Aktivitätsergebnisse in Prozessvariablen zu speichern.
- approvalStatus
approvalStatus
vom Feldtyp Auswahlfeld mit den beiden Werten APPROVED und REJECTED. - comment
comment
vom Feldtyp Mehrzeiliges Textfeld.
In der Funktion applyDefaults wird das Auswahlfeld approvalStatus mit REJECTED vorbelegt:
function applyDefaults() { results.approvalStatus := "REJECTED"; }
In der Funktion
validate
wird die individuelle Meldung COMMENT ausgegeben, wenn der Benutzer den Wert APPROVED ausgewählt hat, ohne einen Kommentar zu erfassen:
function validate(state as Number) { if (results.approvalStatus <> "APPROVED" and results.comment = "") sendMessage(results.comment_id, "COMMENT", list()); }
Das Suffix
_id
hinter dem Namen des Aktivitätsergebnisses bewirkt, dass die farbige Ecke für die Meldung im Kommentarfeld erscheint.
In der Funktion
close
werden schließlich die beiden Aktivitätsergebnisse in gleichnamigen Prozessvariablen gespeichert:
function close(state as Number) { if(results.approvalStatus = "APPROVED") process.approvalStatus := "APPROVED"; else process.approvalStatus := "REJECTED"; process.comment := results.comment; }
Danach können andere Aktivitäten im Prozess die Werte verwenden.
In dem obigen Beispiel wäre auch die einfachere Zuweisung
process.approvalStatus := results.approvalStatus
möglich. Der Unterschied ist, dass durch eine solche Zuweisung die Prozessvariable process.approvalStatus
ein undefiniertes Ergebnis hätte, wenn der Benutzer die Aufgabe oder die Aktivität durch eine Cockpit-Anwendung erledigt, da in diesem Fall keine Eingabe von Ergebnissen möglich ist.
Eine weitere Variante wäre, das Aktivitätseregbnis abhängig vom Status der Aktivität zuzuweisen: erledigt der Benutzer die Aktivität durch eine Cockpit-Anwendung, gilt dies als eine implizite Genehmigung. Wird die Aktivität unbearbeitet erledigt, dann gilt dies als eine implizite Ablehnung:
function close(state as Number) { if(results.approvalStatus = "APPROVED") process.approvalStatus := "APPROVED"; else if(results.approvalStatus <> "") process.approvalStatus := "REJECTED"; else if (state = State:DONE) process.approvalStatus := "APPROVED"; else process.approvalStatus := "REJECTED"; }
Es ist auch möglich, im Feld Erledigungsbestätigung auf dem Karteireiter Bearbeitung der Aktivitätsdefinition den Wert Erledigen durch Workflow-Symbolleiste auszuwählen, um das Erledigen durch eine Cockpit-Anwendung zu unterbinden.
Dialogsteuerung (dialog)
Besitzt die Aktivitätsdefinition ein Aktivitätsergebnis des Feldtyps Seite, dann besteht der Dialog Aktivitätsergebnisse eingeben aus mehreren Seiten. Um per Scripting zwischen den Seiten wechseln zu können, stellt die Variable
parameters
folgende Attribute zur Verfügung:
Variable | Beschreibung |
page page |
Die Variable page page enthält den technischen Namen der aktuellen Seite im Dialog Aktivitätsergebnisse eingeben. Ist die aktuelle Seite die erste Seite des Dialogs, dann ist der Wert von page page eine leere Zeichenkette. |
nextPage nextPage |
Wird der Variable nextPage nextPage der technische Name eines Aktivitätsergbnisses des Feldtyps Seite zugewiesen, und diese Seite befindet sich nach der aktuellen Seite, dann wechselt der Dialog direkt zu dieser Seite, auch wenn andere Seiten dadurch übersprungen werden müssen. Es ist nicht möglich, auf der gleichen Seite zu bleiben oder zu einer Seite zu wechseln, die sich vor der aktuellen Seite befindet. |
Im folgenden Beispiel besitzt eine Aktivitätsdefinition vier Dialogseiten mit den Namen page1, page2, page3 und page4. Jede Seite besitzt ein Textfeld mit den Namen text1, text2, text3 und text4. Ist das Textfeld auf einer Seite leer, dann soll nicht zur darauf folgenden Seite sondern direkt zur letzten Seite page4 gewechselt werden.
function validate(state as Number) { if (dialog.page = "page1" or dialog.page = "") { if (results.text1 = "") dialog.nextPage := "page4"; } if (dialog.page = "page2") { if (results.text2 = "") dialog.nextPage := "page4"; } }
Eine Prüfung auf der Seite page3 ist nicht erforderlich, da die Seite page4 ohnehin die nächste Seite ist.
Funktionsaufrufe (parameters und result)
Ein Funktionsaufruf ist eine Aktivitätsdefinition, die statt Aktivitäten zu erzeugen ein Ergebnis berechnet und zurückgibt. Funktionsaufrufe werden z. B. eingesetzt, um komplexe Berechnungen einmalig zu erfassen oder Ausdrücke in JavaScript auch in Aktivitätsdefinitionen verwenden zu können, die in der System-Skriptsprache erfasst sind.
Die Parameter und Rückgabewerte von Aktivitätsdefinitionen des Typs Funktionsaufruf werden mit der Aktivitätsdefinition erfasst. Jeder Parameter und jeder Rückgabewert hat in der Aktivitätsdefinition die folgenden Eigenschaften:
- Einen innerhalb der Aktivitätsdefinition eindeutigen technischen Namen
- Eine übersetzbare Bezeichnung
- Einen Datentyp
Für jeden Parameter P1,…,Pn und Rückgabewert R1,…,Rm gibt es eine Variable mit dem technischen Namen in den Variablen
parameters
und result
, d.h.:
parameters.P1,…,parameters.Pn result.R1,…,result.Rm
Die Werte der Parameter werden beim Aufruf der Aktivitätsdefinition übergeben und gesetzt. Die Werte der Rückgabewerte sind beim Aufruf
null
und können durch die Aktivitätsdefinition berechnet werden.
ITEMNUMBER
mit der Bezeichnung Artikelnummer und dem Datentyp Zeichenkette sowie den Rückgabewert PRICE
mit der Bezeichnung Preis und dem Datentyp Nummer. In diesem Fall gibt es die folgenden Variablen:
parameters.ITEMNUMBER result.PRICE
Der Wert der Variablen
ITEMNUMBER
wird beim Aufruf der Aktivitätsdefinition gesetzt. Der Wert der Variablen PRICE
muss durch die Aktivitätsdefinition gesetzt werden.Beachten Sie bitte, dass in einer Aktivitätsdefinitionen des Typs Funktionsaufruf die üblichen Umgebungsvariablen für die Datenbank und den Benutzer nicht zur Verfügung stehen, da solche Aktivitätsdefinitionen in der Regel nicht interaktiv durch einen Benutzer beendet werden.
Hintergrundanwendungen (getJobResult)
Der Knotentyp Serviceknoten wird in Prozessdefinitionen verwendet, um eine Aktivität zu erzeugen, die eine Hintergrund-Anwendung aufruft. Ein Serviceknoten wird von einem Verarbeitungsauftrag bearbeitet. Auch in einer Aktivitätsdefinition des Typs Einzelaktivität kann Verarbeitungsauftrag als Bearbeiter ausgewählt werden.
In der Funktion
close
kann die Skriptfunktion getJobResult
verwendet werden, um die Ergebnisse der aufgerufenen Hintergrundanwendung auszuwerten, vorausgesetzt die Aktivität wartet auf den Verarbeitungsauftrag, entweder durch das Aktivieren der Checkbox Auf Verarbeitungsauftrag warten in dem Karteireiter Bearbeitung oder durch den Befehl setJobWaitFinish(true)
in der Funktion create
.
Die Funktion
getJobResult
übergibt eine Hash-Tabelle mit den Variablenwerten, die hinter CisParameterList: auf dem Karteireiter Ausführung im Eigenschaftendialog des Verarbeitungsauftrags stehen.
com.cisag.app.inventory.physical.log.PhysicalInventoryCountProcessing
und Aktion CreateCountLists) hat folgende Ausführungsergebnisse:
CisParameterList: {batchJobGuids:null} {com.cisag.pgm.base.CisApplicationCallResult:true} {nextAction:0} {nextParameters:null} {outQueueEntryGuids:null} {result:1} {resultParmeters:CisParameterList: {ResultNumberOfSuccessfulResults:1} {ResultPhysicalInventoryCountListGuids:[[B@22833e99]}} {state:2} {waitingResult:0}
Wenn eine Aktivität auf den Verarbeitungsauftrag wartet, dann könnte
getJobResult
folgende Hash-Tabelle zurückgeben:
{batchJobGuids=[103=null], com.cisag.pgm.base.CisApplicationCallResult=[B=true], nextAction=[N=0], nextParameters=[103=null], outQueueEntryGuids=[103=null], result=[N=1], resultParmeters=[H={ResultNumberOfSuccessfulResults=[N=1], ResultPhysicalInventoryCountListGuids=[L=[[G=0080EED3CBFB2E10B118AD1BAABC0000]]]}], state=[N=2], waitingResult=[N=0]}
Die eigentlichen Ergebnisse der aufgerufenen Hintergrundanwendung befinden sich im Variablen
resultParmeters
. (Bitte auf die Schreibweise achten!). Folgendes Skript in der Funktion close
wertet diese aus, öffnet die generierten Inventurzähllisten und gibt deren Identifikation ins Protokoll aus:
function close(state as Number) { var rp as HashMap; var cls as Number; /* number of count lists generated */ var clGuids as Guid[]; /* list of count list GUIDs */ var cl as CisObject(com.cisag.app.inventory.physical.obj.PhysicalInventoryCountList); rp := cast(HashMap, getJobResult().resultParmeters); cls := cast(Number, rp.ResultNumberOfSuccessfulResults); clGuids := cast(Guid[], rp.ResultPhysicalInventoryCountListGuids); echo(format(cls, "0") + " count list(s) generated:"); for (g : clGuids) { cl := getByPrimaryKey(CisObject(com.cisag.app.inventory.physical.obj.PhysicalInventoryCountList), g); echo(cl->PhysicalInventory->Type:code + "-" + cl->PhysicalInventory:number + " " + cl:number); } }
Webservices (getServiceResponse)
Der Knotentyp Webservice-Knoten wird in Prozessdefinitionen verwendet, um einen externen Webservice mit Hilfe der Hintergrundanwendung Service-Client aufzurufen. Die Hintergrundanwendung nutzt das HTTP-Protokoll und kann per JSON/REST und XML/SOAP externe Webservices aufrufen.
In der Funktion
close
kann die Skriptfunktion getServiceResponse
verwendet werden, um die Ergebnisse auszuwerten. Die Funktion gibt den Ergebnisparameter responseBody der Hintergrundanwendung als eine Zeichenkette zurück. Die Funktion ist eine kompaktere Schreibweise für den Ausdruck getJobResult()["resultParmeters"]["responseBody"]
. Voraussetzung einer Auswertung ist, dass die Aktivität auf den Verarbeitungsauftrag wartet, entweder durch das Aktivieren der Checkbox Auf Verarbeitungsauftrag warten auf dem Karteireiter Bearbeitung oder durch den Befehl setJobWaitFinish(true)
in der Funktion create
. Je nach ausgewählter Aktion der Hintergrundanwendung (JSON oder XML) können Sie die Funktionen parseJson
oder parseXml
verwenden, um die von getServiceResponse
zurückgegebene Zeichenkette in eine Hash-Tabelle umzuwandeln.
Folgendes Beispiel gibt die vier Ergebnisvariablen data, errors, promise, und ready einer Aktivitätsdefinition des Typs Webservice-Knoten ins Protokoll aus:
function close(state as Number) { var response := parseJson(getServiceResponse()); echo((cast(HashMap, response.data)); echo((cast(String[],response.errors)); echo((cast(Guid, response.promise)); echo((cast(Boolean, response.ready)); }
Individuelle Prüfungen (environment)
Zusätzlich zu den übergebenen Parametern der Funktionen stellt eine individuelle Prüfung die Variable
environment
mit dem Wert userGuid
zur Verfügung. Mithilfe dieser Variable können Sie auswerten, für welchen Benutzer das Business Entity validiert wird. Folgendes Beispiel erlaubt nur dem zuständigen Mitarbeiter eines Beschaffungsauftrags sowie den der Workflowrolle MANAGERS zugeordneten Benutzern, Beschaffungsaufträge freizugeben. Für alle anderen Mitarbeiter bleibt die Freigabe unterbunden.
function validateHeader( persistent as DataView(com.cisag.app.purchasing.order.model.PurchaseOrder), current as DataView(com.cisag.app.purchasing.order.model.PurchaseOrder)) { const OrderStatus as valueSet(com.cisag.app.general.OrderStatus); if ((persistent:status=OrderStatus.ORDER_ENTERED or persistent:status=OrderStatus.ORDER_HELD or persistent:status=OrderStatus.ORDER_CANCELED or (persistent:status=OrderStatus.ORDER_INVALID and persistent:statusBackup=OrderStatus.ORDER_RELEASED)) and current:status=OrderStatus.ORDER_RELEASED) { var authorizedUsers := resolveRole("MANAGERS"); if (not isNull(persistent:responsible)) authorizedUsers := union(authorizedUsers, list(persistent:responsible)); if (not contains(authorizedUsers, environment.userGuid)) sendMessage(null, "ERROR", "No authorization to release."); } }
Beachten Sie bitte, dass das Attribut
statusBackup
verwendet wird, wenn der Beschaffungsauftrag mehr Positionen umfasst, als in einer Datenbank-Transaktion freigegeben werden können. In diesem Fall wird mit der ersten Datenbank-Transaktion der Status des Beschaffungsauftrags auf Ungültig geändert, und das Attribut statusBackup
bekommt den künftigen Status Freigegeben zugewiesen. Erst mit der letzten Datenbank-Transaktion wird der Status des Beschaffungsauftrags auf Freigegeben geändert.
Fehlerbehandlung
Komplexität von Ausdrücken beschränken
Die System-Skriptsprache ist für längere Berechnungen oder die Verarbeitung von größeren Datenmengen ungeeignet. Aus diesem Grund wird die Laufzeit von Bedingungen und Befehlen beschränkt.
Die Standardeinstellungen sind:
Operation | Beschränkung | Erläuterung |
while while |
1.000.000 | while while -Schleifen brechen nach 1.000.000 Durchläufen ab. |
getResultList getResultList
getCisObjectList getCisObjectList |
10.000 | getResultList getResultList und getCisObjectList getCisObjectList können bis zu 10.000 Zeilen oder Objekte abfragen. |
call call
@ @ |
100 | call call und @ @ können maximal 100 Mal rekursiv Aktivitätsdefinitionen aufrufen. Der Vorschlagswert kann nicht verändert werden. |
Mit der System-Property
com.cisag.pgm.workflow.MaxExpressionComplexity
können Sie die Prüfung der Komplexität verändern. Der Vorschlagswert ist 1.000. Die Grenzwerte aller Operationen bis auf die Begrenzung der Rekursionstiefe sind linear vom Wert dieser Property abhängig. Mit dem Wert 0 schalten Sie die Prüfung vollständig ab.
Behandlung von Laufzeitfehlern
Einige Fehler in Ausdrücken können bei der Prüfung des Skripts nicht erkannt werden.
a/b
liefert einen Fehler, wenn b=0.Laufzeitfehler in der Workflow-Engine haben die Meldungsklasse WFL. Fehler, die bei der Auswertung der Ausdrücke auftreten, werden abhängig von der Aktivitätsdefinition in das OLTP- oder Repository-Protokoll geschrieben. Das OLTP- bzw. Repository-Protokoll kann mit der Anwendung Meldungsprotokolle abgefragt werden. Wenn die Vorbedingung fehlerhaft ist, dann wird abhängig von der Aktivität eine Meldung in das OLTP- oder Repository-Protokoll geschrieben. Die Aktivität wird jedoch so behandelt, als ob die Vorbedingung erfüllt wäre.
Bei Fehlern in der Übergangsbedingung, der Berechnung der Bearbeiter oder im Befehlsblock wird keine neue Aktivität erzeugt. Eine Meldung wird in das Systemprotokoll geschrieben. Das Meldungsprotokoll sollte in regelmäßigen Abständen auf Fehler kontrolliert werden, insbesondere dann, wenn Aktivitätsdefinitionen verändert oder neu erfasst wurden.
Erweiterung der System-Skriptsprache
Über eine vorgegebene Programmierschnittstelle kann die System-Skriptsprache um neue Befehle und Funktionen erweitert werden. Insbesondere wenn komplexe Bedingungen geprüft werden sollen, erreichen Sie schnell die Grenzen der Skriptsprache im Bezug auf die Ausdrucksfähigkeit oder Leistungsfähigkeit. In diesem Fall können Sie die Probleme über spezialisierte Funktionen beheben.
Weitere Informationen finden Sie im Kapitel Erweitern der Skriptsprache der Dokumentation Schnittstellen zum Workflow-Management.