Všechny sbírky
Výukové články
API Ninja
API Ninja: Trénink 5/7 - Pokročilé akce a triky
API Ninja: Trénink 5/7 - Pokročilé akce a triky

V pátém předposledním tréninku si ukážeme pokročilé akce v API, chvaty a finty, které REST API ABRA Flexi nabízí

Ota Rádl avatar
Autor: Ota Rádl
Aktualizováno před více než týdnem

Získané schopnosti:

  • znalost akcí a režimů založení, které API umožňuje

  • znalost pokročilých služeb v API

Již jsme zkušení ninjové, kteří zvládnou vyřešit v API spoustu složitých úkonů, nicméně REST API nám nabízí ještě více. Některé akce, operace a služby, které by se museli všemožně obcházet nebo doprogramovat lze pomocí API vyřešit jednoduchými chvaty, které se v této kapitole ukážeme.

Na základní učňovské úrovni si ukážeme, jak přes API například smazat, zamknout či stornovat doklad pomocí akce a také si ukážeme různé režimy založení záznamu. Jelikož budeme data měnit již se neobejdeme bez aplikace jako je například Postman. Válečník se naučí některé služby, které API nabízí a nemusí je tak klikat uživatel v aplikaci. Na úrovni Ninja půjdeme ještě dál a ukážeme si jiný přístup k API pomocí /query a další pokročilejší služeb v API. Dále si na úrovni Ninja ukážeme transakční zpracování. Tento chvat se může hodit, pokud potřebujeme import rozdělit a každý záznam zapsat v samostatné transakci. Připravte si tréninkový plac a jdeme na to!

Úroveň: Učeň

Režimy založení a změnu se řídí pomocí parametru u evidence, v zásadě umíme dva:

  • create

  • update

Představme si situaci, že máme pravidelný import aktualizací informací o obchodních partnerech z CRM do ABRA Flexi a chceme nahrávat pouze aktualizace o firmách. Tedy jinými slovy, zasíláme aktualizace stávajících partnerů v ABRA Flexi, ale nechceme zakládat nové obchodní partnery, aby nevznikly například duplicity. Jak na to?

K tomu využijeme režimy založení. Nejprve si ukážeme nastíněný příklad, zašleme aktualizaci firmy do adresáře a zamezujeme tvorbě nové. Požadavek pošleme pomocí metody POST na známé URL:

Tělo požadavku obsahuje Flexi XML, jak ho známe s jednou malou změnou. Přidáme akci, ve formě parametru create= ignore u elementu evidence:

<?xml version="1.0"?>
<winstrom version="1.0">
<adresar create="ignore">
<id>code:NINJAFIRMA</id>
<ic>123456789</ic>
<nazev>Ninja firma s.r.o.</nazev>
...další informace
</adresar>
</winstrom>

A to je vše, <adresar create="ignore"> to je to kouzlo, které zajistí, pokud firma se zkratkou NINJAFIRMA ještě v datech ABRA Flexi neexistuje, že importér firmu nevytvoří a pokud existuje, aktualizuje její informace.

Jednoduché, že učedníku?

Podobným, přísnějším příkladem může být kontrola existence pomocí akce create='fail'. Atribut create='fail' zakazuje založení nového záznamu. Tedy import dané firmy vypíše chybovou hlášku.

Druhou variantou režimu je update. Jako příklad nám může posloužit import faktur vydaných do ABRA Flexi. Představme si, že chceme zakládat doklady, ale nechceme stávající faktury nijak měnit - aktualizovat. Opět požadavek pošleme pomocí metody POST na URL:

Tělo požadavku pak obsahuje XML s fakturou vydanou rozšířenou o parametr update= ignore u elementu evidence:

<?xml version="1.0"?>
<winstrom version="1.0">
<faktura-vydana update="ignore">
<id>code:VF1-0123/21</id>
... povinné náležitosti faktury
</faktura-vydana>
</winstrom>

