Transformace dat, oprava ukladani udaju konektoru
Transformace dat ve dvou rezimech plus oprava chyby, kvuli ktere se neukladaly
pristupove udaje konektoru. Popis v documentation/13-transformace-dat.md.
Kroky si predavaji i cele struktury:
- FieldType ma object a list. Do sablony se nedosazuji, predavaji se jako celek
dalsimu kroku - proto je u nich v builderu vyber a ne textove pole. Z podminek
nad nimi ma smysl jen "prisla / neprisla"
- strop na velikost struktury (SCRIPT_MAX_VALUE_BYTES, vychozi 256 kB). Radek
s vystupem kroku je nejrychleji rostouci tabulka v systemu
Dva rezimy transformace, oba nad enginem v src/scripts/mapping.ts:
- transform.map-fields: pole na pole s prevody, klikatelne
- transform.to-json: sablona cileveho objektu s ${cesta}
Marker ${...} je zamerne jiny nez {{...}}. Sablony kroku se dosazuji driv, nez
krok bezi, takze {{total}} by strom stihl vyhodnotit, nenasel by parametr toho
jmena a dosadil by prazdno. Cely retezec navic zachova typ, takze
"unitPrice": "${total}" vyrobi cislo - jinak by cizi sluzba dostala castku jako
text a odmitla ji.
Prevod map pro seznamy je to, bez ceho by priklad nesel dokoncit. Bez nej jde
prevest hlavicku dokladu, ale ne polozky objednavky, a doklad by byl na nulu.
Dal pridano:
- idoklad.create-invoice-from-object: druha polovina prikladu, bere hotove telo
dokladu z transformace a doplni povinna pole ze vzoru iDokladu
- spoustec e-shopu predava celou objednavku jako objekt a polozky jako seznam
- klikaci editor pravidel vcetne rezimu JSON pro vnorena pravidla u map
- kontrola JSONu a tvaru pravidel uz pri ulozeni stromu. Preklep je nedodelek,
ne chyba ukladani - rozdelana prace se nezahazuje
Opraveno: konektor neukladal pristupove udaje. Server byl v poradku, overeno
volanim POST i PATCH. Chyba byla v prohlizeci: u pole type="password" prohlizec
ignoruje autocomplete="off" a dosazuje ulozene prihlaseni. Uzivatel pak videl
jednu hodnotu, React drzel jinou, a ulozilo se to, co drzel React, tedy nic.
Resi to autocomplete="new-password", jmena poli, ktera nepripominaji heslo,
a prepinac zobrazeni, aby slo overit, co je opravdu zapsane.
Zakladani a uprava konektoru se presunuly do dialogu, na strance jsou jen male
karty. Formulare rozlozene po strance byly u vic konektoru neprehledne.
Overeno: npm run typecheck prochazi na serveru i webu, node --check na skriptech.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8ad91a6c28
commit
ad56c7f513
@@ -32,6 +32,7 @@ React aplikaci ze slozky `dist/public`.
|
||||
| Nastavitelny dashboard | hotovo | widgety, sirky a poradi, ulozene za uzivatele a firmu |
|
||||
| Skripty konektoru | hotovo | manifest, kontrola parametru, hot reload, iDoklad |
|
||||
| Konektory za firmu | hotovo | pristupove udaje v konektoru, overeni napojeni |
|
||||
| Transformace dat | hotovo | pravidla i sablona JSON, kroky si predavaji struktury |
|
||||
| Sprava clenstvi z portalu | chybi | memberships jdou zmenit jen v kodu |
|
||||
| Bugs a wishes | chybi | vyvojarska agenda, samostatna evidence vedle ticketu |
|
||||
| Beh automatizaci | chybi | ulozeny strom se nevykonava, neni runtime |
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
# 13 - Transformace dat
|
||||
|
||||
Naprogramovano. Souvisi se skripty ([11](11-skripty-konektoru.md))
|
||||
a se sluzbami ([12](12-sluzby-a-konektory.md)).
|
||||
|
||||
## K cemu to je
|
||||
|
||||
Prijde objednavka z e-shopu a do iDokladu je potreba uplne jiny objekt. Jmena
|
||||
poli nesedi, castky jsou textem, polozky maji jinou strukturu. Mezi tim musi byt
|
||||
krok, ktery rekne, co se kam prepise a jak se to po ceste prevede.
|
||||
|
||||
```
|
||||
Nova objednavka (e-shop) -> objekt "order"
|
||||
Transformace dat -> objekt "result" ve tvaru dokladu
|
||||
Vystavit fakturu z objektu -> iDoklad
|
||||
```
|
||||
|
||||
## Kroky si predavaji i cele struktury
|
||||
|
||||
Dosud si kroky predavaly jen jednotlive hodnoty. Pribyly dva typy parametru:
|
||||
|
||||
| Typ | Co to je | Do sablony | Podminka |
|
||||
| -------- | --------------------------- | ---------- | ----------------- |
|
||||
| `object` | cely objekt | ne | je / neni prazdny |
|
||||
| `list` | seznam | ne | je / neni prazdny |
|
||||
|
||||
**Do sablony se nedosazuji.** `{{order}}` v textu by znamenalo vlozit do vety
|
||||
kus JSONu, coz nikdo nechce. Struktura se predava **jako celek** dalsimu kroku,
|
||||
proto je u ni v builderu vyber a ne textove pole.
|
||||
|
||||
Nad strukturou ma z podminek smysl jen "prisla / neprisla". Porovnavat dva
|
||||
objekty by znamenalo urcit, co je "stejny", a to zavisi na pripadu.
|
||||
|
||||
**Strop na velikost.** Struktura nad `SCRIPT_MAX_VALUE_BYTES` (vychozi 256 kB)
|
||||
neprojde kontrolou. Radek s vystupem kroku je nejrychleji rostouci tabulka
|
||||
v systemu (viz [10-runtime-a-kapacita.md](10-runtime-a-kapacita.md)), takze
|
||||
hranice patri do kontroly parametru, ne az do uklidu databaze.
|
||||
|
||||
## Dva rezimy
|
||||
|
||||
Obe moznosti stoji na tom samem enginu v `src/scripts/mapping.ts`.
|
||||
Volba je o tom, cehoz je vic:
|
||||
|
||||
| Rezim | Kdy | Skript |
|
||||
| ------------------------- | -------------------------------------- | ----------------------- |
|
||||
| **Pravidla** (pole na pole) | hlavni prace je v prevodech hodnot | `transform.map-fields` |
|
||||
| **Sablona JSON** | hlavni prace je ve tvaru struktury | `transform.to-json` |
|
||||
|
||||
### Rezim 1: pravidla
|
||||
|
||||
Jedno pravidlo je "vezmi tuhle cestu, projed prevody, uloz sem".
|
||||
|
||||
```json
|
||||
[
|
||||
{ "to": "partnerId", "from": "customer.idokladId", "required": true },
|
||||
{ "to": "description", "from": "number", "transforms": [{ "op": "string" }] },
|
||||
{ "to": "dateOfIssue", "from": "createdAt", "transforms": [{ "op": "date", "format": "day" }] },
|
||||
{ "to": "variableSymbol", "from": "number", "omitIfEmpty": true },
|
||||
{
|
||||
"to": "items",
|
||||
"from": "items",
|
||||
"transforms": [
|
||||
{
|
||||
"op": "map",
|
||||
"rules": [
|
||||
{ "to": "name", "from": "title", "required": true },
|
||||
{ "to": "amount", "from": "quantity", "transforms": [{ "op": "number" }] },
|
||||
{ "to": "unitPrice", "from": "priceWithoutVat", "transforms": [{ "op": "number" }, { "op": "round", "decimals": 2 }] },
|
||||
{ "to": "unit", "value": "ks" },
|
||||
{ "to": "priceType", "value": 0 },
|
||||
{ "to": "vatRateType", "value": 0 },
|
||||
{ "to": "discountPercentage", "value": 0 },
|
||||
{ "to": "isTaxMovement", "value": false }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Prevod `map` je to, bez ceho by priklad nesel dokoncit. Bez nej by slo prevest
|
||||
hlavicku dokladu, ale ne seznam polozek, a doklad by byl na nulu.
|
||||
|
||||
| Klic | K cemu |
|
||||
| ------------- | --------------------------------------------------------- |
|
||||
| `to` | kam se ulozi. Tecka znamena zanoreni: `partner.id` |
|
||||
| `from` | cesta ve zdroji. `items.0.name` i `items[0].name` |
|
||||
| `value` | pevna hodnota, kdyz `from` chybi |
|
||||
| `transforms` | prevody v uvedenem poradi |
|
||||
| `fallback` | pouzije se, kdyz je vysledek prazdny |
|
||||
| `omitIfEmpty` | prazdny vysledek se do vystupu vubec nezapise |
|
||||
| `required` | prazdny vysledek je chyba |
|
||||
|
||||
`required` neni formalita. Doklad bez `partnerId` iDoklad odmitne, a je lepsi
|
||||
to poznat na kroku transformace s nazvem pole, nez z odpovedi 400 od iDokladu.
|
||||
|
||||
### Rezim 2: sablona JSON
|
||||
|
||||
Napise se cely cilovy objekt a na mistech hodnot se odkaze pres `${cesta}`:
|
||||
|
||||
```json
|
||||
{
|
||||
"partnerId": "${customer.idokladId}",
|
||||
"description": "Objednávka ${number}",
|
||||
"dateOfIssue": "${createdAt}",
|
||||
"items": [{ "name": "Zboží dle objednávky", "unitPrice": "${total}", "amount": 1 }]
|
||||
}
|
||||
```
|
||||
|
||||
Dve veci, ktere v tom rezimu rozhoduji:
|
||||
|
||||
**Marker je `${...}`, ne `{{...}}`.** Sablony kroku se dosazuji driv, nez se
|
||||
krok spusti. `{{total}}` by tedy stihl vyhodnotit strom, zadny parametr toho
|
||||
jmena by nenasel a dosadil by prazdno. Rozdilny marker to nemuze splest.
|
||||
|
||||
**Cely retezec zachova typ.** `"unitPrice": "${total}"` vyrobi **cislo**, ne
|
||||
text. Bez toho by cizi sluzba dostala castku jako retezec a vetsina jich to
|
||||
odmitne. Uvnitř delsiho textu (`"Objednávka ${number}"`) se naopak vklada
|
||||
jako text, protoze jinak to nedava smysl.
|
||||
|
||||
## Prevody
|
||||
|
||||
| Prevod | Co dela |
|
||||
| ----------------------------- | ---------------------------------------- |
|
||||
| `trim`, `lower`, `upper` | uprava textu |
|
||||
| `string`, `number`, `boolean` | zmena typu |
|
||||
| `date` (`iso` / `day`) | datum, `day` je jen `YYYY-MM-DD` |
|
||||
| `round` (`decimals`) | zaokrouhleni |
|
||||
| `multiply`, `add` (`by`) | pocty, napriklad prevod na cenu s DPH |
|
||||
| `default` (`value`) | vyplneni prazdne hodnoty |
|
||||
| `replace` (`find`, `with`) | nahrazeni textu |
|
||||
| `slice` (`start`, `end`) | cast textu nebo seznamu |
|
||||
| `split`, `join` (`separator`) | text na seznam a zpatky |
|
||||
| `sum` (`path`) | soucet pres seznam |
|
||||
| `count` | pocet polozek |
|
||||
| `map` (`rules`) | kazdou polozku seznamu podle vlastnich pravidel |
|
||||
|
||||
Sada je zamerne **uzavrena**. Volny vyraz by z transformace udelal dalsi jazyk
|
||||
k ladeni a hlavne by to byl kod bez sandboxu na miste, kde ho nikdo neceka.
|
||||
Kdo potrebuje vic, napise skript.
|
||||
|
||||
## Kontrola
|
||||
|
||||
| Kdy | Co se overi | Vysledek |
|
||||
| ----------------- | ---------------------------------------------------- | --------- |
|
||||
| Pri psani | JSON se parsuje, chyba se ukaze hned pod polem | jen v UI |
|
||||
| Pri ulozeni stromu| JSON a tvar pravidel (`to`, `from`/`value`, `op`) | nedodelek |
|
||||
| Pri behu | typy, `required`, prazdne hodnoty, hloubka zanoreni | chyba behu|
|
||||
|
||||
Rozbite pravidlo je **nedodelek**, ne chyba ukladani. Rozdelana prace se
|
||||
nezahazuje, jen automatizace nepujde zapnout. Stejny rezim jako u ostatnich
|
||||
nedodelku, viz [05-dashboard-a-builder.md](05-dashboard-a-builder.md).
|
||||
|
||||
Neznamy prevod je pri behu chyba, ne preskoceni. Tise ho ignorovat by znamenalo
|
||||
odeslat neprevedena data a divit se az u odberatele.
|
||||
|
||||
## Kde to je
|
||||
|
||||
```
|
||||
src/scripts/mapping.ts engine: cesty, prevody, pravidla, sablona
|
||||
scripts/transform.map-fields.js rezim 1
|
||||
scripts/transform.to-json.js rezim 2
|
||||
scripts/idoklad.create-invoice-from-object.js druha polovina prikladu
|
||||
web/src/components/dashboard/flow/MappingEditor.tsx klikaci editor pravidel
|
||||
web/src/components/dashboard/flow/StepInputs.tsx pole typu mapping, json a object
|
||||
```
|
||||
|
||||
Engine je na serveru a skripty ho dostanou na `ctx.util` jako `get`, `applyRules`
|
||||
a `fillJson`. Nemuze byt v souboru skriptu, protoze skripty nic neimportuji -
|
||||
a nema tam byt, protoze by ho jinak mel kazdy skript ve vlastni verzi.
|
||||
|
||||
## Cely priklad
|
||||
|
||||
```
|
||||
Spoustec: Nova objednavka (e-shop)
|
||||
vystupy: orderNumber, orderTotal, customerEmail, order (objekt), items (seznam)
|
||||
|
||||
Krok 1: Premapovat pole
|
||||
Zdrojova data: order
|
||||
Pravidla: viz vyse
|
||||
vystup: result (objekt), fieldCount
|
||||
|
||||
Krok 2: Vystavit fakturu z objektu (iDoklad)
|
||||
Telo dokladu: result
|
||||
vystupy: invoiceId, documentNumber, totalWithVat, itemCount, invoice
|
||||
|
||||
Krok 3: Odeslat fakturu e-mailem (iDoklad)
|
||||
ID faktury: {{invoiceId}}
|
||||
E-mail: {{customerEmail}}
|
||||
```
|
||||
|
||||
Krok 2 doplni z `GET /issued-invoices/default` povinna pole, ktera z objednavky
|
||||
nikdy neprijdou (`documentSerialNumber`, `isEet`, `isIncomeTax`). Objekt
|
||||
z transformace ho prepise jen tam, kde neco rika.
|
||||
|
||||
## Co chybi
|
||||
|
||||
| Chybi | Poznamka |
|
||||
| --------------------------- | ------------------------------------------------------- |
|
||||
| Nahled transformace | pravidla jde zkusit jen pres test skriptu |
|
||||
| Vnorena pravidla klikanim | prevod `map` se upravuje v rezimu JSON |
|
||||
| Napoveda cest ze skutecnych dat | nabizeji se jmena parametru, ne cesty uvnitr objektu |
|
||||
| Vykonavani ze stromu | runner je hotovy, runtime automatizaci ne |
|
||||
@@ -2,6 +2,44 @@
|
||||
|
||||
Nejnovejsi nahore.
|
||||
|
||||
## 2026-08-12 - transformace dat a oprava konektoru
|
||||
|
||||
Transformace dat popsana v [13-transformace-dat.md](13-transformace-dat.md).
|
||||
|
||||
### Pridano
|
||||
|
||||
- Kroky si predavaji i cele struktury. `FieldType` ma `object` a `list`.
|
||||
Do sablony se nedosazuji, predavaji se jako celek dalsimu kroku - proto je
|
||||
u nich v builderu vyber a ne textove pole. Z podminek nad nimi ma smysl jen
|
||||
"prisla / neprisla".
|
||||
- Strop na velikost struktury (`SCRIPT_MAX_VALUE_BYTES`, vychozi 256 kB).
|
||||
Radek s vystupem kroku je nejrychleji rostouci tabulka v systemu.
|
||||
- `src/scripts/mapping.ts`: cesty, prevody, pravidla a sablona JSON.
|
||||
Skripty ho dostanou na `ctx.util` jako `get`, `applyRules` a `fillJson`.
|
||||
- Dva rezimy transformace: `transform.map-fields` (pole na pole s prevody)
|
||||
a `transform.to-json` (sablona cileveho objektu s `${cesta}`).
|
||||
V sablone je marker `${...}` zamerne jiny nez `{{...}}`: sablony kroku se
|
||||
dosazuji driv, nez krok bezi, a stihly by ji prepsat.
|
||||
- Prevod `map` pro seznamy. Bez nej by slo prevest hlavicku dokladu, ale ne
|
||||
polozky objednavky, a doklad by byl na nulu.
|
||||
- `idoklad.create-invoice-from-object`: druha polovina prikladu, bere hotove
|
||||
telo dokladu z transformace.
|
||||
- Spoustec e-shopu predava celou objednavku jako objekt a polozky jako seznam.
|
||||
- Klikaci editor pravidel v builderu vcetne rezimu JSON pro vnorena pravidla.
|
||||
- Kontrola JSONu a tvaru pravidel uz pri ulozeni stromu. Preklep je nedodelek,
|
||||
ne chyba ukladani - rozdelana prace se nezahazuje.
|
||||
|
||||
### Opraveno
|
||||
|
||||
- **Konektor neukladal pristupove udaje.** Server byl v poradku, chyba byla
|
||||
v prohlizeci: u pole `type="password"` prohlizec ignoruje `autocomplete="off"`
|
||||
a dosazuje ulozene prihlaseni. Uzivatel pak videl jednu hodnotu, React drzel
|
||||
jinou, a ulozilo se to, co drzel React, tedy nic. Resi to `autocomplete`
|
||||
`new-password`, jmena poli, ktera nepripominaji heslo, a prepinac zobrazeni,
|
||||
aby slo overit, co je opravdu zapsane.
|
||||
- Zakladani a uprava konektoru se presunuly do dialogu. Na strance jsou jen
|
||||
male karty - formulare rozlozene po strance byly u vic konektoru neprehledne.
|
||||
|
||||
## 2026-08-12 - sluzby a konektory
|
||||
|
||||
Rozdeleni na sluzbu a konektor. Popis
|
||||
|
||||
Reference in New Issue
Block a user