abra-flexi 0.6.0 → 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 +169 -27
- package/dist/index.cjs +236 -1237
- package/dist/index.d.cts +114 -248
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +114 -248
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +236 -1237
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
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
|
|
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
|
-
###
|
|
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:
|
|
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
|
|
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 =
|
|
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 `
|
|
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
|
|
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 `
|
|
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 `
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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](
|
|
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
|
|
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.
|