Návod k editaci JSON šablony — Tabulková sestava

Tento návod je určen pro úpravu JSON šablon tabulkových sestav (přehledy dokladů, účetní výpisy, ceníky apod.) ve VS Code s live preview.

Obsah:


Jak to funguje

┌───────────────────────────────────────────────────────────┐
│  XML data         +    JSON šablona    →    HTML / PDF    │
│  (z aplikace)          (vaše úpravy)        (výstup)      │
└───────────────────────────────────────────────────────────┘

XML data — připraví aplikace (FoxPro). Obsahují reálná data: čísla dokladů, názvy, ceny, datumy.

JSON šablona — tu upravujete vy. Říká rendereru, jak data zobrazit: které sloupce, jaké formáty, skupiny, součty.

Výstup — HTML (náhled v prohlížeči), PDF (tisk), XLSX (Excel).


Editace ve VS Code

Editaci spustíte z aplikace. Otevře se VS Code s JSON souborem a v prohlížeči se zobrazí HTML náhled.

Základní workflow

  1. Otevřete editaci z aplikace (tlačítko "Upravit šablonu")
  2. VS Code se otevře se JSON souborem, v prohlížeči se zobrazí náhled
  3. Upravte JSON šablonu ve VS Code
  4. Uložte (Ctrl+S) — náhled v prohlížeči se automaticky obnoví za ~2 sekundy
  5. Zkontrolujte výsledek v prohlížeči
  6. Opakujte kroky 3–5

VS Code nápověda (IntelliSense)

Pravidla JSON

Pozor: JSON soubor musí být validní JSON. Nejčastější chyby:

Tip: VS Code červeně podtrhne chybu. Ctrl+Z vrátí zpět poslední změnu.


Struktura JSON šablony

Šablona má tyto hlavní části:

{
  "renderer":   "table",      ← typ šablony (volitelné, pro jednoznačnou identifikaci)
  "aliases":    { ... },      ← zkratky pro dlouhé XML cesty (volitelné)
  "report":     { ... },      ← nastavení celé sestavy
  "header":     { ... },      ← záhlaví (firma, filtr, logo)
  "footer":     { ... },      ← zápatí
  "pageHeader": { ... },      ← záhlaví stránky (opakuje se)
  "pageFooter": { ... },      ← zápatí stránky (opakuje se)
  "i18n":       { ... },      ← překlady textů
  "sections":   [ ... ]       ← sekce s daty (tabulky)
}

1. Nastavení sestavy (report)

{
  "report": {
    "title": "Přehled dokladů",
    "culture": "cs-CZ",
    "orientation": "landscape",
    "pageSize": "A4"
  }
}

Nejčastější vlastnosti

Vlastnost Co dělá Příklad
renderer Typ šablony (volitelné — bez něj se typ pozná z obsahu JSON) "table"
title Název sestavy (zobrazí se v záhlaví) "Přehled dokladů"
culture Formát čísel a datumů "cs-CZ" (čárka), "en-US" (tečka)
orientation Orientace stránky "portrait" (na výšku), "landscape" (na šířku)
pageSize Velikost papíru "A4", "A3", "Letter"
pageBreak Nová stránka mezi skupinami při tisku true / false

Speciální vlastnosti

Vlastnost Co dělá Příklad
dataFontPt Velikost písma dat (v bodech) 6 (malé), 8 (normální), 10 (větší)
xlsxScale Zvětšení písma v Excelu 1.3 (o 30 % větší)
xlsxFreezeHeader Ukotvit záhlaví v Excelu (při scrollování) true
detailBorders Styl čar mezi řádky "all", "vertical", "none", "h-dashed"
filterFontSizePt Velikost fontu filtru (v bodech) 12 (pro podnadpis)
filterStyle Styl filtru "bold" (tučný), "normal" (normální)

Styly okrajů (detailBorders)

Hodnota Jak vypadá
"all" Všechny čáry (mřížka) — výchozí
"vertical" Jen svislé čáry mezi sloupci
"horizontal" Jen vodorovné čáry mezi řádky
"none" Bez vnitřních čar (vnější rámeček zůstává)
"inner-none" Bez čar (i bez rámečku)
"h-dashed" Vodorovné čárkované + svislé plné
"h-dashed-only" Jen vodorovné čárkované (bez svislých)

2. Záhlaví sestavy (header)

{
  "header": {
    "company": "EFES spol. s r.o.\nNeklanova 18\n128 00 Praha 2",
    "filter": "Období: leden 2026",
    "logoFile": "C:\\data\\logo.jpg"
  }
}
Vlastnost Co dělá Poznámka
company Název firmy (a adresa) \n = nový řádek. Ignoruje se, pokud XML obsahuje parametr.adresa1 (viz níže).
filter Popis filtru/období Zobrazí se pod názvem
logoFile Cesta k logu Zobrazí se vpravo nahoře

Logo může být i dynamické: "logoFile": "{header.logoFile}" — cesta se načte z XML dat.

Adresa firmy z XML — parametr.adresa1 a parametr.adresa2

Pokud XML data obsahují element parametr s atributy adresa1 a/nebo adresa2, renderer je automaticky použije pro adresu vlevo nahoře — bez ohledu na header.company v JSON:

loBuilder.Push("parametr")
loBuilder.AddAttribute("adresa1", "EFES spol. s r.o.")
loBuilder.AddAttribute("adresa2", "Neklanova 18" + CHR(10) + "128 00 Praha 2")
loBuilder.Pop()

Výsledek v záhlaví (vlevo nahoře):

EFES spol. s r.o.   ← tučně
Neklanova 18
128 00 Praha 2

Pokud parametr element v XML chybí nebo nemá atributy adresa1/adresa2, použije se header.company jako dříve.


3. Sekce (sections)

Sekce jsou nezávislé části sestavy — každá má vlastní sloupce, skupiny a součty.

{
  "sections": [
    {
      "element": "doklady",
      "label": "Přehled dokladů",
      "columns": { ... },
      "groups": [ ... ],
      "sumExpressions": [ ... ]
    },
    {
      "element": "rekapitulace",
      "label": "Rekapitulace DPH",
      "columns": { ... }
    }
  ]
}
Vlastnost Co dělá Příklad
element Název XML elementu s daty (povinný). Tečková notace pro vnořené elementy: "objednavka.polozky" "doklady"
label Nadpis sekce "Přehled dokladů"
rowNumbers Číslování řádků "global" (průběžné), "group" (v rámci skupiny), false (žádné)
hideZero Skrýt nulové hodnoty true / false
visibleWhen Zobrazit sekci jen když... "parametry.je_platce_dph"
where Filtr řádků — zobrazí jen řádky splňující podmínku. Umožňuje více sekcí se stejným element ale různými filtry (rozvaha, výkaz zisku a ztráty…) "lk1=A", "castka>0"

Rozvaha — více sekcí se stejným elementem

Typický případ: XML obsahuje jednu plochou tabulku s aktivy i pasivy rozlišenými atributem lk1. Pomocí "where" vytvoříte dvě sekce ze stejných dat:

{
  "sections": [
    {
      "element": "data",
      "label": "AKTIVA",
      "where": "lk1=A",
      "columns": {
        "text":   { "label": "Položka" },
        "castka": { "label": "Částka", "align": "right", "format": "N2" }
      },
      "sumExpressions": [{ "field": "castka", "expr": "SUM(castka)", "format": "N2" }],
      "sumLabel": "Aktiva celkem"
    },
    {
      "element": "data",
      "label": "PASIVA",
      "where": "lk1=P",
      "columns": {
        "text":   { "label": "Položka" },
        "castka": { "label": "Částka", "align": "right", "format": "N2" }
      },
      "sumExpressions": [{ "field": "castka", "expr": "SUM(castka)", "format": "N2" }],
      "sumLabel": "Pasiva celkem"
    }
  ]
}

Syntaxe where (stejná jako u sumRows):

Vzor Příklad Popis
"pole=hodnota" "lk1=A" Rovnost (case-insensitive)
"pole!=hodnota" "stav!=Z" Nerovnost
"pole" "aktivni" Neprázdné, nenulové
"!pole" "!zruseno" Prázdné nebo nulové
"pole>hodnota" "castka>0" Numerické porovnání
"pole>=hodnota" "castka>=0" Numerické porovnání

Pořadí sekcí se stejným element: Výstup následuje pořadí JSON (ne pořadí v XML). Sekce AKTIVA bude tedy vždy před PASIVA bez ohledu na pořadí řádků v XML.


4. Sloupce (columns)

Sloupce se definují jako objekt — klíč je název XML atributu, hodnota je nastavení:

{
  "columns": {
    "cislo":  { "label": "Číslo",    "align": "center", "width": "60px" },
    "nazev":  { "label": "Název",    "align": "left" },
    "datum":  { "label": "Datum",    "align": "center", "format": "dd.MM.yyyy" },
    "cena":   { "label": "Částka",   "align": "right",  "format": "N2" },
    "pozn":   { "hide": true }
  }
}

Základní vlastnosti sloupce

Vlastnost Co dělá Příklad
label Text v záhlaví "Číslo dokladu"
align Zarovnání "left", "center", "right"
width Šířka "12c", "15n2", "d", "t", "16.1mm", "80px", "15%"
format Formát čísla/data viz tabulka níže
hide Skrýt sloupec true
hideZero Skrýt nulové hodnoty true
negativeRed Záporná čísla červeně true

Formáty (format)

