Přeskočit na hlavní obsah

Workflow a procesy

Jak pracovat s nástrojem Activiti?

Autor: Petr Pech

💡 Máte-li zájem o funkcionalitu workflow, je potřeba oslovit našeho integračního partnera ARIT a probrat s ním konkrétní možnosti nastavení a integrace.

Základem workflow a procesů je nástroj Activiti. Jeho součástí je programátorské rozhraní Activiti REST API, které je přístupné na této adrese:

/c/<identifikátor firmy>/activiti/

Omezení proti standardnímu Activiti

  • Není podporované rozhraní /login. Používá se autorizace ABRA Flexi.

  • Není podporovaná modifikace uživatelů, skupin a členství. Vše se dělá přes rozhraní ABRA Flexi.

  • Nahrání nového procesu musí být realizováno přes ABRA Flexi (kvůli definici platností workflow). Aktualizace procesů mohou být již přes Activiti API.


API pro ABRA Flexi

Výpis definicí workflow k dané evidenci:

GET /c/<identifikátor firmy>/<evidence>/workflows.xml

Spuštění workflow:

PUT /c/<identifikátor firmy>/<evidence>/<id záznamu>/workflows/<processId>/start

Při spuštění je možné také předat parametry pro workflow, které je možné použít při rozhodování:

PUT /c/<identifikátor firmy>/<evidence>/<id záznamu>/workflows/<processId>/start?parametr1=value1&parametr2=value2

Události a úkoly

Seznam událostí (poznámek a úkolů) u daného objektu — jde o relaci udalosti na konkrétním záznamu:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalosti

Vypsání událostí včetně dalších atributů workflow:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalosti.xml?includes=udalost/actRuTask

⚠️ Relace na záznamu se jmenuje udalosti (množné číslo) — cesta …/<ID>/udalost vrací 404. Naopak samostatná evidence, nad kterou se filtruje, je udalost v jednotném čísle. Obě podoby tedy platí, ale každá na jiném místě URL.

Při práci s workflow chcete obvykle úkoly pouze určitého typu. Typ události nese vlastnost typAkt, což je vazba na evidenci typ-aktivity; úkoly workflow mají v této evidenci kód ÚKOL WORKFLOW:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalosti/(typAkt = 'code:ÚKOL WORKFLOW')

🚨 Vlastnost typUdalosti ani hodnota druhUdal.workflow v tomto API neexistují — takový filtr skončí chybou 400 s hlášením „Vlastnost 'typUdalosti' neexistuje". Používejte typAkt. Alternativně lze úkoly workflow vybrat podle processDefinitionId is not null.

Výpis všech úkolů pro konkrétní workflow:

/c/<identifikátor firmy>/udalost/(typAkt = 'code:ÚKOL WORKFLOW' and processDefinitionId = '<processId>')

Výpis všech úkolů s daným klíčem úkolu pro konkrétní workflow:

/c/<identifikátor firmy>/udalost/(typAkt = 'code:ÚKOL WORKFLOW' and processDefinitionId = '<processId>' and taskDefinitionKey = '<taskKey>')

Výpis všech úkolů, které může aktuálně přihlášený uživatel vyřešit:

/c/<identifikátor firmy>/udalost@ukoly-k-realizaci

Seznam úkolů a k nim související objekty:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalosti.xml?includes=udalost/doklFak

Signály a zprávy

Zaslání signálu všem běžícím workflow, které na něj mohou reagovat:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/workflow-signal/<signalId>?param1=value

Zaslání zprávy všem běžícím workflow, které na ni mohou reagovat:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/workflow-message/<messageId>?param1=value

Práce s úkolem

/c/<identifikátor firmy>/udalost/<ID záznamu>/<operace>

Operace

Význam

claim.xml

přivlastnit si úkol

unclaim.xml

odvlastnit si úkol

complete.xml
​complete.xml?param1=value… 1)

vyřešit úkol

assign.xml?username=user 1)

předat úkol uživateli user

add-comment.xml?comment=text 1) 2)

přidat komentář k úkolu

  • 1) Pro hodnoty parametrů obsahující jiné než povolené znaky URL (mezera, zavináč atd.) je zapotřebí provést URL encoding.

  • 2) Kódování textů je očekáváno v UTF-8.

ℹ️ Události, které jsou typu úkol pro workflow, se zruší poté, co jsou vyřešeny. Místo .xml lze také použít .json nebo hlavičku Accept.


Objekty použitelné při rozhodování ABRA Flexi

Výraz

Popis

flexibee.user(username)