Jednoduše jsme zařídili, že pokud faktura VF1-0123/21 už v ABRA Flexi existuje nebude nijak měněna. Pokud faktura neexistuje vytvoří se nová.

Oba režimy mají ještě výchozí stav update=ok a create=ok, které jsou výchozí a není nutné je uvádět. Tedy update=ok mění veškeré existující záznamy, ale povolí i založit. Create=ok zakládá vše, ale také mění vše.

Učedníku, dokážeš vymyslet a otestovat příklad na update=ignore?


To byly režimy založení a změny. Nyní se podíváme na akce, které API nabízí následující:

  • action=delete

  • action=storno

  • action=lock

  • action=lock-for-ucetni

  • action=unlock

Akce jsou pro Ninju chvaty, které umožňují v API simulovat stisk tlačítka jako v aplikaci. Představme si, jak bez akce stornovat doklad. Nastavovat element storno=true, stačí to? Stačí nám rychlá akce, která stornuje i navázané doklady a to je kus práce bez akce.

Požadavek s akcí vypadá obdobně jako s režimy založení/změny. Přejdeme tedy hned k příkladu, kdy chceme nově založenou fakturu jednoduše a rychle stornovat, takže pošleme požadavek pomocí metody POST na URL:

A tělo už bystřejší učedník jistě odvodil:

<?xml version="1.0"?>
<winstrom version="1.0">
<faktura-vydana action="storno">
<id>code:VF1-0123/21</id>
... další informace nejsou potřeba!
</faktura-vydana>
</winstrom>

API ABRA Flexi nám odpoví, že aktualizovalo fakturu, která je nyní stornována.

A co action=delete, učedníku? Učedník, který zná metody HTTP jistě přemýšlí, jaký je rozdíl mezi action=delete a HTTP metodou DELETE? Obě akce jsou v jádru shodné. Lehce se liší činnost před vyvoláním akce. Například action=delete dovoluje smazání dokladů i v jiném než aktuálním období. Request DELETE toto nedovolí a hlásí "No permisson". Action=delete je použitelné téměř všude. Nelze použít na uživatelích, nebo standardních záznamech přehledů apod. Action=delete podle druhu vazeb provede buď smazání navazaných záznamů, zrušení vazeb nebo nepovolení akce.

Poslední ukázkou v dnešním tréninku pro učedníka je zamykání. Zamykání jistě znáte z desktopové aplikace, pohodlně pomocí tlačítka zamkneme, odemkneme, ale jak na to v API. Příklad už je každému zřejmě jasný.

Opět POST požadavek na URL:

A tělo s action=lock:

<?xml version="1.0"?>
<winstrom version="1.0">
<faktura-vydana action="lock">
<id>code:VF1-0123/21</id>
... další informace nejsou potřeba!
</faktura-vydana>
</winstrom>

Chvat se zámkem si ještě rozšíříme o dávkové zpracování. Tedy, co když chceme zamknout několik faktur najednou, dle nějakého filtru? Filtr uvedeme jako další parametr a máme vyhráno:

<?xml version="1.0"?> 
<winstrom version="1.0">
<faktura-vydana action="lock-for-ucetni" filter="stavUhrK = 'stavUhr.uhrazeno'">
</faktura-vydana>
</winstrom>

Tímto požadavkem jsme zamknuli všechny vydaná faktury, které jsou ve stavu Uhrazeno. Ale pozor, zamknuli jsme je tentokrát pro všechny, kromě paní účetní, resp. uživatele, který má roli Účetní.

Čas trénovat učedníku, prostoru je dost, porovnat mazání akcí a mazání HTTP metodou, či dávkové zamykání s jinými filtry a odemykání, ať není vše ve Flexi zamčené. Hodně štěstí!

Úroveň: Válečník

Válečníku, v dnešním tréninku si ukážeme řadu šikovných služeb, pomocí kterých v API můžeš automatizovat spoustu úkonů a ulehčit tak práci uživatelům v aplikaci. Ukážeme si jednodušší ze služeb, pokud ti trénink nebude stačit, další pokročilejší služby uvedeme v Ninja úrovni. Utáhni opasek, jdeme na věc.