Formát Výstup (cs-CZ) Popis
"N0" 1 234 Celé číslo s oddělovačem tisíců
"N2" 1 234,56 2 desetinná místa
"N4" 1 234,5678 4 desetinná místa
"P" / "P2" 12,34 % Procenta
"dd.MM.yyyy" 15.01.2026 Datum
"dd.MM.yyyy HH:mm" 15.01.2026 14:30 Datum a čas
"50" (max 50 znaků) Tvrdé oříznutí textu
"50." (max 50 znaků + …) Tvrdé oříznutí + trojtečka (celkem ≤ 50)
"50w" (max 50 znaků) Oříznutí na poslední celé slovo
"50w." (max 50 znaků + …) Celé slovo + trojtečka
"###.###" 381.002 Textová maska
"Ano;Ne" Ano / Ne Boolean — truthy→první, falsy→druhá část

Zkrácení textu. na konci přidá trojtečku (), w ořízne na celé slovo.

Formáty v praxi (XML → JSON → výstup)

Číslo s 2 desetinnými místy:

XML atribut JSON definice Výstup (cs-CZ)
cena="1234.5" "format": "N2" 1 234,50

Datum:

XML atribut JSON definice Výstup
datum="2026-01-15" "format": "dd.MM.yyyy" 15.01.2026

Záporná čísla červeně:

XML atribut JSON definice Výstup
zustatek="-500" "format": "N2", "negativeRed": true -500,00

Pokročilé vlastnosti sloupce

Vlastnost Co dělá Příklad
expr Výpočet z jiných sloupců "cena * pocet"
round Zaokrouhlení výsledku 2 (na 2 des. místa)
running Průběžný součet true
resetAt Reset součtu při změně skupiny "ucet"
template Šablona textu "{cena:N2} {mena}"
suppressRepeat Nezobrazit opakovanou hodnotu true
noWrap Nezalamovat text (PDF: ořízne, XLSX: bez wrap) true
maxWidth Max. šířka s automatickým zalamováním (HTML: CSS max-width, XLSX: wrap) "60mm"
visibleWhen Zobrazit sloupec jen když... "header.je_cizi_mena"

5. Počítané sloupce (expr)

Sloupec může místo XML hodnoty zobrazit výsledek výpočtu:

{
  "celkem": {
    "label": "Celkem",
    "expr": "cena * pocet",
    "format": "N2",
    "round": 2,
    "align": "right"
  },
  "s_dph": {
    "label": "S DPH",
    "expr": "cena * pocet * 1.21",
    "format": "N2",
    "round": 2,
    "align": "right"
  }
}

Ve výrazech můžete použít:


6. Průběžný součet (running)

Sloupec s running: true zobrazuje narůstající součet:

{
  "zustatek": {
    "label": "Zůstatek",
    "expr": "prijem - vydaj",
    "running": true,
    "resetAt": "ucet",
    "format": "N2",
    "align": "right"
  }
}
Řádek Příjem Výdaj Zůstatek
1 1 000 0 1 000
2 0 300 700
3 500 0 1 200

resetAt = název skupiny, při jejíž změně se zůstatek vynuluje.


7. Template sloupce

Sloučí hodnoty z více polí do jednoho sloupce:

{
  "adresa": {
    "label": "Adresa",
    "template": "{ulice}, {psc} {mesto}"
  },
  "cena_mena": {
    "label": "Cena",
    "template": "{cena:N2} {parametry.mena}"
  }
}

V šabloně:

Víceřádkové buňky (\n v template)

Znak \n v šabloně vytvoří víceřádkovou buňku:

{
  "adresa": {
    "label": "Adresa",
    "template": "{ulice}\n{psc} {mesto}"
  }
}

Výsledek:

┌──────────────────┐
│ Hlavní 15        │
│ 110 00 Praha     │
└──────────────────┘

8. Podmíněná viditelnost (visibleWhen)

Sloupec nebo celá sekce se zobrazí jen pokud je podmínka splněna:

{
  "cena_eur": {
    "label": "Cena EUR",
    "format": "N2",
    "visibleWhen": "header.je_cizi_mena"
  },
  "kurz": {
    "label": "Kurz",
    "format": "N3",
    "visibleWhen": "header.kurz>1"
  }
}

Podporované podmínky

Zápis Význam Příklad
"pole" Pole hodnotu (neprázdné) "header.je_cizi_mena"
"!pole" Pole nemá hodnotu (prázdné) "!header.je_cizi_mena"
"pole=hodnota" Rovnost (bez ohledu na velká/malá) "header.mena=EUR"
"pole!=hodnota" Nerovnost "header.mena!=CZK"
"pole>hodnota" Číslo je větší "header.kurz>1"
"pole>=hodnota" Číslo je větší nebo rovno "header.kurz>=1"
"pole<hodnota" Číslo je menší "header.sazba<21"
"pole<=hodnota" Číslo je menší nebo rovno "header.sazba<=15"

Funguje na:


9. Potlačení opakovaných hodnot (suppressRepeat)

{
  "faktura": {
    "label": "Faktura",
    "suppressRepeat": true
  }
}
Faktura Datum Částka
FV001 15.01. 1 000
16.01. 500
17.01. 200
FV002 18.01. 3 000

Hodnota "FV001" se zobrazí jen jednou. Při změně skupiny se tracker resetuje.

Poznámka: V XLSX výstupu se suppressRepeat automaticky ignoruje — Excel uživatel potřebuje kompletní hodnoty pro filtrování, řazení a vzorce.


9b. Výběr a pořadí sloupců (printColumns)

V columns definujete všechny dostupné sloupce. Property printColumns na sekci pak za běhu vybere, které z nich se vytisknou a v jakém pořadí.

{
  "sections": [{
    "element": "doklady",
    "printColumns": "rada,doklad,castka,text",
    "columns": {
      "rada": { "label": "Řada" },
      "doklad": { "label": "Doklad" },
      "ucet_md": { "label": "MD" },
      "ucet_d": { "label": "D" },
      "castka": { "label": "Částka", "format": "N2" },
      "text": { "label": "Text" },
      "organizace": { "label": "Organizace" }
    }
  }]
}

→ Vytisknou se jen 4 sloupce: rada, doklad, castka, text.

Dynamický výběr z XML: Pomocí {element.field} se seznam sloupců načte z XML dat:

"printColumns": "{parametry.sloupce}"

Ve FoxPro nastavíte:

loBuilder.AddElement("parametry")
loBuilder.AddAttribute("sloupce", "rada,doklad,castka,text")
loBuilder.Pop()

Uživatel si za běhu volí sloupce, výběr se předá přes XML. Prázdný printColumns nebo prázdné XML pole = tisknou se všechny sloupce.


10. Skupiny (groups)

Skupiny seskupí řádky a zobrazí mezisoučty. Dva režimy:

Skupiny s plochou XML (groupExpression) — nejčastější

Data jsou plochá (všechny řádky na jedné úrovni), renderer seskupí podle hodnot atributů:

{
  "groups": [
    {
      "groupExpression": "rada",
      "label": "Řada {rada}",
      "headerMode": "external",
      "tableBreak": true,
      "sumExpressions": [
        { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
      ],
      "sumLabel": "Celkem za řadu {rada}"
    }
  ]
}

Pozor: Data musí být setříděná podle skupinových polí! Renderer neřadí data sám — pouze detekuje změny hodnot. V FoxPro zajistěte ORDER BY v SQL dotazu.

Vlastnosti skupiny

Vlastnost Co dělá Příklad
groupExpression Pole pro seskupení "rada" nebo ["typ", "rada"]
label Nadpis skupiny "Řada {rada}"{rada} se nahradí hodnotou
headerMode Styl nadpisu "external" (nad tabulkou), "inline" (řádek v tabulce)
tableBreak Každá skupina = samostatná tabulka true / false
resetRowNumbers Číslování od 1 v každé skupině true
hideGroupHeader Skrýt nadpis skupiny true (data se stále seskupují)
hideGroupFooterIfSingle Skrýt součet u skupiny s 1 řádkem true
forceNewPage Začít skupinu na nové stránce true (jen paged režim)
reprintHeader Znovutisk záhlaví (firma, nadpis, logo) true — každá skupina = nová sestava
detailBorders Čáry jen pro tuto skupinu "vertical", "none", "h-dashed" atd.
sumBorder Čára nad součtem "solid", "dashed", "light", "none"
sumBorders Vnitřní okraje v součtových řádcích "all", "vertical", "horizontal", "none", "inner-none", "h-dashed", "h-dashed-only"
sumStyle Styl součtových řádků "bold" (výchozí tučný), "light" (normální písmo)
sumLabelAlign Zarovnání popisku součtu "right" (výchozí), "left"
headerBackground Barva pozadí group header řádku "#ffffc0" (hex), "LightYellow" (pojmenovaná), "rgb(255,255,192)" (RGB)
sumBackground Barva pozadí sum řádků "#ccffcc" (hex), "LightGreen" (pojmenovaná), "#ffffff" (bílá)
headerLabelField Sloupec pro label v group header "text" — přepne na per-column mód
headerValues Další hodnoty v group header [{ "field": "poznamka", "value": "{ucty.poznamka}" }]
xlsxSheetName Nový XLSX list pro každou skupinu "Účet {ucet:###.###}" — template pro název listu
footerRows Bloky pod tabulkou za skupinou Viz 11f. Bloky pod tabulkou

Vizuální styl součtových řádků:

Více úrovní skupin

{
  "groups": [
    {
      "groupExpression": ["typ", "rada"],
      "label": "{typ} — řada {rada}",
      "headerMode": "external",
      "tableBreak": true,
      "sumExpressions": [
        { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
      ]
    },
    {
      "groupExpression": "sdoklad",
      "label": "Doklad {sdoklad}",
      "headerMode": "inline",
      "tableBreak": false,
      "sumExpressions": [
        { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
      ]
    }
  ]
}

Pořadí v poli = od vnější skupiny (mění se méně často) po vnitřní (mění se častěji).

Pole dostupná v záhlaví a patičce skupiny

V placeholderech {field} v label a sumLabel jsou dostupná všechna pole z datového řádku — nejen skupinové pole z groupExpression:

{
  "groupExpression": "stredisko",
  "label": "Středisko {stredisko} — {stredisko_nazev}",
  "sumLabel": "Celkem za {stredisko} — {stredisko_nazev}"
}

11. Součty (sumExpressions)

Definují se na skupině (mezisoučty) nebo na sekci (celkový součet):

{
  "sumExpressions": [
    { "field": "cena",   "expr": "SUM(cena)",              "format": "N2" },
    { "field": "pocet",  "expr": "COUNT()",                 "format": "N0" },
    { "field": "prumer", "expr": "AVG(cena)",               "format": "N2" },
    { "field": "marze",  "expr": "SUM(prodej) - SUM(nakup)","format": "N2" },
    { "field": "jc",     "expr": "SUM(cena) / SUM(pocet)",  "format": "N2", "round": 2 }
  ],
  "sumLabel": "Celkem"
}
Výraz Co počítá
SUM(pole) Součet
COUNT() Počet řádků
COUNT(pole) Počet řádků kde pole má hodnotu
AVG(pole) Průměr
MIN(pole) Minimum
MAX(pole) Maximum
SUM(a * b) Součet součinů
SUM(a) / SUM(b) Podíl součtů

V sumLabel fungují placeholdery: "Celkem za řadu {rada}".

Template na sumExpression

Součtový řádek může místo prosté formátované hodnoty zobrazit šablonu s textem:

{
  "sumExpressions": [
    {
      "field": "cena",
      "expr": "SUM(cena)",
      "template": "{value:N2} {parametry.mena}"
    }
  ]
}

Výsledek: "75 020,00 EUR" místo prostého "75 020,00". Placeholdery v template:


11b. Víceřádkové patičky (sumRows)

Pokud potřebujete pod skupinou nebo sekcí více součtových řádků (např. celkem + splatné + po splatnosti), použijte sumRows místo sumExpressions + sumLabel:

{
  "sumRows": [
    {
      "sumLabel": "Celkem",
      "labelField": "text",
      "sumExpressions": [
        { "field": "md", "expr": "SUM(md)", "format": "N2" },
        { "field": "d", "expr": "SUM(d)", "format": "N2" }
      ]
    },
    {
      "sumLabel": "Splatné",
      "labelField": "text",
      "where": "stav=S",
      "sumBorder": "none"
    },
    {
      "sumLabel": "Po splatnosti",
      "labelField": "text",
      "where": "stav=P",
      "sumBorder": "none",
      "style": "bold",
      "hideIfZero": true
    }
  ]
}
Vlastnost Typ Popis
sumLabel string Popisek řádku ({field} placeholdery fungují)
labelField string Název sloupce pro label. Bez toho se label rozprostře přes textové sloupce
where string Filtr: "stav=S" (rovnost), "stav!=P" (nerovnost), "castka>1000" / ">=500" / "<100" / "<=50" (numerické), "stav" (neprázdné), "!stav" (prázdné)
sumExpressions array Vlastní výrazy. Pokud chybí, dědí z prvního řádku který je má
sumBorder string Čára nad řádkem: "solid" (auto pro 1.), "none" (auto pro 2.+), "dashed", "light"
hideIfZero bool Přeskočit řádek pokud všechny výsledky jsou nulové
style string "bold" (výchozí) nebo "light" (normální váha písma, stejná velikost jako detail)
labelAlign string "right" (výchozí) nebo "left" — zarovnání popisku

Dědění výrazů: Druhý a třetí řádek nemá sumExpressions — automaticky použije výrazy z prvního řádku, jen je vyhodnotí jen pro řádky vyhovující podmínce where.

Pozor: sumRows a sumExpressions+sumLabel se navzájem vylučují. Pokud na skupině/sekci máte sumRows, nepoužívejte současně sumExpressions + sumLabel. Starý formát bez sumRows funguje beze změn.


11c. Vizuální stylování skupin

Barvy pozadí

Na skupině můžete nastavit barvy pozadí záhlaví a patičky:

{
  "groupExpression": "ucet",
  "headerBackground": "#ffffc0",
  "sumBackground": "#ffffff"
}
Vlastnost Co dělá Výchozí
headerBackground Barva pozadí group header řádku #e8f4fc (světle modrá)
sumBackground Barva pozadí sum (patičkových) řádků #f0f0f0 (subtotal), #e8e8e8 (grand total)

Podporované formáty barevheaderBackground, sumBackground a background na sumExpression:

Příklady: "LightYellow", "#ffffc0", "rgb(255, 255, 192)" — všechny jsou ekvivalentní a produkují stejnou žlutou barvu.

Per-column group header

Standardně se label skupiny zobrazí jako colspan přes celou šířku. S headerLabelField se label umístí do konkrétního sloupce, headerValues přidají další hodnoty do jiných sloupců:

{
  "groupExpression": "ucet",
  "label": "{ucet:###.###} {ucty.nazev}",
  "headerLabelField": "text",
  "headerBackground": "#ffffc0",
  "headerValues": [
    { "field": "poznamka", "value": "{ucty.poznamka}", "style": "bold" }
  ]
}

Výsledek: label "067.200 Půjčka Greens Apple" se zobrazí ve sloupci text, hodnota "{ucty.poznamka}" ve sloupci poznamka. Buňky s obsahem automaticky zabírají sousední prázdné sloupce (auto-colspan).

Per-cell stylování v sum řádcích

Na sumExpression lze přidat per-cell overrides (align, background, style), nebo zobrazit neagregátní hodnotu z lookup kontextu (value místo expr):

{
  "sumExpressions": [
    { "field": "md", "expr": "SUM(md)", "format": "N2" },
    { "field": "dal", "expr": "SUM(dal)", "format": "N2" },
    { "field": "poznamka", "value": "{ucty.poznamka}", "align": "right", "background": "#c0e0ff", "style": "bold" }
  ]
}

Třetí výraz neagreguje — value zobrazí textovou hodnotu z lookup kontextu s modrým pozadím, tučným písmem a pravým zarovnáním.


11c2. Víceřádkové záhlaví tabulky (headerRows)

Property headerRows umožňuje vytvořit záhlaví ve více řádcích — typicky pro seskupení sloupců:

{
  "sections": [{
    "element": "data",
    "headerRows": [
      [
        { "text": "Identifikace", "colspan": 2, "align": "center" },
        { "text": "Hodnoty",      "colspan": 2, "align": "center", "background": "#e0f0ff" }
      ],
      [
        { "text": "Kategorie" },
        { "text": "Název" },
        { "text": "Ks",     "align": "right" },
        { "text": "Celkem", "align": "right" }
      ]
    ],
    "columns": {
      "kategorie": { "label": "Kategorie" },
      "nazev":     { "label": "Název" },
      "ks":        { "label": "Ks",     "align": "right", "format": "N0" },
      "celkem":    { "label": "Celkem", "align": "right", "format": "N0" }
    }
  }]
}

Výsledek: první řádek záhlaví zobrazí skupinové nadpisy ("Identifikace" přes 2 sloupce, "Hodnoty" přes 2 sloupce), druhý řádek zobrazí názvy jednotlivých sloupců.

Vlastnosti buňky záhlaví:

Vlastnost Popis
text Text buňky
colspan Počet sloupců které buňka zabere (výchozí 1)
rowspan Počet řádků které buňka zabere (výchozí 1)
align "left", "center", "right" — null = zarovnání ze sloupce
style "bold" (výchozí) nebo "normal"
background CSS barva pozadí buňky (#rrggbb)

Pokud headerRows chybí, použijí se label ze columns jako jednořádkové záhlaví (zpětná kompatibilita).

11d. Podpole pod řádkem (subFields)

Pod každým datovým řádkem se mohou zobrazit doplňkové údaje — EAN, šarže, poznámka apod.:

{
  "sections": [{
    "element": "polozky",
    "columns": {
      "nazev": { "label": "Název" },
      "cena":  { "label": "Cena", "format": "N2" }
    },
    "subFields": [
      { "field": "ean", "label": "EAN" },
      { "field": "sarze", "label": "Šarže", "format": "dd.MM.yyyy" },
      { "field": "poznamka" }
    ]
  }]
}

Výstup: pod datovým řádkem se zobrazí např. EAN: 8594001234567 · Šarže: 15.01.2026 · Poznámka textu.

Vlastnost Co dělá Příklad
field Název XML atributu "ean"
label Popisek před hodnotou "EAN" (zobrazí EAN: hodnota)
format Formát hodnoty "dd.MM.yyyy", "N2"
visibleWhen Podmíněná viditelnost "stav" / "!stav"

Auto-hiding: Pokud jsou všechna subFields pro daný řádek prázdná, podřádek se přeskočí.


11e. Mezera před grand totalem (sumSpacerMm)

Vlastnost sumSpacerMm na sekci vloží prázdný řádek o zadané výšce před grand total:

{
  "sections": [{
    "element": "data",
    "sumSpacerMm": 3,
    "sumExpressions": [
      { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
    ],
    "sumLabel": "Celkem"
  }]
}

Výchozí hodnota je 0 (žádná mezera). Vizuálně oddělí poslední datový řádek od součtu.


11e. Markdown v datových buňkách

Hodnoty začínající znakem ^ se renderují jako Markdown. Bez prefixu = prostý text (beze změny).

Kde funguje

Podporované formáty

Zápis Výsledek
**tučný** tučný
*kurzíva* kurzíva
==zvýrazněný== zvýrazněný text (žlutě)
- položka odrážkový seznam
[odkaz](url) klikatelný odkaz

Tip: Markdown v template

Pokud chcete formátovat buňku, která kombinuje více polí, použijte template začínající ^:

{
  "nazev_pozn": {
    "label": "Název",
    "template": "^**{nazev}**\n{poznamka}"
  }
}

Výsledek: název tučně, pod ním poznámka normálním písmem — vše v jedné buňce.

Pozor:


11f. Bloky pod tabulkou (footerRows)

Za součtovými řádky skupiny (nebo za grand totalem sekce) lze přidat bloky — popisky, hodnoty, podmíněné texty, podpisy. Typické pro inventarizační výkazy, protokoly, rekapitulace.

Typy bloků

Typ Co dělá
spacer Prázdné místo (výška v mm)
label-value Popisek + hodnota (např. „Účetní stav: 71 127,33 Kč")
text Volný text (podmíněný nebo statický)
signature Dva podpisy vedle sebe

Příklad — inventarizační výkaz

{
  "groups": [{
    "groupExpression": "ucet",
    "label": "Účet {ucet:###.###}",
    "sumExpressions": [{ "field": "castka", "expr": "SUM(castka)", "format": "N2" }],
    "footerRows": [
      { "type": "spacer", "heightMm": 3 },
      { "type": "label-value", "label": "Účetní stav:", "template": "{ucetni_stav:N2} Kč",
        "labelField": "text", "valueField": "md", "style": "bold", "fontSizePt": 10 },
      { "type": "label-value", "label": "Zjištěný stav:", "template": "{zjisteny_stav:N2} Kč",
        "labelField": "text", "valueField": "md", "fontSizePt": 10 },
      { "type": "label-value", "label": "Rozdíl:", "template": "{rozdil:N2} Kč",
        "labelField": "text", "valueField": "md", "style": "bold", "fontSizePt": 10 },
      { "type": "text", "text": "Inventarizační komise navrhuje odpis rozdílu.",
        "visibleWhen": "rozdil" },
      { "type": "signature", "signatureLeft": "Předseda komise",
        "signatureRight": "Člen komise" }
    ]
  }]
}

Vlastnosti footerRow

Vlastnost Co dělá Příklad
type Typ bloku "spacer", "label-value", "text", "signature"
label Popisek (label-value) "Účetní stav:"
template Šablona hodnoty s placeholdery "{castka:N2} Kč"
value Přímá šablona hodnoty "{ucetni_stav:N2}"
field + format Pole z XML + formát "castka" + "N2"
text Text pro typ "text" "Inventarizační komise navrhuje..."
style Styl písma "bold", "normal", "title"
fontSizePt Velikost fontu 10, 12
visibleWhen Podmíněná viditelnost "rozdil", "!rozdil", "SUM(rozdil)", "!SUM(rozdil)"
labelField Zarovnání labelu na sloupec "text" (dle sloupce v tabulce)
valueField Zarovnání hodnoty na sloupec "md" (dle sloupce v tabulce)
signatureLeft Levý podpis "Předseda komise"
signatureRight Pravý podpis "Člen komise"
heightMm Výška spaceru v mm 3, 5

Priorita hodnoty

Renderer hledá hodnotu v tomto pořadí:

  1. template — šablona s placeholdery: "{castka:N2} {mena}"
  2. value — přímá šablona: "{ucetni_stav:N2}"
  3. field + format — prosté pole s formátem

Ukotvení na sloupce

Footer rows se zobrazují mimo tabulku, ale mohou být vizuálně zarovnány ke sloupcům tabulky:

Na skupině vs. na sekci

{
  "sections": [{
    "element": "data",
    "groups": [{ "groupExpression": "ucet", "footerRows": [...] }],
    "footerRows": [
      { "type": "text", "text": "Celkový přehled za {header.obdobi}", "style": "title" }
    ]
  }]
}

Agregátní výrazy ve footerRows

visibleWhen a template/value ve footerRows podporují agregátní výrazy: SUM(), AVG(), MIN(), MAX(), COUNT().

{
  "footerRows": [
    { "type": "label-value", "label": "Rozdíl:", "template": "{SUM(rozdil):N2} Kč", "style": "bold" },
    { "type": "text", "text": "Stav souhlasí.", "visibleWhen": "!SUM(rozdil)" },
    { "type": "text", "text": "Komise navrhuje odpis.", "visibleWhen": "SUM(rozdil)", "style": "bold" }
  ]
}

Tip: Na skupině se agregáty počítají z řádků dané skupiny. Na sekci se počítají ze všech řádků sekce.

XLSX: Nový list pro každou skupinu (xlsxSheetName)

V XLSX výstupu může každá skupina vytvořit nový worksheet:

{
  "groupExpression": "ucet",
  "xlsxSheetName": "Účet {ucet:###.###}"
}

Název listu se resolvuje z dat skupiny. Neplatné znaky se automaticky odstraní (max 31 znaků). Pouze pro XLSX — HTML a PDF tuto vlastnost ignorují (tam se používá forceNewPage/tableBreak).

Tip: Pokud chcete nový list i bez šablony názvu, použijte forceNewPage: true — v XLSX se automaticky vytvoří nový list s názvem z group label.


12. Lookup tabulky

Doplní data z jiné XML tabulky (např. název firmy k číslu organizace):

{
  "groupExpression": "organizace",
  "label": "{organizace} {adresy.orgnazev:80}",
  "lookup": { "element": "adresy" }
}

Renderer dohledá v XML elementu <adresy> řádek se shodnou hodnotou organizace a zpřístupní jeho atributy.

Řetězený lookup (přes více tabulek)

{
  "lookup": [
    { "element": "hlavicky_dokladu" },
    { "element": "adresy", "key": "organizace" }
  ]
}

Krok 1: dohledá hlavičku dokladu. Krok 2: z hlavičky vezme organizace a dohledá adresu.

Přístup k lookup hodnotám

Lookup na úrovni sekce (per-row)

Lookup nemusí být jen na skupině — lze ho definovat přímo na sekci. Pak se provádí per-row (pro každý řádek zvlášť):

{
  "sections": [
    {
      "element": "polozky",
      "lookup": { "element": "sklad", "key": "kod_zbozi" },
      "columns": {
        "kod_zbozi": { "label": "Kód" },
        "sklad.nazev": { "label": "Název zboží" },
        "pocet":       { "label": "Množství", "format": "N2" }
      }
    }
  ]
}

Pro každý řádek v <polozky> se dohledá odpovídající řádek v <sklad> podle kod_zbozi a zpřístupní se jeho atributy přes tečkovou notaci (sklad.nazev).


12b. Aliasy pro XML cesty (aliases)

Pokud v šabloně opakovaně používáte dlouhé tečkové cesty, můžete si definovat zkratky:

{
  "aliases": {
    "pol": "objednavka.polozky",
    "hlav": "objednavka.hlavicka"
  },
  "sections": [{
    "element": "pol",
    "columns": {
      "cena": { "label": "Cena {hlav.mena}", "format": "N2" }
    }
  }]
}

Aliasy pro lookup tabulky (více skupin na stejný element)

Typický případ: Předvaha — tři úrovně účtů (syn1, syn2, syn3), všechny hledají v jednom elementu syn_ucty. Každý alias vytvoří vlastní lookup session (cache se nestírají):

{
  "aliases": {
    "syn_ucty1": "syn_ucty",
    "syn_ucty2": "syn_ucty",
    "syn_ucty3": "syn_ucty"
  },
  "sections": [{
    "element": "data",
    "groups": [
      {
        "groupExpression": "syn1",
        "label": "{syn1} {syn_ucty1.nazev}",
        "lookup": { "element": "syn_ucty1", "key": "syn1", "foreignKey": "syn" },
        "sumLabel": "Σ {syn1} {syn_ucty1.nazev}"
      },
      {
        "groupExpression": "syn2",
        "label": "{syn2} {syn_ucty2.nazev}",
        "lookup": { "element": "syn_ucty2", "key": "syn2", "foreignKey": "syn" }
      },
      {
        "groupExpression": "syn3",
        "label": "{syn3} {syn_ucty3.nazev}",
        "lookup": { "element": "syn_ucty3", "key": "syn3", "foreignKey": "syn" }
      }
    ]
  }]
}

V XML stačí jeden element syn_ucty:

<syn_ucty>
  <row syn="0" nazev="Dlouhodobý majetek" />
  <row syn="01" nazev="Dlouhodobý nehmotný majetek" />
  <row syn="011" nazev="Zřizovací výdaje" />
</syn_ucty>

Při otevření editoru přes OpenReportEditor() se aliasy automaticky přidají do VS Code IntelliSense — nabídnou se jako syn_ucty1, syn_ucty2, syn_ucty3 s poli syn a nazev.


13. Dynamické labely sloupců

Záhlaví sloupce může obsahovat hodnotu z XML:

{
  "cena": {
    "label": "Cena {parametry.mena}",
    "format": "N2"
  }
}

Záhlaví se zobrazí jako: Cena EUR (pokud <parametry mena="EUR" />).


14. Stránkování (paged režim)

Pro sestavy s mnoha stránkami:

{
  "report": {
    "pageLayout": "paged",
    "orientation": "landscape",
    "pageMarginMm": 8
  },
  "pageHeader": {
    "left": "{company}",
    "center": "{title}",
    "right": "Strana {page} z {pages}"
  },
  "pageFooter": {
    "left": "Vytištěno: {date}",
    "right": "{filter}"
  }
}

Placeholdery v záhlaví/zápatí stránky:

Placeholder Co zobrazí
{page} Číslo stránky
{pages} Celkový počet stránek
{title} Název sestavy
{company} Název firmy
{date} Aktuální datum (dd.MM.yyyy)
{datetime} Aktuální datum a čas (dd.MM.yyyy HH:mm:ss)
{filter} Filtr z header.filter

Vlastnost fromPage (číslo) na pageHeader/pageFooter umožňuje zobrazit záhlaví/zápatí až od dané stránky (např. "fromPage": 2).

Tip: Přetečení stránky v tisku Pokud sestava v prohlížeči vypadá správně, ale v tisku přeteče na další stránku, je to způsobeno kumulativními odchylkami CSS renderingu (padding, border, line-height). Vlastnost pageSafetyMarginMm (výchozí 5) kompenzuje tyto odchylky. Pokud stále přetéká, zvyšte hodnotu (např. "pageSafetyMarginMm": 8). Nastavení 0 bezpečnostní okraj vypne.


15. Lokalizace (i18n)

Překlad textů v sestavě:

{
  "i18n": {
    "Celkem": "Total",
    "Strana": "Page"
  }
}

16. Průběh renderování (ShowProgress)

Při generování velkých sestav (stovky řádků) lze zobrazit dialog s průběhem a tlačítkem Storno:

loBuilder.ShowProgress = .T.
loBuilder.Render("sestava.pdf", "sablona.json")    && dialog s průběhem
loBuilder.ShowProgress = .F.                        && zpět bez dialogu

Dialog zobrazuje:

Tip: Property ShowProgress přežívá Reset() i EndBatch(). Stačí nastavit jednou a funguje pro všechna volání Render().


17. Generování z FoxPro FRX

Existující FoxPro FRX reporty lze automaticky konvertovat na JSON šablony:

*--- Auto-detekce typu (table/document) ---
loBuilder.ConvertFrxToAllFiles("C:\frx\CENIK.xml", "C:\output\")

*--- Pokud auto-detekce špatně klasifikuje typ ---
loBuilder.ConvertFrxToTableReportAllFiles("C:\frx\CENIK.xml", "C:\output\")
loBuilder.ConvertFrxToDocumentAllFiles("C:\frx\INVUCKC.xml", "C:\output\")

Výstup: 3 soubory ve výstupní složce — .json (šablona), _sample.xml (vzorová data), .prg (FoxPro kód).

Varianty jen pro JSON soubor:

loBuilder.ConvertFrxToJsonFile("CENIK.xml", "cenik.json")              && auto-detekce
loBuilder.ConvertFrxToTableReportJsonFile("CENIK.xml", "cenik.json")   && vynuceně tabulka
loBuilder.ConvertFrxToDocumentJsonFile("INVUCKC.xml", "invuckc.json")  && vynuceně dokument

Tip: Auto-detekce typu se řídí výškami bandů a počtem polí. Pokud výsledek nevypadá správně, použijte variantu s vynuceným typem (TableReport nebo Document v názvu metody).


Příklady z praxe

Jednoduchý ceník

{
  "report": {
    "title": "Ceník",
    "culture": "cs-CZ"
  },
  "header": {
    "company": "EFES spol. s r.o."
  },
  "sections": [
    {
      "element": "polozky",
      "columns": {
        "kod":    { "label": "Kód",       "align": "center", "width": "60px" },
        "nazev":  { "label": "Název" },
        "cena":   { "label": "Cena/ks",   "align": "right", "format": "N2" },
        "mj":     { "label": "MJ",        "align": "center", "width": "40px" }
      }
    }
  ]
}

Saldokonto s průběžným zůstatkem

{
  "report": {
    "title": "Saldokonto",
    "culture": "cs-CZ",
    "detailBorders": "vertical",
    "xlsxScale": 1.3
  },
  "sections": [
    {
      "element": "pohyby",
      "hideZero": true,
      "columns": {
        "faktura": { "label": "Faktura",  "suppressRepeat": true },
        "den":     { "label": "Datum",     "format": "dd.MM.yyyy" },
        "md":      { "label": "Má dáti",   "format": "N2", "align": "right", "negativeRed": true },
        "d":       { "label": "Dal",       "format": "N2", "align": "right" },
        "zust":    { "label": "Zůstatek",  "expr": "md - d", "running": true,
                     "resetAt": "organizace", "format": "N2", "align": "right" }
      },
      "groups": [
        {
          "groupExpression": "organizace",
          "label": "{organizace} {adresy.orgnazev:80}",
          "headerMode": "external",
          "tableBreak": true,
          "lookup": { "element": "adresy" },
          "sumExpressions": [
            { "field": "md",   "expr": "SUM(md)",   "format": "N2" },
            { "field": "d",    "expr": "SUM(d)",     "format": "N2" },
            { "field": "zust", "expr": "SUM(md) - SUM(d)", "format": "N2" }
          ]
        }
      ],
      "sumExpressions": [
        { "field": "md",   "expr": "SUM(md)",   "format": "N2" },
        { "field": "d",    "expr": "SUM(d)",     "format": "N2" },
        { "field": "zust", "expr": "SUM(md) - SUM(d)", "format": "N2" }
      ],
      "sumLabel": "Celkem"
    }
  ]
}

Přehled s podmíněnými sloupci (cizí měna)

{
  "sections": [
    {
      "element": "polozky",
      "columns": {
        "nazev": { "label": "Název" },
        "cena":  { "label": "Cena Kč", "format": "N2", "align": "right",
                   "visibleWhen": "!header.je_cizi_mena" },
        "cizi":  { "label": "Cena {header.mena}", "format": "N2", "align": "right",
                   "visibleWhen": "header.je_cizi_mena" },
        "kurz":  { "label": "Kurz", "format": "N3",
                   "visibleWhen": "header.je_cizi_mena" }
      }
    }
  ]
}

Hlavní kniha — pokročilé funkce sumRows

Hlavní kniha (účetní sestava) je typický příklad složitého reportu, kde potřebujete:

Sestava má typicky 3 úrovně skupin:

  1. Syntetika (vnější) — seskupení účtů se stejným číslem syntetiky
  2. Účet (střední) — konkrétní analytický účet
  3. Období (vnitřní) — měsíce s doklady

scope — agregace přes nadřazenou skupinu

Normálně sumExpressions počítá součty přes řádky aktuální skupiny. Na vnitřní skupině (období) ale často potřebujete KZ (konečný zůstatek), který se počítá přes všechny řádky účtu — tedy přes nadřazenou skupinu.

Property "scope" na sumRow říká: "pro tento součet vezmi řádky z jiné skupiny".

{
  "groupExpression": "obdobi",
  "sumRows": [
    {
      "sumLabel": "KZ k m.{obdobi}",
      "scope": "ucet",
      "where": "obdobi<={obdobi}",
      "sumExpressions": [
        { "field": "md", "expr": "SUM(md)-SUM(d)", "format": "N2" }
      ]
    }
  ]
}

Hodnota "scope" je název groupExpression nadřazené skupiny (zde "ucet"). Renderer vezme všechny řádky dané skupiny účtu a teprve na nich aplikuje where filtr.

Dynamické where — placeholder v podmínce

Podmínka "where" na sumRow může obsahovat {field} placeholder, který se nahradí hodnotou z aktuální skupiny:

{
  "sumLabel": "PZ k m.{obdobi}",
  "scope": "ucet",
  "where": "obdobi<{obdobi}"
}

Pokud je aktuální období 2, podmínka se resolvuje na "obdobi<2" — výsledek zahrnuje jen řádky období 0 a 1. Díky tomu můžete na vnitřní skupině (období) spočítat kumulativní zůstatek k aktuálnímu měsíci.

Ternární výraz v sumExpressions

Ternární výraz umožňuje podmíněný výpočet v součtovém řádku. Syntaxe: podmínka?výraz_true:výraz_false.

{
  "sumExpressions": [
    { "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2" },
    { "field": "d",  "expr": "osnova.ap=P?SUM(d)-SUM(md):0", "format": "N2" }
  ]
}

Podmínka osnova.ap=A se vyhodnotí z lookup tabulky (osnova účtů). Pokud je účet aktivní (A), zobrazí se MD-D, jinak se zobrazí 0. Pro pasivní účet (P) naopak D-MD.

Ternární výrazy lze řetězit: a=1?X:a=2?Y:Z — funguje jako if-elseif-else.

SUMBY — per-subgroup agregace

Pro syntetiku (vnější skupinu), která obsahuje mix aktivních a pasivních účtů, nestačí prostý ternární výraz — ten se vyhodnotí jen jednou pro celou syntetiku. SUMBY řeší tento problém: rozparticionuje řádky podle zadaného pole a pro každou partici vyhodnotí výraz zvlášť.

{
  "sumLabel": "KZ syntetika",
  "sumExpressions": [
    { "field": "md", "expr": "SUMBY(ucet, osnova.ap=A?SUM(md)-SUM(d):0)", "format": "N2" },
    { "field": "d",  "expr": "SUMBY(ucet, osnova.ap=P?SUM(d)-SUM(md):0)", "format": "N2" }
  ]
}

SUMBY(ucet, ...) znamená: rozděl řádky syntetiky podle hodnoty ucet, pro každý účet vyhodnoť vnitřní výraz (s jeho lookup kontextem z osnovy) a výsledky sečti.

visibleWhen na sumRow

Property "visibleWhen" na součtovém řádku řídí, zda se řádek zobrazí. Podmínka se vyhodnocuje z aktuálního group elementu:

{
  "sumLabel": "Obrat m.{obdobi}",
  "visibleWhen": "obdobi>0",
  "sumExpressions": [
    { "field": "md", "expr": "SUM(md)", "format": "N2" }
  ]
}

Řádek "Obrat" se zobrazí jen pro období > 0 (ne pro počáteční zůstatky). Pro období 0 (PZ) se řádek přeskočí.

hideZero na sumExpression

Property "hideZero": true na jednotlivé sumExpression způsobí, že pokud je výsledek výrazu nula, buňka zůstane prázdná (místo zobrazení "0,00"):

{ "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2", "hideZero": true }

Typické použití: v Hlavní knize je KZ na straně MD jen u aktivních účtů, u pasivních je 0 — prázdná buňka je přehlednější než "0,00".

Dynamický forceNewPage a tableBreak

Vlastnosti "forceNewPage" a "tableBreak" mohou být místo true/false zadané jako placeholder, který se resolvuje z XML dat:

{
  "groupExpression": "ucet",
  "forceNewPage": "{parametr.lstrankovat}",
  "tableBreak": "{parametr.lstrankovat}"
}

FoxPro kód nastaví lstrankovat na .t. nebo .f. a renderer automaticky přepne stránkování za běhu. Hodnoty "1", ".t.", "true", "yes" se interpretují jako true, ostatní jako false.

Kompletní příklad — Hlavní kniha

{
  "renderer": "table",
  "report": {
    "title": "Hlavní kniha",
    "culture": "cs-CZ",
    "pageLayout": "paged",
    "dataFontPt": 8
  },
  "header": { "company": "Firma s.r.o." },
  "pageHeader": {
    "left": "{company}", "center": "{title}",
    "right": "Strana {page} z {pages}", "heightMm": 10, "fromPage": 2
  },
  "sections": [{
    "element": "data",
    "columns": {
      "den":    { "label": "Den",    "align": "center", "format": "dd.MM.yyyy", "width": "15.6mm" },
      "doklad": { "label": "Doklad", "template": "{rada} {doklad}", "align": "center", "width": "13.2mm" },
      "text":   { "label": "Text",   "width": "44.4mm" },
      "md":     { "label": "Má dáti","align": "right", "format": "N2", "hideZero": true, "width": "31.5mm" },
      "d":      { "label": "Dal",    "align": "right", "format": "N2", "hideZero": true, "width": "31mm" }
    },
    "groups": [
      {
        "groupExpression": "syn",
        "label": "{syn} {syn_ucty.nazev}",
        "lookup": { "element": "syn_ucty", "key": "syn" },
        "tableBreak": true,
        "headerMode": "external",
        "sumRows": [
          {
            "sumLabel": "PZ syntetika", "where": "obdobi=0",
            "sumExpressions": [
              { "field": "md", "expr": "SUM(md)", "format": "N2" },
              { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
            ]
          },
          {
            "sumLabel": "Obraty syntetika", "where": "obdobi>0",
            "sumExpressions": [
              { "field": "md", "expr": "SUM(md)", "format": "N2" },
              { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
            ]
          },
          {
            "sumLabel": "KZ syntetika",
            "sumExpressions": [
              { "field": "md", "expr": "SUMBY(ucet, osnova.ap=A?SUM(md)-SUM(d):0)", "format": "N2", "hideZero": true },
              { "field": "d",  "expr": "SUMBY(ucet, osnova.ap=P?SUM(d)-SUM(md):0)", "format": "N2", "hideZero": true }
            ],
            "style": "bold"
          }
        ]
      },
      {
        "groupExpression": "ucet",
        "label": "{ucet} {osnova.nazev}",
        "lookup": { "element": "osnova", "key": "ucet" },
        "forceNewPage": "{parametr.lstrankovat}",
        "tableBreak": "{parametr.lstrankovat}",
        "headerMode": "inline",
        "sumRows": [
          {
            "sumLabel": "PZ {ucet}", "where": "obdobi=0",
            "sumExpressions": [
              { "field": "md", "expr": "SUM(md)", "format": "N2" },
              { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
            ]
          },
          {
            "sumLabel": "Obrat {ucet}", "where": "obdobi>0",
            "sumExpressions": [
              { "field": "md", "expr": "SUM(md)", "format": "N2" },
              { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
            ]
          },
          {
            "sumLabel": "KZ {ucet}",
            "sumExpressions": [
              { "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2", "hideZero": true },
              { "field": "d",  "expr": "osnova.ap=P?SUM(d)-SUM(md):0", "format": "N2", "hideZero": true }
            ],
            "style": "bold"
          }
        ]
      },
      {
        "groupExpression": "obdobi",
        "hideGroupHeader": true,
        "tableBreak": false,
        "headerMode": "inline",
        "sumRows": [
          {
            "sumLabel": "PZ k m.{obdobi}",
            "scope": "ucet",
            "where": "obdobi<{obdobi}",
            "visibleWhen": "obdobi>0",
            "sumExpressions": [
              { "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2", "hideZero": true },
              { "field": "d",  "expr": "osnova.ap=P?SUM(d)-SUM(md):0", "format": "N2", "hideZero": true }
            ],
            "sumBorder": "none"
          },
          {
            "sumLabel": "Obrat m.{obdobi}",
            "visibleWhen": "obdobi>0",
            "sumExpressions": [
              { "field": "md", "expr": "SUM(md)", "format": "N2" },
              { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
            ],
            "sumBorder": "dashed"
          },
          {
            "sumLabel": "KZ k m.{obdobi}",
            "scope": "ucet",
            "where": "obdobi<={obdobi}",
            "sumExpressions": [
              { "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2", "hideZero": true },
              { "field": "d",  "expr": "osnova.ap=P?SUM(d)-SUM(md):0", "format": "N2", "hideZero": true }
            ],
            "style": "bold"
          }
        ]
      }
    ],
    "sumRows": [
      {
        "sumLabel": "PZ Celkem", "where": "obdobi=0",
        "sumExpressions": [
          { "field": "md", "expr": "SUM(md)", "format": "N2" },
          { "field": "d",  "expr": "SUM(d)",  "format": "N2" }
        ]
      },
      {
        "sumLabel": "KZ celkem",
        "sumExpressions": [
          { "field": "md", "expr": "SUMBY(ucet, osnova.ap=A?SUM(md)-SUM(d):0)", "format": "N2", "hideZero": true },
          { "field": "d",  "expr": "SUMBY(ucet, osnova.ap=P?SUM(d)-SUM(md):0)", "format": "N2", "hideZero": true }
        ],
        "style": "bold"
      }
    ]
  }]
}

Tip: Lookup tabulky syn_ucty a osnova obsahují názvy syntetik a účtů. FoxPro je přidá přes AddElementWithXmlContent. Data musí být setříděná podle skupin: nejprve syn, pak ucet, pak obdobi.


Quick Wins — 10 vylepšení

Sada drobných vylepšení, která zvyšují přehlednost a použitelnost sestav. Všechna fungují ve všech třech výstupních formátech (HTML, PDF, XLSX), pokud není uvedeno jinak.

Watermark — vodoznak přes celou stránku

Vlastnost "watermark" v sekci report zobrazí velký průhledný text diagonálně přes celou stránku. Podporuje {element.field} placeholdery — pokud se placeholder resolvuje na prázdný řetězec, watermark se nezobrazí.

{
  "report": {
    "watermark": "{parametr.stav}"
  }
}

Pokud XML obsahuje <parametr stav="NÁVRH" />, zobrazí se vodoznak "NÁVRH". Pokud je atribut prázdný nebo element chybí, vodoznak se nezobrazí.

Lze zadat i statický text:

{
  "report": {
    "watermark": "KONCEPT"
  }
}

Textové modifikátory — :UPPER, :LOWER, :PROPER

Modifikátor se přidá za formát (nebo místo formátu) a změní velikost písmen ve výsledné hodnotě:

Modifikátor Výsledek Příklad
:UPPER Vše velkými "produkt alfa""PRODUKT ALFA"
:LOWER Vše malými "PRODUKT""produkt"
:PROPER Každé slovo velké "jan novák""Jan Novák"

Modifikátor funguje na sloupci (format) i v template placeholderech ({pole:PROPER}):

{
  "columns": {
    "kod":   { "label": "Kód",   "format": "UPPER" },
    "nazev": { "label": "Název", "format": "PROPER" },
    "popis": { "label": "Popis", "template": "{prijmeni:UPPER} {jmeno:PROPER}" }
  }
}

Modifikátor lze kombinovat s formátem: "format": "N2:UPPER" — nejprve se aplikuje formát, pak modifikátor.

Fallback hodnoty — {pole1|pole2|'výchozí'}

Syntaxe s | (svislítkem) umožňuje zadat řetězec záložních hodnot. Použije se první neprázdná:

{
  "columns": {
    "kontakt": { "label": "Kontakt", "template": "{email|telefon|'neuvedeno'}" }
  }
}

Funguje i s tečkovou notací: {header.kontakt|dodavatel.email|'—'}.

Debug mód — vizuální značky chybějících polí

Vlastnost "debug": true v sekci report zapne diagnostické značky v HTML výstupu:

{
  "report": {
    "debug": true
  }
}

Pokud se placeholder {pole} nemůže resolvovat (pole v XML neexistuje), místo prázdné buňky se zobrazí červeně podbarvený text [MISSING: pole]. Pokud selže výpočet expr, zobrazí se [ERR: výraz].

Tip: Debug mód zapněte jen při vývoji šablony. V produkci by měl být vypnutý (nebo property vůbec neuvádějte).

hideColumns — vylučovací seznam sloupců

Vlastnost "hideColumns" na sekci odebere zadané sloupce z výstupu. Je to opak printColumns — místo vyjmenování viditelných sloupců vyjmenujete ty, které chcete skrýt:

{
  "sections": [{
    "element": "data",
    "hideColumns": "id, internal_code, poznamka",
    "columns": {
      "id": { "label": "ID" },
      "nazev": { "label": "Název" },
      "internal_code": { "label": "Interní kód" },
      "cena": { "label": "Cena", "format": "N2" },
      "poznamka": { "label": "Poznámka" }
    }
  }]
}

V tomto příkladu se zobrazí jen sloupce "Název" a "Cena". hideColumns se aplikuje před printColumns — můžete je kombinovat.

Zebrování řádků — alternateRowBackground

Vlastnost "alternateRowBackground" v sekci report nastaví barvu pozadí každého druhého řádku (sudé řádky):

{
  "report": {
    "alternateRowBackground": "#f9f9f9"
  }
}

Hodnota je CSS barva (hex formát). Bez této vlastnosti mají všechny řádky bílé pozadí. Doporučené světlé odstíny: "#f9f9f9" (šedá), "#f0f8ff" (modrá), "#f5fff5" (zelená).

IN operátor — test na seznam hodnot

Operátor IN funguje v podmínkách where, visibleWhen a rowStyle.when. Testuje, zda hodnota pole patří do zadaného seznamu:

{
  "sumRows": [
    {
      "sumLabel": "Aktivní celkem",
      "where": "stav IN (A, B, C)",
      "sumExpressions": [{ "field": "castka", "expr": "SUM(castka)", "format": "N2" }]
    }
  ]
}

Porovnání je case-insensitive, hodnoty se automaticky trimují. Závorky jsou povinné, hodnoty oddělte čárkami.

Příklady:

Podmíněné stylování řádků — rowStyle

Vlastnost "rowStyle" na sekci umožňuje obarvit nebo zvýraznit řádky podle podmínky. Definuje se jako pole pravidel — první pravidlo, jehož podmínka odpovídá, se aplikuje:

{
  "sections": [{
    "element": "data",
    "rowStyle": [
      { "when": "stav=STORNO", "background": "#ffe0e0", "style": "italic" },
      { "when": "castka<0",    "background": "#fff3cd", "color": "#856404" },
      { "when": "stav=A",      "color": "#006600" }
    ],
    "columns": { ... }
  }]
}

Vlastnosti pravidla:

Vlastnost Popis Příklad
when Podmínka (stejná syntaxe jako where) "stav=STORNO", "castka<0", "typ IN (A, B)"
background CSS barva pozadí celého řádku "#ffe0e0" (růžová)
color CSS barva textu celého řádku "#006600" (zelená)
style Styl písma: "bold" nebo "italic" "italic"

Podmínky v when podporují všechny operátory: =, !=, >, <, >=, <=, IN(...), a také test na prázdnotu ("pole" = neprázdné, "!pole" = prázdné).

Ternární výrazy v šablonách — {podmínka?true:false}

V template sloupcích a jiných šablonách můžete použít inline podmíněný text:

{
  "columns": {
    "stav_text": { "label": "Stav", "template": "{stav=A?Aktivní:stav=P?Pasivní:Zrušený}" }
  }
}

Syntaxe: {podmínka?text_true:text_false}. Podmínky lze řetězit (else-if): {a=1?X:a=2?Y:Z}.

Ternární výrazy fungují i v sumLabel:

{
  "sumLabel": "{osnova.ap=A?Zůstatek MD:Zůstatek DAL}"
}

A v sumExpressions.expr (s agregačními funkcemi):

{
  "expr": "osnova.ap=A?SUM(md)-SUM(d):0"
}

Poznámka: V expr se ternární výraz vyhodnotí jednou pro celou skupinu. Podmínka se resolvuje z group elementu nebo lookup kontextu. Pro per-subgroup logiku použijte SUMBY.


Řešení problémů

Nic se nezobrazuje / prázdná sestava

Chybí sloupec

Čísla se nezarovnávají / špatný formát

Součty se nepočítají

JSON nejde uložit / červené podtržení

Skupiny nefungují (groupExpression)


Znakové jednotky šířek sloupců

Místo absolutních mm hodnot můžete šířky sloupců zadat relativně k fontu. Výhoda: při změně dataFontPt se šířky automaticky přepočítají — nemusíte nic měnit.

Zápis Příklad Význam
"12c" 12 znaků šířka pro 12 znaků textu
"15n2" N(15,2) šířka pro 15 číslic s 2 des. místy (vč. oddělovačů)
"8n" / "8n0" N(8,0) šířka pro 8 číslic bez desetinných
"d" datum šířka pro datum (dd.MM.yyyy)
"t" datetime šířka pro datum a čas
"16.1mm" stávající beze změny (zpětná kompatibilita)

Příklad:

{
  "columns": {
    "datum":   { "label": "Datum",  "width": "d",    "format": "dd.MM.yyyy" },
    "doklad":  { "label": "Doklad", "width": "10c" },
    "castka":  { "label": "Částka", "width": "12n2", "format": "N2", "align": "right" },
    "text":    { "label": "Text",   "width": "25c" }
  }
}

Tip: Znakové jednotky fungují i v minWidth a maxWidth. Stávající mm/px/% hodnoty fungují beze změny.

Tip: CursorSchemaGenerator nyní generuje znakové jednotky automaticky ("d", "12n2", "20c" atd.).

Dávková konverze existujících JSON šablon

Pro převod stávajících mm šířek na znakové jednotky:

*--- Konverze JSON stringu ---
lcNovy = loBuilder.ConvertJsonWidthsToCharUnits(lcJson)

*--- Konverze souboru (přepíše) ---
loBuilder.ConvertJsonFileWidthsToCharUnits("C:\sablony\prehled.json")

Konverze automaticky rozpozná typ sloupce (číslo, datum, text) z formátu a zarovnání.


Doporučené šířky sloupců v mm

Pokud potřebujete ručně nastavit "width" v mm na sloupcích (místo znakových jednotek nebo auto-výpočtu), použijte tuto referenční tabulku. Šířky odpovídají vzorci z CursorSchemaGenerator:

charWidthMm = fontPt × 0.6 × 25.4 / 72
gapMm       = 2 × (0.5 − 0.015 × fontPt) × charWidthMm
paddingMm   = 2.1                           (CSS: 2×4px padding, fixed)
columnMm    = effWidth × charWidthMm + gapMm + paddingMm

Padding (2.1 mm) je CSS td{padding:2px 4px} — s border-collapse:collapse je uvnitř šířky sloupce a nezávisí na velikosti fontu. Korekce pro numerické sloupce: mezera (oddělovač tisíců) = 0.35 znaku, čárka (des. oddělovač) = 0.45 znaku.

Typ Obraz (picture) effWidth 6 pt 7 pt 8 pt 9 pt
Date dd.MM.yyyy 8.50 13.9 15.9 17.8 19.7
DateTime dd.MM.yyyy HH:mm 14.00 20.9 24.0 27.1 30.2
L A/N 3.00 7.0 7.7 8.5 9.2
N0 (3 cifry) 999 3.00 7.0 7.7 8.5 9.2
N0 (6 cifer) 999 999 6.65 11.6 13.1 14.6 16.2
N0 (9 cifer) 999 999 999 10.30 16.2 18.5 20.8 23.1
N0 (12 cifer) 999 999 999 999 13.95 20.9 23.9 27.0 30.1
N2 (3+2) 999,99 5.55 10.2 11.5 12.8 14.1
N2 (6+2) 999 999,99 9.20 14.8 16.9 19.0 21.0
N2 (9+2) 999 999 999,99 12.85 19.5 22.3 25.1 28.0
N2 (12+2) 999 999 999 999,99 16.50 24.1 27.7 31.3 34.9
N3 (3+3) 999,999 6.55 11.5 13.0 14.5 16.0
N3 (6+3) 999 999,999 10.20 16.1 18.4 20.7 22.9
N3 (9+3) 999 999 999,999 13.85 20.7 23.8 26.8 29.9
N3 (12+3) 999 999 999 999,999 17.50 25.4 29.2 33.0 36.8
C(4) xxxx (×1.2) 4.80 9.2 10.4 11.5 12.6
C(6) xxxxxx 6.00 10.8 12.2 13.5 14.9
C(10) xxxxxxxxxx 10.00 15.8 18.1 20.3 22.5
C(20) 20 znaků 20.00 28.5 32.9 37.3 41.6
C(30) 30 znaků 30.00 41.2 47.7 54.2 60.6
C(40) 40 znaků 40.00 53.9 62.5 71.1 79.7
C(50) 50 znaků 50.00 66.6 77.4 88.1 98.7

Dostupná šířka stránky (po odečtení 2×8 mm okrajů):

Formát Portrait Landscape
A4 194 mm 281 mm
A3 281 mm 404 mm

Tip: CursorSchemaGenerator počítá tyto šířky automaticky. Tabulku použijte když upravujete "width" ručně v JSON šabloně a chcete, aby sloupce správně seděly na stránku.

Poznámka: Krátké textové sloupce (≤ 4 znaky) se násobí koeficientem 1.2, aby záhlaví nebylo příliš stěsnané. CursorSchemaGenerator standardně ořezává textové sloupce na maxLenString=20 znaků.

Přepočet šířek při změně velikosti písma

Tip: Pokud používáte znakové jednotky ("12c", "15n2", "d" atd.), přepočet není potřeba — šířky se přizpůsobí automaticky.

Pokud máte šířky v mm a měníte dataFontPt v JSON šabloně (např. z 8 na 7), je potřeba přepočítat šířky sloupců ("width").

Přesný vzorec (padding = fixní, content + gap = škálují se):

paddingMm = 2.1
width_nové = paddingMm + (width_staré - paddingMm) × (fontPt_nové / fontPt_staré)

Zjednodušený vzorec (chyba < 0.5 mm pro sloupce > 10 mm):

width_nové ≈ width_staré × (fontPt_nové / fontPt_staré)

Přepočítávací koeficienty (násobit stávající šířku):

Z \ Na 6 pt 7 pt 8 pt 9 pt
6 pt 1.167 1.333 1.500
7 pt 0.857 1.143 1.286
8 pt 0.750 0.875 1.125
9 pt 0.667 0.778 0.889

Příklad přesný (8pt → 7pt, sloupec 19.0mm):

2.1 + (19.0 - 2.1) × 7/8 = 2.1 + 14.79 = 16.9mm  →  "width": "16.9mm"

Příklad zjednodušený (stejný sloupec):

19.0 × 0.875 = 16.6mm  →  "width": "16.6mm"   (rozdíl 0.3mm)

Tip: Koeficienty jsou prostý poměr fontů (fontPt_nové / fontPt_staré). Nemusíte si je pamatovat — stačí vydělit: 7/8 = 0.875, 6/8 = 0.75 atd. Přesný vzorec se vyplatí u úzkých sloupců (< 12 mm), kde fixní padding 2.1 mm tvoří velký podíl.


Pokročilé funkce sumRows (Hlavní kniha)

scope — agregace přes nadřazenou skupinu

Normálně sumRow počítá součet přes řádky aktuální skupiny. Property scope umožňuje počítat přes řádky nadřazené skupiny nebo celé sekce.

{
  "sumLabel": "KZ k m.{obdobi}",
  "scope": "ucet",
  "where": "obdobi<={obdobi}",
  "sumExpressions": [
    { "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2", "hideZero": true }
  ]
}

Typický případ: Skupina obdobi (měsíce) je vnořená v skupině ucet. KZ k měsíci potřebuje sčítat přes všechny řádky účtu, ne jen aktuální měsíc. "scope": "ucet" expanduje rozsah agregace na celou nadřazenou skupinu.

Dynamické where s placeholdery

Where podmínka může obsahovat {field} — hodnota se dosadí z aktuální grupy:

Ternární výraz v sumExpression

Podmíněný výpočet: "expr": "podmínka?true_výraz:false_výraz"

{ "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "format": "N2" }

Pokud účet je Aktivní (osnova.ap=A), spočítá MD−Dal. Jinak vrátí 0. Podmínka využívá lookup kontext (osnova.ap se dohledá z lookup tabulky).

SUMBY — per-subgroup agregace

Pro situace kde účty pod jednou syntetikou mají různé strany (A/P):

{ "field": "md", "expr": "SUMBY(ucet, osnova.ap=A?SUM(md)-SUM(d):0)", "hideZero": true }

SUMBY rozdělí řádky podle ucet, pro každý účet vyhodnotí ternární výraz (s jeho vlastním lookup kontextem) a sečte výsledky. Typicky pro SYN=343 (DPH) kde 3431 je Aktivní a 3432 je Pasivní.

visibleWhen na sumRow

Řádek se zobrazí jen při splnění podmínky:

{ "sumLabel": "PZ k m.{obdobi}", "visibleWhen": "obdobi>0" }

Řádek "Počáteční zůstatek k měsíci" se nezobrazí pro období 0 (samotný PZ).

hideZero na sumExpression

Per-buňka blank if zero — buňka zůstane prázdná pokud výsledek je 0:

{ "field": "md", "expr": "osnova.ap=A?SUM(md)-SUM(d):0", "hideZero": true }

Rozdíl: hideIfZero na sumRow skryje celý řádek. hideZero na sumExpression skryje jen jednu buňku.

Dynamický forceNewPage / tableBreak

forceNewPage a tableBreak mohou být řízeny z XML dat:

{
  "groupExpression": "ucet",
  "forceNewPage": "{parametr.lstrankovat}",
  "tableBreak": "{parametr.lstrankovat}"
}

Hodnota "1" nebo "true" → zapnuto, ostatní → vypnuto.


Quick Wins — 10 vylepšení

Watermark

Text přes celou stránku (vodoznak):

{ "report": { "watermark": "NÁVRH" } }

Podporuje {field} placeholdery: "watermark": "{header.stav}". Prázdný řetězec = nezobrazit.

Textové modifikátory (:UPPER, :LOWER, :PROPER)

Transformace textu ve formátu nebo šabloně:

{
  "label": "Firma",
  "format": "UPPER"
}

V šablonách: {firma:UPPER}, {nazev:PROPER}. Kombinace s formátem: {castka:N2:UPPER}.

Modifikátor Výsledek Příklad
:UPPER VELKÁ PÍSMENA "efes" → "EFES"
:LOWER malá písmena "EFES" → "efes"
:PROPER Velká Počáteční "jan novák" → "Jan Novák"

Fallback hodnoty (coalesce)

První neprázdná hodnota z více polí:

{ "template": "{nazev_cz|nazev_en|'Bez názvu'}" }

Znak | odděluje alternativy. Literál v uvozovkách 'text' slouží jako poslední fallback.

Debug mód

Pro ladění šablon — zobrazí chybové markery místo tichého ignorování:

{ "report": { "debug": true } }

V HTML: [MISSING: pole] (žlutý) a [ERR: výraz] (červený).

hideColumns — vylučovací seznam

Opak printColumns — které sloupce NEUKÁZAT:

{ "sections": [{ "hideColumns": ["id", "internal_code"] }] }

Sloupce zůstávají dostupné pro výpočty a lookup, jen se nezobrazí.

Zebrování řádků (alternateRowBackground)

Střídavé podbarvení sudých řádků:

{ "report": { "alternateRowBackground": "#f9f9f9" } }

IN operátor

Testování příslušnosti k množině ve where, visibleWhen, rowStyle:

{ "where": "typ IN (P, V, S)" }

Podmíněné stylování řádků (rowStyles)

Barva pozadí, tučné písmo nebo barva textu podle podmínky:

{
  "rowStyles": [
    { "when": "stav=STORNO", "background": "#ffe0e0", "style": "bold", "color": "red" },
    { "when": "castka<0", "background": "#fff3e0" }
  ]
}

První matchující pravidlo se aplikuje na řádek.

Ternární výrazy v šablonách

Inline podmíněný text v libovolné šabloně:

{
  "template": "{stav=A?Aktivní:Neaktivní}",
  "label": "Účet {ucet} {osnova.ap=A?AKTIVNÍ:PASIVNÍ}"
}

Syntaxe: {podmínka?text_true:text_false}. Podmínky: =, !=, >, <, IN, field, !field.


Časté úpravy — rychlý přehled

Co chci Kam to napsat Příklad
Změnit nadpis sloupce columns.pole.label "label": "Nový název"
Skrýt sloupec columns.pole.hide "hide": true
Formát čísla columns.pole.format "format": "N2"
Formát data columns.pole.format "format": "dd.MM.yyyy"
Zarovnat vpravo columns.pole.align "align": "right"
Šířka sloupce columns.pole.width "width": "80px"
Skrýt nuly sections[].hideZero "hideZero": true
Záporná červeně columns.pole.negativeRed "negativeRed": true
Na šířku report.orientation "orientation": "landscape"
Součet sloupce sumExpressions { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
Změnit název sestavy report.title "title": "Nový název"
Bez čar mezi řádky report.detailBorders "detailBorders": "vertical"
Větší písmo v Excelu report.xlsxScale "xlsxScale": 1.3
Podmíněný sloupec columns.pole.visibleWhen "visibleWhen": "header.je_cizi_mena"
Průběžný součet columns.pole.running "running": true, "resetAt": "ucet"

Příklad: Jak přidat nový sloupec

V sekci columns přidejte nový klíč (= název XML atributu) s nastavením:

"columns": {
  "kod":    { "label": "Kód",  "align": "center", "width": "60px" },
  "nazev":  { "label": "Název" },
  "poznamka": { "label": "Poznámka" }
}

Příklad: Jak přidat součet

Na sekci nebo skupinu přidejte sumExpressions:

"sumExpressions": [
  { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
],
"sumLabel": "Celkem"