Vrací uživatele s uvedeným jménem

flexibee.userQuery(username)

Vrátí dotazovací objekt uživatele s uvedeným jménem (výstup je shodný s metodou objectQuery).

flexibee.object(evidenceType)

Vrátí objekt daného typu, který je připojen k úkolu workflow

flexibee.objectQuery(evidenceType).relation(relationName).filter(filter).list()

Umožňuje filtrovat objekty v relaci.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).one()

Umožňuje vrátit první objekt ve filtrované relaci.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).sum()

Umožňuje sečíst objekty ve filtrované relaci.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).firstQuery().relation(relationName2).one()

Umožňuje zřetězit zpracování dotazování.

flexibee.objectQuery(evidenceType).relation(relationName).list()

Umožňuje filtrovat objekty v relaci.

flexibee.objectQuery(evidenceType).relation(relationName).one()

Umožňuje vrátit první objekt v relaci.

flexibee.objectQuery(evidenceType).relation(relationName).sum()

Umožňuje sečíst objekty v relaci.

flexibee.wrap(object)

Obalí objekt pomocí query (stejný výsledek jako vrací např. objectQuery). Lze pak využít sadu funkcí, které nabízí query.

flexibee.query(evidenceType).filter(filter).one()

Vrátí jeden objekt daného typu, který odpovídá uvedenému filtru.

flexibee.query(evidenceType).filter(filter).firstQuery().signal('signalName')

Vyvolá signál nad všemi workflow, které běží nad zvoleným záznamem.

flexibee.query(evidenceType).filter(filter).list()

Vrátí všechny objekty daného typu, které odpovídají uvedenému filtru.

flexibee.query(evidenceType).filter(filter).count()

Vrátí počet objektů daného typu, které odpovídají uvedenému filtru.

flexibee.query(evidenceType).filter(filter).sum(propertyName)

Vrátí součet daného sloupečku pro všechny objekty, které odpovídají filtru.

flexibee.query(evidenceType).filter(filter).max(propertyName)

Vrátí maximum daného sloupečku pro všechny objekty, které odpovídají filtru.

flexibee.query(evidenceType).filter(filter).min(propertyName)

Vrátí minimum daného sloupečku pro všechny objekty, které odpovídají filtru.

flexibee.query(evidenceType).filter(filter).avg(propertyName)

Vrátí průměr daného sloupečku pro všechny objekty, které odpovídají filtru.

flexibee.query(evidenceType).asc(propertyName).first()

Umožní řazení vzestupně.

flexibee.query(evidenceType).desc(propertyName).first()

Umožní řazení sestupně.

flexibee.settings()

Vrátí aktuální nastavení firmy (evidence nastaveni). Název firmy lze tedy získat např. ${flexibee.settings().nazFirmy}

flexibee.settingsForDate(dt)

Vrátí nastavení firmy pro daný den (obvykle datum dokladu), např. ${flexibee.settingsForDate(dt).nazFirmy}

flexibee.varName(evidenceType)

Vrátí interní název proměnné, kterou používá ABRA Flexi pro vazbu jednotlivých workflow na doklady a objekty. Používá se obvykle při volání podprocesu.

flexibee.isDesktop()

Vrátí true, pokud workflow aktuálně běží v desktopové aplikaci.

flexibee.isServer()

Vrátí true, pokud workflow běží přes REST API nebo v prohlížeči.

flexibee.importXml(string)

Provede import XML řetězce dle ABRA Flexi REST API. Vrací kolekci identifikátorů objektů z XML importu.

Proměnné

Proměnná

Popis

now

Aktuální datum a čas.

authenticatedUserId

Jméno aktuálně přihlášeného uživatele. Pro více informací je nutné použít flexibee.user(authenticatedUserId) — viz dokumentace Activiti.

task

Záznam Activiti, který reprezentuje úkol (viz dokumentace Activiti).

execution

Informace o aktuálně běžícím workflow (viz dokumentace Activiti).


Volání podprocesu

Pokud voláte podproces a chcete, aby výsledné úkoly byly provázány k dokladům, je nutné aktivovat propagaci vazební proměnné do workflow. To učiníte takto:

<callActivity id="callSubProcess" calledElement="checkCreditProcess">
<extensionElements>
<activiti:in source="${flexibee.varName('faktura-prijata')}" target="${flexibee.varName('faktura-prijata')}" />
<activiti:in source="initiator" target="initiator" />
</extensionElements>
</callActivity>


Práce s uživateli ve workflow