Zaměříme se na skladové služby. Mezi nejpoužívanější můžeme zařadit aktualizaci požadavků na výdej, přepočet skladu, který je doporučeno dělat u velkých firem výhradně přes API, či služby inventury. Jsou zde i ale výstupy jako stav skladu k datu apod.

Začneme požadavky na výdej. V případě, že je v nastavení firmy povolené generování požadavků na výdej, tak lze pomocí REST API volat službu Aktualizace skladových požadavků na výdej. Pro volání v REST API můžeme využít HTTP metody PUT a POST.

Požadavek vypadá následovně:

Jednoduché, požadavek nepotřebuje žádný parametr, bohužel není možné využít webový prohlížeč, který posílá požadavky metodou GET. V případě úspěšného vykonání služby je vracen HTTP status 200 a odpověď:

<?xml version="1.0"?> 
<winstrom version="1.0">
<success>true</success>
</winstrom>

V případě, že nemáme povoleny požadavky na výdej v nastavení firmy, REST API nás o tom informuje chybovým status kódem 400 a zprávou:

<?xml version="1.0"?> 
<winstrom version="1.0">
<success>false</success>
<message>Není povoleno generovat požadavky na výdej.
</message>
</winstrom>

Další jednoduchý, ale velmi mocný chvat každého API Válečník je přepočet skladu. Přepočet skladu má za úkol zkontrolovat a případně přepočíst na správné hodnoty ceny na skladové kartě. Jak již bylo zmíněno, u velkých firem, co se týče objemu skladu, je často jedniná možnost přepočtu skladu přes API. Opět můžeme můžeme využít HTTP metody PUT a POST. V případě přepočtu skladu máme však dvě možnosti - přepočet celého skladu a přepočet skladové karty:

Přepočet přes celý sklad má 2 parametry. Parametr ucetniObdobi, který je povinný, je nutné určit v jakém období se má sklad přepočítat. Druhý parametr sklad je nepovinný, v případě více skladů dojde k přepočtu všech. V případě přepočtu přes skladovou kartu není potřeba období uvádět, jelikož skladová karta již sama o sobě podléhá období. Můžeme však využít filtraci pro získání záznamu.

Válečníku, kde se tedy vzalo dostupMj? To již známe, jedná se o pole evidence, případně si připomeň 3. trénink!

Odpověď API je pak obdobná jako u aktualizace požadavků na výdej, úsěch 200 - True, neúspěch 400 - s popisech chyby.

Máme aktualizováno, máme přepočteno, tak co si výsledky zkontrolovat? Dále se podíváme na službu Stav skladu k datu. Stav skladu k datu lze získat HTTP metodou GET, je tedy možné si požadavek uložit do internetového prohlížeče jako záložku a libovolně volat z prohlížeče:

Parametr skladu je povinný, určíme jaký sklad chceme zobrazit. Datum je nepovinné, v případě, že jej neuvedeme získáme stav skladu k aktuálnímu dni. A jak vypadá výstup? Jak si budeme přát dle evidence stav-skladu-k-datu. Známe již možnosti filtrace a detailu z třetího tréninku, takže si uvedeme jednoduchý příklad:

Válečníku, teď je na tobě, abys prověřil jak vypadá výstup, hurá do toho!

Poslední služby, které si na úrovni Válečník ukážeme jsou služby pro Inventuru. Co když nám některé stavy nesedí a je potřeba sklad zinventarizovat? Nejprve si musíme inventuru založit pomocí HTTP metody POST pošleme do REST API:

<?xml version="1.0"?> 
<winstrom>
<inventura>
<datZahaj>2021-09-30</datZahaj>
<sklad>code:PLZEŇ</sklad>
<typInventury>Kontrola skladu NINJA</typInventury>
<stavK>stavInventury.zahajena</stavK>
</inventura>
</winstrom>

