Workflow Engine
De Ultimo workflow engine is het mechanisme waarmee alle bedrijfslogica wordt uitgevoerd. Workflows zijn XML-gebaseerde definities die bepalen wat er gebeurt bij statuswijzigingen, imports, geplande taken en gebruikersacties. Elke workflow bevat properties, security-instellingen en een execution-blok met instructies.
Wat is een workflow?bewerken
Een workflow in Ultimo is een XML-bestand dat bedrijfslogica definieert. Workflows worden automatisch uitgevoerd door de engine op basis van triggers (events). Ze kunnen:
- Velden vullen of berekenen
- Validaties uitvoeren
- Records aanmaken, wijzigen of verwijderen
- Emails en reminders versturen
- Dialogen tonen aan de gebruiker
- Andere workflows aanroepen
Workflow naamgevingbewerken
Workflows volgen een strikte naamconventie: {EntityName}_{TriggerType}. Voorbeelden:
| Workflow naam | Betekenis |
|---|---|
Job_PreApproved |
Wordt uitgevoerd VOOR de status van Job naar Approved gaat |
Job_PostApproved |
Wordt uitgevoerd NA de status van Job naar Approved is gegaan |
Job_PreImport |
Wordt uitgevoerd VOOR het importeren van een Job record |
Job_PostImport |
Wordt uitgevoerd NA het importeren van een Job record |
Job_PreDelete |
Wordt uitgevoerd VOOR het verwijderen van een Job |
Job_PreTrash |
Wordt uitgevoerd VOOR het naar prullenbak verplaatsen van een Job |
Job_PostTrash |
Wordt uitgevoerd NA het naar prullenbak verplaatsen van een Job |
Job_PreOpen |
Wordt uitgevoerd VOOR het openen van een Job record |
Job_PostOpen |
Wordt uitgevoerd NA het openen van een Job record |
Trigger typesbewerken
Statuswijzigingen (Pre/Post)bewerken
De meest voorkomende trigger. Voor elke statusovergang in de Status Matrix worden Pre- en Post-workflows uitgevoerd:
- Pre-workflows (
_Pre{Status}) - Worden uitgevoerd VOOR de statuswijziging. Geschikt voor: - Validaties (mag deze overgang plaatsvinden?)
- Voorbereidende acties
- Gebruikersinvoer verzamelen
- Post-workflows (
_Post{Status}) - Worden uitgevoerd NA de statuswijziging. Geschikt voor: - Vervolgacties (jobs aanmaken, emails sturen)
- Gerelateerde records bijwerken
- Notificaties versturen
Import workflows (PreImport/PostImport)bewerken
Worden getriggerd bij het importeren van data via connectors:
- PreImport - Kan het record manipuleren of overslaan (
SkipRecord = True) - PostImport - Kan vervolgacties uitvoeren na import, inclusief statuswijzigingen
Typische properties bij import workflows:
<Property Name="Job" Type="Job" Accessor="Optional" Direction="In" />
<Property Name="ChangeStatusTo" Type="Status?" Accessor="Optional" Direction="In" />
<Property Name="ConnectorAction" Type="ConnectorAction?" Accessor="Optional" Direction="In" />
<Property Name="PropertyValues" Type="Dictionary[Object]" Accessor="Optional" Direction="In" />
<Property Name="SkipRecord" Type="Boolean" Accessor="Optional" Direction="Out" Default="False" />
Delete en Trash workflowsbewerken
- PreTrash - Validatie of trash toegestaan is
- PostTrash - Opruimacties na trash
- PreDelete - Gerelateerde objecten verwijderen voor definitieve delete
De volgorde bij een delete is: PreTrash -> status naar Trash -> PostTrash -> PreDelete -> daadwerkelijke delete.
Open workflows (PreOpen/PostOpen)bewerken
Worden uitgevoerd bij het openen van een record in de UI:
- PreOpen - Kan initialisatielogica bevatten
- PostOpen - Kan berekeningen of controles uitvoeren
Scheduled workflowsbewerken
Workflows die op een vast tijdschema worden uitgevoerd via de scheduler in UCT. Deze hebben geen directe entity-trigger maar worden periodiek aangeroepen.
Standaard workflows (Standard type)bewerken
Workflows van het type Standard zijn herbruikbare logica-blokken die door andere workflows worden aangeroepen via WorkflowCall.
XML structuurbewerken
Elke workflow heeft dezelfde basisstructuur:
<Workflow Name="Job_PostApproved" Version="2025.07.28" WorkflowType="ChangeStatus"
AllowUserInteraction="False"
xmlns="urn:Ultimo.Framework.Workflow-mapping">
<Security EditLevel="10" ViewLevel="20" UserContentLevel="30" />
<Description>Post approved Job</Description>
<Properties>
<Property Name="Job" Type="Job" Accessor="Root" Direction="In" />
<Property Name="Counter" Type="Int32" Accessor="Internal" Default="0" />
<Property Name="TempList" Type="List[Job]" Accessor="Internal" />
</Properties>
<Execution>
<UserContent Name="Pre" />
<!-- Standaard bedrijfslogica hier -->
<Transaction>
<Assign Name="Set description" Property="${Job.Description}" Value="Goedgekeurd" />
</Transaction>
<UserContent Name="Post" />
</Execution>
</Workflow>
Onderdelenbewerken
Security
<Security EditLevel="10" ViewLevel="20" UserContentLevel="30" />
| Level | Beschrijving |
|---|---|
| EditLevel | Minimaal security level om de volledige workflow te bewerken |
| ViewLevel | Minimaal security level om de workflow te bekijken |
| UserContentLevel | Minimaal security level om UserContent secties te bewerken |
Standaard waarden: EditLevel=10 (alleen Ultimo R&D), ViewLevel=20 (consultants), UserContentLevel=30 (klantbeheerders).
Consultant tip: Als consultant heb je doorgaans level 20, waardoor je standaard workflows kunt bekijken maar niet bewerken. Aanpassingen doe je via UserContent secties (level 30).
Properties
Properties zijn de variabelen van een workflow. Elk property heeft:
| Attribuut | Beschrijving |
|---|---|
| Name | Naam van de property, gebruikt als ${Name} in de workflow |
| Type | Datatype: Job, String, Int32, Boolean, List[Job], Status?, etc. |
| Accessor | Root (hoofd domain object), Optional (optioneel), Internal (alleen intern) |
| Direction | In (invoer), Out (uitvoer), InOut (beide) |
| Default | Standaard waarde |
Execution
Het <Execution> blok bevat de daadwerkelijke instructies. Alle workflow instructies worden hierin geplaatst.
UserContent (Pre/Post hooks)bewerken
UserContent is het mechanisme waarmee consultants en klantbeheerders bedrijfslogica kunnen toevoegen aan standaard workflows ZONDER de originele workflow te wijzigen.
<Execution>
<UserContent Name="Pre" />
<!-- Standaard Ultimo logica (niet aanpasbaar) -->
<Transaction>
<ChangeStatus Name="Change status" DomainObject="${Job}" NewStatus="${ChangeStatusTo}" />
</Transaction>
<UserContent Name="Post" />
</Execution>
Hoe werkt het?bewerken
- Elke workflow heeft (standaard) een
<UserContent Name="Pre" />en<UserContent Name="Post" />sectie - Pre wordt uitgevoerd VOOR de standaard logica
- Post wordt uitgevoerd NA de standaard logica
- UserContent wordt opgeslagen als apart bestand in de FileService:
UserContent_{ActionFieldId}_{Pre|Post}.wfl - Je bewerkt UserContent via de UCT workflow editor
Wanneer gebruik je Pre vs Post?bewerken
| Situatie | Gebruik |
|---|---|
| Extra validatie toevoegen | Pre |
| Velden vullen voor de standaard actie | Pre |
| Record aanmaken na statuswijziging | Post |
| Email versturen na actie | Post |
| Waarde berekenen op basis van resultaat standaard actie | Post |
Consultant tip: Gebruik ALTIJD UserContent in plaats van de standaard workflow te wijzigen. Bij een Ultimo upgrade worden standaard workflows overschreven, maar UserContent blijft behouden.
Voorbeeld: validatie toevoegen in Pre UserContentbewerken
<!-- UserContent Pre: extra validatie voor goedkeuring -->
<Validation Name="Equipment verplicht"
Condition="${Job.Equipment} != Empty"
MessageCode="9001" />
Voorbeeld: Job aanmaken in Post UserContentbewerken
<!-- UserContent Post: vervolgJob aanmaken na afmelding -->
<Transaction>
<Insert Name="Maak vervolgjob" ObjectType="Job" OutputProperty="${NewJob}">
<Parameter Name="Status" Direction="In" Value="JobStatus.Created" />
<Parameter Name="Equipment" Direction="In" Value="${Job.Equipment}" />
<Parameter Name="Description" Direction="In" Value="Vervolg op ${Job.Id}" />
</Insert>
</Transaction>
Transaction blokkenbewerken
Alle database-operaties (lezen, schrijven, verwijderen) MOETEN binnen een <Transaction> blok staan. Zie Transaction voor details.
<Transaction>
<!-- Database operaties hier -->
<GetList Name="..." Type="Job" OutputProperty="${Jobs}" />
<Insert Name="..." ObjectType="Job" OutputProperty="${NewJob}">
<Parameter Name="Status" Direction="In" Value="JobStatus.Created" />
</Insert>
<Assign Name="..." Property="${Job.Description}" Value="Bijgewerkt" />
</Transaction>
Belangrijke eigenschappen van Transaction:
- Flush - Tussentijds naar database schrijven
- IsolationLevel - Default of ReadCommitted (voor performance-gevoelige situaties)
- IncludeTrashedObjects - Ook verwijderde objecten meenemen
WorkflowTypebewerken
| Type | Beschrijving |
|---|---|
ChangeStatus |
Wordt getriggerd door statuswijzigingen |
Standard |
Herbruikbare workflow, aangeroepen via WorkflowCall |
Bulk |
Voor bulk-operaties, UserContent moet binnen ForEach staan |
Scheduled |
Wordt periodiek uitgevoerd via de UCT Scheduler |
ChangeStatus workflowsbewerken
Het meest voorkomende type. Deze workflows worden automatisch aangeroepen wanneer de status van een domain object verandert via de Status Matrix. Ze volgen de naamconventie {EntityName}_Pre{Status} en {EntityName}_Post{Status}.
Kenmerken: - Worden getriggerd door statuswijzigingen in de Status Matrix - De root property is altijd het domain object waarvan de status verandert - Pre-workflows draaien VOOR de statuswijziging (validatie, voorbereiding) - Post-workflows draaien NA de statuswijziging (vervolgacties)
Standard workflowsbewerken
Herbruikbare logica-blokken die worden aangeroepen via WorkflowCall vanuit andere workflows. Ze worden niet rechtstreeks door het systeem getriggerd.
Kenmerken:
- Worden nooit automatisch uitgevoerd; alleen via WorkflowCall
- Kunnen parameters ontvangen en retourneren (In/Out/InOut)
- Worden gebruikt voor gedeelde bedrijfslogica, bijv. Job_CreateAndInitialize
- ActionField workflows (knoppen op schermen) zijn typisch van dit type
Bulk workflowsbewerken
Speciaal type voor bulkoperaties op meerdere records tegelijk. Het verschil met Standard is dat UserContent secties binnen een ForEach loop moeten staan.
Scheduled workflowsbewerken
Workflows die op een vast tijdschema worden uitgevoerd via de Scheduler in UCT. Ze hebben geen directe entity-trigger.
Kenmerken:
- AllowUserInteraction is altijd False (er is geen UI)
- Worden geconfigureerd via UCT > Scheduler met een cron-expressie of interval
- Typisch gebruik: nachtelijke batch-taken, verlopen contracten, herinneringen
Volledige lijst van trigger typesbewerken
Pre/Post per statusbewerken
Voor elke status in de Status Matrix worden Pre- en Post-workflows aangemaakt:
| Trigger | Voorbeeld | Moment |
|---|---|---|
Pre{Status} |
Job_PreApproved |
VOOR statuswijziging naar Approved |
Post{Status} |
Job_PostApproved |
NA statuswijziging naar Approved |
PreSave |
Job_PreSave |
VOOR het opslaan van wijzigingen |
PostSave |
Job_PostSave |
NA het opslaan van wijzigingen |
PreOpen |
Job_PreOpen |
VOOR het openen van een record |
PostOpen |
Job_PostOpen |
NA het openen van een record |
PreImport |
Job_PreImport |
VOOR het importeren van een record |
PostImport |
Job_PostImport |
NA het importeren van een record |
PreTrash |
Job_PreTrash |
VOOR het naar prullenbak verplaatsen |
PostTrash |
Job_PostTrash |
NA het naar prullenbak verplaatsen |
PreDelete |
Job_PreDelete |
VOOR definitieve verwijdering |
Pre{Inactive} |
AbnormalityType_PreInactive |
VOOR het inactief zetten |
Post{Inactive} |
AbnormalityType_PostInactive |
NA het inactief zetten |
Pre{Active} |
AbnormalityType_PreActive |
VOOR het actief zetten |
Post{Active} |
AbnormalityType_PostActive |
NA het actief zetten |
Voorbeelden van veelvoorkomende statusnamen in triggers: Created, Approved, Active, Finished, Closed, Postponed, Open, Inactive, Trash.
Bijzondere trigger patternsbewerken
| Pattern | Beschrijving |
|---|---|
ActionField{NNN} |
Workflow gekoppeld aan een actieknop op een scherm, bijv. ActionField025 (Approve Job) |
{Entity}_Delete |
Volledige delete-workflow (niet Pre/Post, maar de daadwerkelijke delete-logica) |
Dialog_{Name} |
Workflow die een dialoog beheert |
Validation_{Name} |
Herbruikbare validatie-workflow |
ScheduledTask_{Name} |
Geplande taak |
Bulk_{Name} |
Bulkverwerking |
Security levels in detailbewerken
Security levels bepalen wie een workflow mag bekijken en bewerken. Ze worden gedefinieerd in het <Security> element:
<Security EditLevel="10" ViewLevel="20" UserContentLevel="30" />
Level betekenissenbewerken
| Level | Wie | Rechten |
|---|---|---|
| 10 | Ultimo R&D | Volledige lees- en schrijftoegang tot alle workflows. Alleen R&D kan standaard workflows aanpassen |
| 20 | Consultants (implementatiepartners) | Kunnen workflows bekijken (ViewLevel=20), maar niet de standaard logica wijzigen |
| 30 | Klantbeheerders | Kunnen UserContent secties bewerken (UserContentLevel=30). Dit is het niveau voor klantspecifieke aanpassingen |
| 40+ | Eindgebruikers met beperkte rechten | Hogere levels kunnen worden gebruikt voor extra restricties |
Praktische gevolgenbewerken
- EditLevel=10: Alleen Ultimo R&D kan de standaard workflow-logica wijzigen. Bij een upgrade worden deze workflows overschreven
- ViewLevel=20: Consultants en klantbeheerders kunnen de workflow bekijken om te begrijpen wat de standaard logica doet
- UserContentLevel=30: Klantbeheerders en consultants kunnen UserContent Pre/Post secties bewerken. Dit is de aanbevolen manier om bedrijfslogica aan te passen
Consultant tip: Je security level wordt bepaald door je gebruikersrol in UCT. Controleer je level via UCT > Gebruikersbeheer als je onverwacht geen toegang hebt tot workflows.
Settings in workflowsbewerken
Sommige workflows bevatten een <Settings> blok dat de configuratie van de workflow bepaalt:
<Settings>
<SettingsGroup Name="WorkOrder">
<Setting Name="CreateActiveJobOnApproval" Type="Boolean" Value="False" />
<Setting Name="CreateJobOnApproval" Type="Boolean" Value="True" />
</SettingsGroup>
</Settings>
Settings worden in de workflow gelezen via #{Settings.GroupName.SettingName} en kunnen worden overschreven per entiteitscontext via de UCT-instellingen.
Daarnaast kunnen globale Ultimo-instellingen worden gelezen met #{UltimoSettings.SettingName}:
<When Name="StockLevelPerSite" Condition="#{UltimoSettings.StockLevelPerSite} == True">
<!-- Site-specifieke logica -->
</When>
AllowUserInteractionbewerken
Bepaalt of de workflow dialogen mag tonen aan de gebruiker. Bij scheduled workflows en import workflows is dit altijd False. Bij statuswijzigingen vanuit de UI kan dit True zijn.
Gebruik ChooseUserInteraction om logica te splitsen tussen interactieve en niet-interactieve scenario's:
<ChooseUserInteraction Name="Keuze">
<WithUserInteraction Name="Met UI">
<Dialog Name="VraagGebruiker" TitleCode="CONFIRM">
<Text Name="Reden" OutputProperty="${Reden}" LabelCode="REASON" Required="True" />
</Dialog>
</WithUserInteraction>
<WithoutUserInteraction Name="Zonder UI">
<Assign Name="Standaard reden" Property="${Reden}" Value="Automatisch" />
</WithoutUserInteraction>
</ChooseUserInteraction>
Workflow bestandenbewerken
In UCT worden workflows beheerd via de workflow editor. De XML wordt opgeslagen in de Ultimo database. Export via UCT levert .wfl bestanden op.
De structuur in het export bestand (workflows.xml) is:
<Workflows>
<Workflow Name="Job_PostApproved" IsCustom="false" IsLight="true" ...>
<Properties>
<Property Name="Job" Type="Job" Accessor="Root" IsUnknown="false" />
</Properties>
<CurrentValue><![CDATA[ ... workflow XML ... ]]></CurrentValue>
</Workflow>
</Workflows>
| Attribuut | Beschrijving |
|---|---|
IsCustom |
true als het een klantspecifieke workflow is |
IsLight |
true als beschikbaar in Light licentie |
IsTechnician |
true als beschikbaar voor Technician licentie |
IsSelfService |
true als beschikbaar in Self Service |
Standaard workflowsbewerken
Ultimo wordt geleverd met duizenden standaard workflows. Hieronder een overzicht van de belangrijkste standaard workflows per entiteit, gebaseerd op de daadwerkelijke workflows.xml. Zie standaard-workflows voor het volledige overzicht.
Naamconventiebewerken
Standaard workflows gebruiken de werkwoordsvorm van de status:
| In de workflow | In documentatie/spreektaal |
|---|---|
Job_PreApprove |
"Pre-goedkeuring" of "PreApproved" |
Job_PostFinish |
"Post-afmelding" of "PostFinished" |
Job_PreActivate |
"Pre-activering" of "PreActive" |
Job_PostClose |
"Post-sluiting" of "PostClosed" |
Voor transitie-specifieke workflows wordt de voltooid-deelwoord-vorm gebruikt: Job_PreApprovedToFinished (voor de overgang van Approved naar Finished).
Job workflowsbewerken
| Workflow | Trigger | Beschrijving |
|---|---|---|
Job_PreApprove |
Pre Approved | Autorisatiecheck (budget vs. bevoegdheid medewerker), materiaalreservering, impliciete statuswijziging Requested->Created |
Job_PostApprove |
Post Approved | Zet voortgangsstatus, werkt Equipment next-PM velden bij, controleert materiaalvoorraad-progressstatus |
Job_PreActivate |
Pre Active | LOTO-controle, werkvergunningsvalidatie, impliciete statusovergangen, multijob-parentcheck |
Job_PostActive |
Post Active | Zet voortgangsstatus, werkt Equipment next-PM bij, synchroniseert JobSchedulePart |
Job_PreFinish |
Pre Finished | Impliciete statusovergangen, bulk-PM validatie, multijob-verwerking, werkvergunningscontrole |
Job_PostFinish |
Post Finished | Meest complex: meetpuntwaarden bijwerken, PmWorkOrder update, laatste onderhoudsdatum, email naar melder, servicecontract-KPI's |
Job_PreClose |
Pre Closed | Valideert gerelateerde records (materialen, uren, subcontractors) |
Job_PostClose |
Post Closed | Planning bijwerken, voortgangsstatus, conditiegebreken sluiten, multijob check |
Equipment workflowsbewerken
| Workflow | Trigger | Beschrijving |
|---|---|---|
Equipment_PreActive |
Pre Active | Heropent PmJobs/PmWorkOrders bij reactivering vanuit ToDelete, un-trasht InspectionLines |
Equipment_PreActiveToScrapped |
Pre Active->Scrapped | Valideert dat Equipment is uitgebouwd |
Equipment_PreTrash |
Pre Trash | Validatie voor prullenbak |
Equipment_PreDelete |
Pre Delete | Verwijdert gerelateerde documenten, features, kosten, etc. |
Equipment_PreImport / PostImport |
Import | Import-specifieke logica |
PmWorkOrder workflowsbewerken
| Workflow | Trigger | Beschrijving |
|---|---|---|
PmWorkOrder_PreApprove |
Pre Approved | Valideert meetpunten, frequenties, emailadres; berekent volgende onderhoudsdatum |
PmWorkOrder_PostApprove |
Post Approved | Keurt PmJobs goed, werkt next-PM velden bij, zet AutoPM NextRunDate, verwerkt periodieke activiteiten |
PmWorkOrder_PostReopen |
Post Reopen | Verwerking na heropenen |
Purchase workflowsbewerken
| Workflow | Trigger | Beschrijving |
|---|---|---|
Purchase_PreApprove |
Pre Approved | Leeg standaard -- puur UserContent hooks voor klantspecifieke validaties |
Purchase_PostApprove |
Post Approved | Cascade: zet alle PurchaseLines naar status Approved |
Purchase_PostActive |
Post Active | Verwerking na activeren |
Purchase_PreClose |
Pre Closed | Sluit inkooporder en verwijdert kosten |
Purchase_PostClose |
Post Closed | Sluit alle PurchaseLines |
PurchaseRequest workflowsbewerken
| Workflow | Trigger | Beschrijving |
|---|---|---|
PurchaseRequest_PreApprove |
Pre Approved | Validaties voor goedkeuring |
PurchaseRequest_PostApprove |
Post Approved | Verstuurt email naar aanvrager |
PurchaseRequest_PostActive |
Post Active | Verwerking na activeren |
PurchaseRequest_PostCreate |
Post Created | Verwerking na aanmaak |
Aantallen per entiteitbewerken
De standaard installatie bevat workflows voor ~200 entiteiten. De entiteiten met de meeste workflows:
| Entiteit | ~Aantal | Entiteit | ~Aantal |
|---|---|---|---|
| Job | 610 | PurchaseRequest | 76 |
| Equipment | 182 | Invoice | 66 |
| Article | 124 | ProcessFunction | 50 |
| Purchase | 114 | ServiceContract | 48 |
| PmWorkOrder | 82 | Cost | 48 |
| Permit | 82 | Receipt | 46 |
Gerelateerde artikelenbewerken
- workflow-instructies - Alle beschikbare instructies
- expressions - Expression functies voor condities en berekeningen
- workflow-patronen - Praktische patronen voor consultants
- standaard-workflows - Volledig overzicht van standaard workflows per entiteit
- workflow-debugger - Debugging tips