Pokud chcete pracovat s uživateli, je několik následujících možností.

⚠️ Dejte si pozor, abyste v rámci definice uživatelů nepoužili znak čárky (,). Activiti má chybu, která zabraňuje jeho použití.

Původce workflow

Při startu workflow nadefinujte proměnnou initiator. Tu pak můžete použít jako název uživatele pro přidělení úkolu.

<startEvent id="theStart" activiti:initiator="initiator">

Aktuální uživatel

Pokud chcete úkol přidělit stejnému uživateli, který provedl aktuální operaci, použijte proměnnou authenticatedUserId.

Konkrétní uživatel

Při zpracování můžete použít konkrétního uživatele. Můžete také vyhledat uživatele podle určitých kritérií (např. štítek):

<formalExpression>${flexibee.query('uzivatele').relation('stitek = "code:PRACOVNIK"').one().kod}</formalExpression>

Nebo uživatelskou vazbu:

<formalExpression>${flexibee.userQuery(initiator).relation('uzivatelske-vazby').filter('typVazby = "code:NADRIZENY"').one().kod}</formalExpression>


Modifikace dokladů

Někdy je nutné při zpracování workflow modifikovat jeden nebo více dokladů. To lze provést použitím flexibee-xml. Aby metoda flexibee.object() fungovala, musí být workflow navázané na tento dokument.

<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="object" expression="${flexibee.object('faktura-vydana')}"/>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[
<winstrom>
<faktura-vydana action="storno">
</faktura-vydana>
</winstrom>
]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>

Lze také modifikovat více objektů:

<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[
<winstrom>
<faktura-vydana action="storno">
<id>code:FAV0001/2013</id>
</faktura-vydana>
<faktura-vydana action="storno">
<id>code:FAV0002/2013</id>
</faktura-vydana>
</winstrom>
]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>

Získání identifikátorů modifikovaných objektů

Pomocí proměnné idsVar lze získat kolekci identifikátorů, které byly modifikovány XML importem.

<serviceTask id="import" activiti:class="flexibee-xml">
…
<extensionElements>
<activiti:field name="idsVar" stringValue="seznamId" />
</extensionElements>
</serviceTask>

Po úspěšně vykonaném XML importu pak bude proměnná seznamId obsahovat kolekci identifikátorů zmodifikovaných objektů.

Zpracování chyb při importu XML

Pokud nastane chyba při importu XML v tasku typu flexibee-xml, je zpracování workflow přerušeno výjimkou WSBusinessRTException. Výjimka obsahuje popis chyby a zobrazí se v GUI jako chybový dialog.

Pokud má workflow pokračovat i při chybě v importu, lze definici tasku rozšířit o parametry errorVar a errorMessageVar:

<serviceTask id="storno" activiti:class="flexibee-xml">
…
<extensionElements>
<activiti:field name="errorVar" stringValue="wasError" />
<activiti:field name="errorMessageVar" stringValue="errorMessage" />
</extensionElements>
</serviceTask>

Proměnná

Datový typ

Popis

errorVar

Boolean

Definuje název proměnné (např. wasError), kam se uloží příznak výskytu chyb při importu.

errorMessageVar

String

Definuje název proměnné (např. errorMessage), kam se uloží text popisující chyby importu.


Podmíněné větvení na základě objektů

Ve workflow lze pokládat dotazy ABRA Flexi a reagovat na základě odpovědi:

${flexibee.object('objednavka-prijata').sumCelkem > 1000}

Lze se ptát i obecně, např. kolik neuhrazených faktur je u firmy, která je uvedena u aktuální faktury:

${flexibee.query('faktura-vydana').filter('stavUhrK != "stavUhr.uhrazeno" and stavUhrK != "stavUhr.uhrazenoRucne" and firma='.concat(flexibee.object('faktura-vydana').firma.id)).sum('sumCelkem') > 1000}


Přenášení stavu workflow do dokladu

Někdy je nutné na základě stavu workflow měnit i stav dokladu. To lze realizovat pomocí štítků, které jsou přiděleny do jedné skupiny, u které je nastavena exkluzivita (pak při nastavení nového štítku ze stejné skupiny dojde ke zrušení ostatních). Realizace je pak opět pomocí flexibee-xml, které zavoláte při každé změně stavu workflow:

<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="object" expression="${flexibee.object('faktura-vydana')}"/>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[
<winstrom>
<faktura-vydana>
<stitky>SCHVÁLENO</stitky>
</faktura-vydana>
</winstrom>
]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>


Související

Dostali jste odpověď na svou otázku?