Povinné pole je pouze datum zahájení datZahaj, ale proč neuvést více a mít v datech pořádek. Nyní máme předpis inventury a je potřeba uvést, jaké položky budeme kontrolovat. Představme si, že fyzická kontrola stavu proběhla a známe reálné množství dané položky, pošleme stav položky obratně do inventury pomocí POST metody požadavek:

Obsahem těla bude právě položka a její stav, nesmíme zapomenout provázat na danou inventuru pomocí ID:

<?xml version="1.0"?>
<winstrom>
<inventura-polozka>
<cenik>code:NINJASŤÍT</cenik>
<mnozMjReal>150</mnozMjReal>
<inventura>3</inventura>
</inventura-polozka>
</winstrom>

Válečník jistě ví, jak získat ID inventury.

Nyní máme v inventuře položku NINJAŠTÍT s reálním stavem 150 ks. Programový stav inventura načetla z aktuálního stavu skladu. Nicméně může se stát, že invetura trvá týden a během inventury proběhnou pohyby na skladu. K těmto situacím nám slouží Aktualizuj stavy, která je v API opět velice jednoduchá. Službu voláme pomocí metody GET, žádné parametry, žádné filtry, pouze opět je nutné znát ID inventury:

Máme téměř hotovo, máme zinventarizovanou položku, máme aktuální realný stav skladu vs. programový stav skladu, posledním krokem je tedy vygenerovat inventurní rozdíly a srovnat tak stavy. Použijeme metodu vygeneruj-doklady. Opět použijeme metodu GET, přibyde nám však však jeden povinný parametr typDokId:

Pro zkušené válečníky je jistě hračka získat ID typu skladového pohybu, tak pouze pro připomenutí požadavek na tyto typy vypadá následovně:

Voláním získáme všechny typy skladových dokladů. Zvládneš si volání lépe přizpůsobit, válečníku?

API odpovídá příslušnými zprávami dle chyby nebo úspěchu:

Doklady byly úspěšně vygenerovány.

--nebo--

Při inventuře nevznikl žádný inventurní rozdíl.

--nebo--

Na položce s ID = 2 se vyskytla chyba Na skladě není dostatek zboží.

Válečníku, to je pro dnešek vše, pusť se do tréninku, je čas vyčisti sklad!

Úroveň: API Ninja

Ninjo, připrav se, dnes to bude obsáhlé a výživné. Naučíme se další ze série služeb jako Válečník. Poté si ukážeme přístup k API pomocí /query a na závěr transakční zpracování.

REST API v oblasti párování plateb nabízí řadu možnosti, některé z nich si ukážeme na příkladech. Pokladnu nebo banku lze spárovat s jednou nebo více fakturami vydanými nebo přijatými.

Jelikož jsme na úrovni Ninja, nebudeme se zabývat tvorbou dokladů, kterou jsme se již naučili a přistoupíme rovnou k párování. Párování vždy zasíláme metodou POST buď na endpoint banka nebo pokladni-pohyb v závislosti, jaké doklady chceme párovat. Pojďme na příklad:

<?xml version="1.0"?> 
<winstrom version="1.0">
<banka>
<id>code:B+001/2021</id>
<sparovani>
<uhrazovanaFak type="faktura-vydana" castka="1000">
code:FV1
</uhrazovanaFak>
<uhrazovanaFak type="faktura-vydana">code:FV2</uhrazovanaFak>
<zbytek>ignorovat</zbytek>
</sparovani>
</banka>
</winstrom>

První částí je identifikace banky, využíváme identifikace dle interního číslo. Zároveň lze v tomto kroku banku i založit, tedy pokud uvedeme další povinné informace evidence banka, můžeme bankovní pohyb rovnou založit. Poté přichází samotné sparovani. Jak název elementu uhrazovanaFak napovídá, specifikujeme zde, jaký doklad uhrazujeme. V jednom spárování lze uhrazovat více faktur najednou. Při spárování s více fakturami musí být všechny uvedené faktury stejného typu faktury (vydané nebo přijaté). U každé uhrazované faktury lze uvést atribut castka, jehož hodnota omezuje celkovou částku k úhradě, která bude z faktury uhrazena. Hodnota atributu castka nesmí překročit zbývající částku k úhradě na uhrazované faktuře.

