abra-flexi 0.5.7 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,7 @@ Místo npm použíjte přímo git repository a `npm link` (knihovnu mustí nejd
22
22
  git checkout git@github.com:tomasKavan/abraFlexiClient.git
23
23
  cd abraFlexiClient
24
24
  npm install
25
- npm run build:lib
25
+ npm run build
26
26
  npm link
27
27
  ```
28
28
 
@@ -32,13 +32,13 @@ Ve svém projektu potom:
32
32
  npm link abra-flexi
33
33
  ```
34
34
 
35
- ### Gnerování evidenčních tříd
35
+ ### Generování evidenčních tříd
36
36
 
37
37
  Součástní repository knihovny je nástroj pro generování evidenčních tříd z metadat, které poskytuje API. Generátor dovoluje vybrat subset generovaných tříd. To je užitečné, pokud chcete udržet knihovnu co nejmenší a generovat pouze třídy pro Vámi použivané evidence.
38
38
 
39
39
  Generátor je třeba přeložit
40
40
  ```
41
- npm run build:cli
41
+ npm run build:gen
42
42
  chmod a+x ./bin/index.js
43
43
  ```
44
44
 
@@ -49,7 +49,7 @@ a následně lze generování spustit například takto:
49
49
 
50
50
  knihovnu s vygenerovanými třídami lze přeložit
51
51
  ```
52
- npm run build:cli
52
+ npm run build
53
53
  ```
54
54
 
55
55
  ### Příklady
@@ -69,21 +69,46 @@ ts-node examples/createAndSave.ts -s https://muj.server.cz -c moje-firma -u uziv
69
69
 
70
70
  V návodu se používají pojmy
71
71
  - **evidence** Typ evidence v systému ABRA Flexi, například Faktura přijatá či Položka faktury přijaté. Každá evidence je reprezentováná evidenční třídou, například `AFFakturaPrijata` či `AFPolozkaFakturyPrijate`.
72
- - **instance** Záznam v evidenci. Například faktura přijatá s kódem IV24.0001, identifikátorem 14 a dlšími hodnotami je instancí. Instance je v knihovně reprezentována instancí evidenční třídy, například: `const fp = new AFFakturaPrijata()`.
72
+ - **instance** Záznam v evidenci. Například faktura přijatá s kódem IV24.0001, identifikátorem 14 a dlšími hodnotami je instancí. Instance je v knihovně reprezentována instancí evidenční třídy, například: `const fp = await api.create(AFFakturaPrijata)`.
73
73
 
74
74
  ### Import a inicializace knihovny
75
75
 
76
76
  ```typescript
77
- import { AFApiClient } from 'abra-flexi'
77
+ import { AFApiClient, AFApiConfig } from 'abra-flexi'
78
78
 
79
79
  const apiOpts: AFApiConfig = {
80
80
  url: '<doplnte_server>',
81
- company: '<doplnte_spolecnost>
81
+ company: '<doplnte_spolecnost>'
82
82
  }
83
83
 
84
84
  const api = new AFApiClient(apiOpts)
85
85
  ```
86
86
 
87
+ ### Logování
88
+
89
+ Ve výchozím stavu je klient tichý (nevypisuje nic). Logování lze zapnout pomocí `logLevel`:
90
+
91
+ ```typescript
92
+ const api = new AFApiClient({
93
+ url: '<server>',
94
+ company: '<spolecnost>',
95
+ logLevel: 'debug' // 'none' | 'error' | 'warn' | 'info' | 'debug'
96
+ })
97
+ ```
98
+
99
+ Je možné také předat vlastní logger (např. Winston), který musí implementovat rozhraní `{ debug, info, warn, error }`:
100
+
101
+ ```typescript
102
+ import winston from 'winston'
103
+
104
+ const api = new AFApiClient({
105
+ url: '<server>',
106
+ company: '<spolecnost>',
107
+ logger: winston.createLogger({ ... }),
108
+ logLevel: 'info' // pokud neuvedete, přeposílají se všechny úrovně
109
+ })
110
+ ```
111
+
87
112
  ### Dotazování instancí
88
113
 
89
114
  Pro dotazování instancí jsou k dispozici metody `query` (vrací kolekci instancí evidenčních tříd) a `queryOne` (vrací jedu instanci).
@@ -92,7 +117,7 @@ Parametrech dotazu může být uveden požadovaný detail. Detail se zapisuje fo
92
117
 
93
118
  Pozor! Vnořené M:N či 1:N relací knihovna zatím podporuje pouze na základní úrovni. Například detail `faktura-vydana-polozka.cenik.atributy.typAtributu` se načte pouze po instanci ceníku. Bude řešeno v dalších verzích.
94
119
 
95
- Filtrování je možné vkládat pomocí metod `Filter(expr, params)`, `ID(id)` nebo `CODE(code)`. Metoda `Filter` akceptuje textovou šablonu (`expr`), ve které budou všechny návěstí nahrazeny hodnotami předanými ve druhém argumentu (`params`). Návěstí mohou být:
120
+ Filtrování je možné vkládat pomocí metod `Filter(expr, params)`, `ID(id)`, `CODE(code)` nebo `EXT(ext)`. Metoda `Filter` akceptuje textovou šablonu (`expr`), ve které budou všechny návěstí nahrazeny hodnotami předanými ve druhém argumentu (`params`). Návěstí mohou být:
96
121
  - `:key` se nahradí textovou hodnotou klíče `key` ve druhém argumentu,
97
122
  - `::mujKod` se nahradí textovou hodnotou klíče `mujKod` ve druhém argumentu a prefixuje se předponou `code:`,
98
123
 
@@ -114,11 +139,9 @@ const queryOpts: AFQueryOptions = {
114
139
  filter: Filter(`typDokl = '::td'`, { td: 'MUJ_TYP_DOKLADU'})
115
140
  }
116
141
 
117
- const query = api.query(AFInterniDoklad, queryOpts)
118
-
119
142
  const run = async () => {
120
143
  try {
121
- const data = await query
144
+ const data = await api.query(AFInterniDoklad, queryOpts)
122
145
  console.log(data)
123
146
  } catch (e) {
124
147
  console.error(e)
@@ -128,6 +151,35 @@ run()
128
151
 
129
152
  ```
130
153
 
154
+ ### Stránkování a celkový počet záznamů
155
+
156
+ Dotazy podporují parametry `limit` a `start` pro stránkování. Pro zjištění celkového počtu záznamů (nezávislého na velikosti stránky) předejte `addRowCount: true`. Výsledek metody `query()` je standardní pole, ale navíc obsahuje vlastnost `totalCount` s celkovým počtem nalezených záznamů na serveru.
157
+
158
+ ```typescript
159
+ const PAGE_SIZE = 50
160
+
161
+ const firstPage = await api.query(AFAdresar, {
162
+ detail: ['id', 'kod', 'nazev'],
163
+ limit: PAGE_SIZE,
164
+ start: 0,
165
+ addRowCount: true // vyžádá @rowCount od serveru
166
+ })
167
+
168
+ console.log(firstPage.totalCount) // např. 1234 — celkový počet, bez ohledu na limit
169
+ console.log(firstPage.length) // 50 — velikost stránky
170
+
171
+ const totalPages = Math.ceil(firstPage.totalCount! / PAGE_SIZE)
172
+
173
+ // Další stránky — addRowCount není třeba opakovat (zvyšuje zátěž serveru)
174
+ const secondPage = await api.query(AFAdresar, {
175
+ detail: ['id', 'kod', 'nazev'],
176
+ limit: PAGE_SIZE,
177
+ start: PAGE_SIZE
178
+ })
179
+ ```
180
+
181
+ > **Poznámka:** `addRowCount: true` způsobí extra COUNT dotaz na straně serveru. Používejte ho pouze pro první stránku a hodnotu `totalCount` si uložte pro výpočet dalších stránek.
182
+
131
183
  ### Načtení většího detailu
132
184
 
133
185
  Pro načtení většího detailu či aktualizaci dříve načtených instancí můžete použít metody `populate` a `populateOne`. Detailem požadované vlastnosti se aktualizují na původní instanci.
@@ -139,11 +191,9 @@ const options = {
139
191
  detail: AFQueryDetail.FULL
140
192
  }
141
193
 
142
- const populate = api.populateOne(loadEntity)
143
-
144
194
  const run = async () => {
145
195
  try {
146
- const populatedEntity = await populate
196
+ const populatedEntity = await api.populateOne(loadedEntity, options)
147
197
  console.log(populatedEntity)
148
198
  console.log(populatedEntity === loadedEntity) // Vypíše true
149
199
  } catch (e) {
@@ -156,20 +206,18 @@ run()
156
206
 
157
207
  ### Načtení instancí z uživatelských vazeb
158
208
 
159
- Instance entit odkazované pomocí uživatelských vazeb je možné načíst metodou `queryURel`. Metodě je třeba zaslat zdrojovou kolekci instancí. Instance neumsí být stejného typu (evidence), ale musí mít klíč `uzivatelske-vazby`. Metoda načítá vazby na kokrétní evidenci (vazby ostatních typů jsou vynechány). Vazby je možné filtrovat dle typu `typVazby`. Načtená data jsou přidána do vazeb zrojových instancí (vlastnost `object`). Data jsou dále vrácena jako kolekce párů `{ entity: zdrojova_entity, referencedFrom: načtená_entita }`.
209
+ Instance entit odkazované pomocí uživatelských vazeb je možné načíst metodou `queryURels`. Metodě je třeba zaslat zdrojovou kolekci instancí. Instance neumsí být stejného typu (evidence), ale musí mít klíč `uzivatelske-vazby`. Metoda načítá vazby na kokrétní evidenci (vazby ostatních typů jsou vynechány). Vazby je možné filtrovat dle typu `typVazby`. Načtená data jsou přidána do vazeb zrojových instancí (vlastnost `object`). Data jsou dále vrácena jako kolekce párů `{ entity: zdrojova_entity, referencedFrom: načtená_entita }`.
160
210
 
161
- Načteny jsou pouze instance vazeb, které se již vyskytují ve zdrojové kolekci! Metoda `queryURel` tedy sama uživatelské vazby na jednotlivých zdrojových instancích nenačítá. Načítá pouze instance, na které vazba odkazuje.
211
+ Načteny jsou pouze instance vazeb, které se již vyskytují ve zdrojové kolekci! Metoda `queryURels` tedy sama uživatelské vazby na jednotlivých zdrojových instancích nenačítá. Načítá pouze instance, na které vazba odkazuje.
162
212
 
163
213
  ```typescript
164
214
  const soureEntities // Zde máme kolekci entit, pro které načítáme instance odkazované uživatelskou vazbou
165
215
 
166
- const query = api.queryURels(AFInterniDoklad, soureEntities, {
167
- detail: ['id', 'kod', 'typDokl']
168
- })
169
-
170
216
  const run = async () => {
171
217
  try {
172
- const pairs = await query
218
+ const pairs = await api.queryURels(AFInterniDoklad, soureEntities, {
219
+ detail: ['id', 'kod', 'typDokl']
220
+ })
173
221
  console.log(pairs)
174
222
  } catch (e) {
175
223
  console.error(e)
@@ -181,11 +229,103 @@ run()
181
229
 
182
230
  ### Práce se štítky
183
231
 
184
- *TODO: Přidat popis*
232
+ Štítky (stitky) jsou na každé instanci dostupné jako textový řetězec ve vlastnosti `stitky`. Pro pohodlnější práci jsou k dispozici metody `getStitky()` a `getStitkyBySkupina(skup)`, které vrací pole instancí `AFStitek`.
233
+
234
+ Knihovna udržuje interní cache štítků, která se průběžně aktualizuje. Strategii cache lze nastavit v konfiguraci klienta pomocí `stitkyCacheStrategy` (`None`, `Lazy` (výchozí), `Eager`).
185
235
 
186
236
  ### Vytváření, změna a odstraňování instancí
187
237
 
188
- *TODO: Přidat popis*
238
+ #### Vytvoření nové instance
239
+
240
+ Novou instanci evidence vytvoříte pomocí `api.create()`. **Nepoužívejte `new` přímo** — konstruktor vyžaduje interní závislosti, které správně injektuje pouze klient.
241
+
242
+ ```typescript
243
+ import { AFFakturaVydana } from 'abra-flexi'
244
+
245
+ const faktura = await api.create(AFFakturaVydana)
246
+ faktura.popis = 'Testovací faktura'
247
+ // ... nastavte další vlastnosti
248
+
249
+ const saved = await api.save(faktura)
250
+ console.log(saved.id) // ID přidělené serverem je automaticky přiřazeno zpět na instanci
251
+ ```
252
+
253
+ #### Odkaz na existující záznam bez načítání
254
+
255
+ Pokud potřebujete odkázat na existující záznam (např. jako relaci na jiné entitě), ale nechcete ho načítat, použijte `createIdStub()`:
256
+
257
+ ```typescript
258
+ const firma = await api.createIdStub(AFAdresar, { id: 123 })
259
+ // nebo podle kódu:
260
+ const firma = await api.createIdStub(AFAdresar, { kod: 'MOJE_FIRMA' })
261
+ ```
262
+
263
+ Instance vytvořená přes `createIdStub()` je správně označena jako existující (`isNew === false`) a lze ji použít v relacích jiných entit.
264
+
265
+ #### Uložení změn
266
+
267
+ Metoda `save()` uloží jak novou instanci (POST/PUT), tak změny na existující. Na server se odesílají pouze změněné vlastnosti.
268
+
269
+ ```typescript
270
+ const faktura = await api.queryOne(AFFakturaVydana, { filter: ID(42) })
271
+ faktura.popis = 'Aktualizovaný popis'
272
+ await api.save(faktura)
273
+ ```
274
+
275
+ **Poznámka k uživatelským vazbám:** ABRA Flexi nepodporuje vytvoření nové entity společně s uživatelskými vazbami v jednom požadavku. Pokud entita obsahuje `uzivatelske-vazby`, je třeba ji nejdříve uložit bez vazeb a vazby přidat v samostatném volání `save()`.
276
+
277
+ #### Smazání instance
278
+
279
+ ```typescript
280
+ await api.delete(faktura)
281
+ ```
282
+
283
+ Metoda funguje pro všechny typy evidencí, včetně `AFUzivatelskaVazba` (kde ABRA API nevystavuje standardní DELETE endpoint — knihovna to řeší automaticky).
284
+
285
+ ### Stahování souborů
286
+
287
+ Metoda `queryFile()` slouží ke stažení dat v jiném formátu než JSON — například PDF, XML, CSV nebo ISDOC. Vrací objekt `{ blob, contentType, filename }`.
288
+
289
+ ```typescript
290
+ import { AFFakturaVydana, ID } from 'abra-flexi'
291
+ import fs from 'fs'
292
+
293
+ // PDF faktury
294
+ const pdf = await api.queryFile(AFFakturaVydana, 'pdf', { filter: ID(42) })
295
+ fs.writeFileSync(pdf.filename ?? 'faktura.pdf', Buffer.from(await pdf.blob.arrayBuffer()))
296
+
297
+ // XML
298
+ const xml = await api.queryFile(AFFakturaVydana, 'xml', { filter: ID(42) })
299
+
300
+ // CSV kolekce
301
+ const csv = await api.queryFile(AFAdresar, 'csv', { limit: 100 })
302
+
303
+ // ISDOC / ISDOCX a další rozšíření
304
+ const isdocx = await api.queryFile(AFFakturaVydana, 'isdocx', { filter: ID(42) })
305
+ ```
306
+
307
+ #### Tisk pomocí pojmenované sestavy
308
+
309
+ Parametry `reportName` a `reportLang` umožňují zvolit konkrétní tiskovou sestavu:
310
+
311
+ ```typescript
312
+ const pdf = await api.queryFile(AFFakturaVydana, 'pdf', {
313
+ filter: ID(42),
314
+ reportName: 'faktura-dph',
315
+ reportLang: 'cs'
316
+ })
317
+ ```
318
+
319
+ ### Akce na instancích
320
+
321
+ Pojmenované akce definované v ABRA Flexi (např. storno, uzavření dokladu) lze volat metodou `callEntityAction()`. Instance musí být uložená (mít přidělené `id`).
322
+
323
+ ```typescript
324
+ import { AFFakturaVydana } from 'abra-flexi'
325
+
326
+ const faktura = await api.createIdStub(AFFakturaVydana, { id: 2452 })
327
+ await api.callEntityAction(faktura, 'storno')
328
+ ```
189
329
 
190
330
  ## Task list pro vydání stabilní verze
191
331
 
@@ -194,8 +334,10 @@ run()
194
334
  - [X] Načítání užviatelských relací
195
335
  - [X] Refersh již načtených dat
196
336
  - [X] Pohodlná práce se štítky
337
+ - [X] Vytváření, mazání a změna záznamů v REST API
338
+ - [X] Stahování souborů (PDF, CSV, XML, ISDOC, ...)
339
+ - [X] Akce na instancích
197
340
  - [ ] Jednotný handling identifikátorů záznamů
198
- - [x] Vytváření, mazání a změna záznamů v REST API
199
341
  - [ ] Lokální keš a společné instance pro jedno ID
200
342
  - [ ] Battle tested - reálné nasazení, úprava rozhraní dle reálného použití
201
343
  - [ ] Verzování, npm balíčkování
@@ -204,8 +346,8 @@ run()
204
346
 
205
347
  # English
206
348
 
207
- [ABRA Flexi]([https://www.abra.eu/flexi/](https://www.abra.eu/en/flexi/) is Czech ERP for small businesses, developer by [ABRA Software](https://www.abra.eu/en). To access data in ABRA Flexi there is a REST API with public documentation.
349
+ [ABRA Flexi](https://www.abra.eu/en/flexi/) is Czech ERP for small businesses, developed by [ABRA Software](https://www.abra.eu/en). To access data in ABRA Flexi there is a REST API with public documentation.
208
350
 
209
- ABRA Flexi Typescript client (AFTC) is library to call ABRA Fflexi REST API. It's for browsers and server environments (Node.js). It provides methods for CRUD.
351
+ ABRA Flexi Typescript client (AFTC) is library to call ABRA Flexi REST API. It's for browsers and server environments (Node.js). It provides methods for CRUD.
210
352
 
211
- Because ABRA Flexi is Czech software, it's expected to have mainly Czech developer audience. English version of the documentation will be finalized when the library API becomes stable.
353
+ Because ABRA Flexi is Czech software, it's expected to have mainly Czech developer audience. English version of the documentation will be finalized when the library API becomes stable.