Další element je zbytek, který může nabývat více hodnot, protože zbytek může nastat, když uhrazující částka na uhrazujícím dokladu a součet částek na uhrazovaných fakturách nesouhlasí (např. při kurzovém rozdílu a nebo schází doplatit pár korun). Možné hodnoty jsou:

  • ne: zbytek nesmí nastat; pokud k němu dojde, API vrátí chybu

  • zauctovat: zbytek se zaúčtuje

  • ignorovat: zbytek se ignoruje

  • castecnaUhrada: pokud je částka na uhrazujícím dokladu menší než na uhrazovaném, jedná se o částečnou úhradu

  • castecnaUhradaNeboZauctovat: pokud je částka na uhrazujícím dokladu větší než na uhrazovaném, zbytek se zaúčtuje; pokud je menší, jedná se o částečnou úhradu

  • castecnaUhradaNeboIgnorovat: pokud je částka na uhrazujícím dokladu větší než na uhrazovaném, zbytek se ignoruje; pokud je menší, jedná se o částečnou úhradu

Ninjo, nyní znáš princip, jistě tě napadá, co se stane, když se liší měna dokladů? Lze spárovat pokladnu nebo banku v domácí měně s fakturami v cizí měně. Krásný příklad pro trénink!

Párování bychom měli, co když potřebujeme odpárovat? To je velmi jednoduché, bez atributů a velmi obdobné sparovani existuje odparovani. POST metoda, požadavek na totožný endpoint banka nebo pokladni-pohyb a tělo požadavku vypadá následovně:

<?xml version="1.0"?> 
<winstrom version="1.0">
<banka>
<id>code:B+001/2021</id>
<odparovani>
<uhrazovanaFak type="faktura-vydana">code:FV1</uhrazovanaFak>
</odparovani>
</banka>
</winstrom>


Opět lze uvést více uhrazovaných faktur nebo také žádnou, odpárují se tak všechny navázané na daný bankovní pohyb.

API samozřejmě nabízí i automatické párování, které má řadu možných nastavení, aby byl API Ninja chvat, co nejefektivnější. Opět posíláme POST požadavek:

Použili jsme filtraci na bankovní pohyby vystavené od 1. 10. 2021 a dále několik parametrů, které nám dovolují párování řídit. Možnosti jsou následující:

mod – mód automatického párování:

  • varCasUcet: párovat dle variabilního sym. a částky a účtu

  • varCas: párovat dle variabilního sym. a částky (výchozí hodnota)

  • jenVar: párovat dle variabilního sym.

  • jenCastka: připojit – párovat kdy souhlasí částka a nesouhlasí VS

obdobi – v kterých obdobích se budou hledat doklady k úhradě

  • aktualni: aktuální účetní období

  • aktualni-predchozi: aktuální i předchozí účetní období

  • vsechna: všechna účetní období (výchozí hodnota)

ignorovat-rozdil-castka – jak velký rozdíl mezi úhradou a uhrazovaným dokladem ignorovat (výchozí hodnota 0.0 – částky musí odpovídat, v módu jenVar se nastavení rozdílu ignoruje)

zauctovat-rozdil – zda se zaúčtují doklady pokud dojde ke spojení úhrad, kdy nejsou částky dokladů shodné (výchozí hodnota true – vznikne interní doklad na rozdíl mezi doklady a doklady budou plně spárovány)

Ninjo, v oblasti služeb API je stále co prozkoumávat, na to nám ovšem trénink nestačí - vazby ZDD, zápočty, přiznání DPH, inicializace období, a další. Nudit se nelze, trénovat a zlepšovat ano!

Pomocí volání /query lze zaslat všechny parametry a filtry, které se standardně posílají v URL adrese, pomocí těla volání. V této dokumentaci si popíšeme základní funkčnost. V těle volání POST lze zaslat úroveň detailu, stránkování, filtraci apod. Pro /query vždy používáme HTTP metodu POST. Aktuálně je /query dostupné pouze ve formátu JSON. Ukážeme si příklad nad fakturou vydanou, volání standardně vypadá takto:


Tělo pak může vypadat například takto:

{ "winstrom": { 

"detail":"custom:kod,nazFirmy,datVyst,datSplat,zbyvaUhradit,
storno,juhSum,sumCelkem,stavUhrK,sumCelkemMen,mena(kod),
stredisko(nazev,kod,id),typDokl(typDoklK)",

"includes":"/faktura-vydana/mena,/faktura-vydana/stredisko,/faktura-vydana/typDokl",

"filter":"(kod like \"2021\" and datSplat lt now() and mena eq \"31\" and typDokl eq \"code:FAKTURA\")",

"no-ext-ids":"true",
}
}

Filtr obsahuje logické operátory and nebo or případně další, jak je uvedeno v dokumentaci filtrace. Dále jsou zde escapovány významové uvozovky pomocí zpětných lomítek pro zápis řetězců. Také si můžete všimnou funkce now(), která zajišťuje předání dnešního data. Možná je i kombinace, kdy některé parametry zapíšeme do URL:

Tělo je pak totožné:

{ "winstrom": { 
"detail":"custom:kod,sumCelkem,varSym,typDokl,firma(email,tel)",

"limit":"0",

"filter" : "(datVyst > 2021-06-01) and typDokl = \"code:OBP\" ",

"includes":"/faktura-vydana/stredisko",

"order":["sumCelkem","kod"],
}
}

Jedná se o jiný přístup k API, například pokud chcete získávat data pomocí POST požadavků a nechcete parametry uvádět v adrese, kde je může uživatel vidět.

Poslední co si v dnešním tréninku ukážeme, je transakční zpracování. Ve výchozím nastavení se každý import přes REST API provádí jako jedna databázová transakce – tedy buď se uloží všechno, co zašleme nebo vůbec nic. Toto chování lze ale změnit pokročilou variantu XML importu, která při nevhodném použití může vést k nekonzistenci dat. Trénujeme, takže se není čeho bát!

Ukážeme si rovnou příklad. Představme si situaci, kdy tvoříme faktury vydané a zasíláme tento požadavek:

<winstrom version="1.0" atomic="false">
<skupina-zbozi update="ignore">
<kod>VYBAVENI</kod>
<id>code:VYBAVENI</id>
<nazev>Ninjovské vybavení</nazev>
</skupina-zbozi>
<cenik>
<nazev>Ninjovské ostří</nazev>
<id>code:NINJAOSTRI</id>
<typZasobyK>typZasoby.zbozi</typZasobyK>
<skupZboz>code:VYBAVENI</skupZboz>
</cenik>
</winstrom>

Může ovšem nastat situace, kdy transakční chování není nutné, pak lze atributem atomic toto chování změnit. Pokud nastavíte atribut atomic na hodnotu false, importuje se každý záznam v samostatné transakci. Tedy v příkladu výše proběhnou dvě databázové transakce, jedna pro skupinu zboží VYBAVENI, druhá pro ceník NINJAOSTRI. Pokud některý import sleže další se může bez problému dokončit.

Jaký to přináší užitek? Když importujete velká XML s mnoha záznamy, například dávku faktur, transakce trvá dlouho a mnoho informací se musí držet v paměti. Obojí má nepříznivý vliv na výkon. Pokud je ale každý záznam samostatný a nevadí, že uložení některého z nich selže (např. když import pravidelně opakujete a/nebo dokážete v případě problémů zasáhnout ručně), můžete podstatně snížit paměťovou náročnost importu.

To je pro dnešní trénink vše Ninjo, je čas trénovat samostatně. Doporučujeme různé kombinace dnes naučeného.

Není čas ztrácet čas, můžeš pokračovat na poslední trénink - uživatelské tlačítko

Dostali jste odpověď na svou otázku?