API dynamických položek ve výpočtech (di)

Objekt di slouží k práci s řádky proměnné typu Dynamické položky přímo z kódu na záložce Výpočty úkolu (viz Jak a kdy běží výpočty). Řádky umí číst celé, vybírat filtrem po stránkách, přidávat, přepisovat a mazat jednotlivě nebo hromadně. Je k dispozici v kontextu úkolu (Task-JS) a procesu (Process-JS). Jak se proměnná Dynamické položky navrhuje, popisuje článek Proměnná Dynamické položky, jak s tabulkou pracuje uživatel, článek Tabulka dynamických položek ve formuláři. Ostatní objekty výpočtů (vars, proc, task, dr) popisuje Reference API výpočtů: proměnné a případ.

Od verze 5.21
Proměnná Dynamické položky a objekt di jsou nové ve verzi 5.21. Starší proměnné typu Dynamické řádky dál fungují beze změny a pracuje se s nimi přes dr.

Příklady v článku vycházejí z ukázkové objednávky s proměnnou items a sloupci item (text), quantity (číslo), unitPrice (číslo, měna), vatRate (číselník 0/12/21), urgent (zaškrtávací pole) a justification (text).

// Součet objednávky bez DPH z řádků tabulky
const cell = (row, name) => row.cells.find((c) => c.columnName === name)?.value;
const rows = await di.from('items').getRows();
const total = rows.reduce((sum, row) => sum + (cell(row, 'quantity') ?? 0) * (cell(row, 'unitPrice') ?? 0), 0);
await vars['orderTotal'].setValue(total);

Jak di funguje

  • Nejdřív zavolejte di.from(proměnná). Všechna další volání pracují s touto proměnnou, dokud nezavoláte from() znovu s jinou. Bez from() skončí každé volání chybou Call di.from(variable) before working with the rows.
  • from() vrací di, takže volání lze řetězit: await di.from('items').getRows().
  • Všechny metody kromě from() jsou asynchronní, volejte je s await.
  • Sloupce se adresují technickým názvem sloupce (písmena a číslice, začíná písmenem), ne popiskem. Neznámý název sloupce skončí chybou a nic se neuloží.
  • Změny se ukládají okamžitě do případu. Uživatel, který má úkol otevřený, je uvidí po novém načtení formuláře.

Tvar řádku

Metody pro čtení vracejí řádky v tomto tvaru, metody pro zápis přijímají stejný tvar (vlastnost label se při zápisu ignoruje, přečtený řádek tedy můžete poslat zpět beze změny):

{
    id: 1534,            // id řádku; při zápisu určuje, který řádek se přepíše
    position: 0,         // pořadí řádku v tabulce (od 0)
    cells: [
        { columnName: 'item', value: 'Laptop Dell Latitude 7450' },
        { columnName: 'quantity', value: 3 },
        { columnName: 'vatRate', value: '21', label: '21' },
    ],
}

Prázdná buňka v poli cells chybí. Při zápisu buňka s hodnotou null, '' nebo bez hodnoty zůstane prázdná.

Typ sloupceHodnota při čteníCo přijímá při zápisu
Textřetězecřetězec nebo číslo
Číslo (i měna a procento)čísločíslo nebo řetězec s číslem (desetinná tečka)
Zaškrtávací poletrue / falsetrue / false (nebo 1 / 0)
Datumřetězec ve formátu ISO 8601 v UTC, např. 2026-12-01T00:00:00.000Zřetězec s datem nebo časové razítko
Uživatel, role, organizační jednotkaid záznamu, v label jeho názevid existujícího záznamu
Souborid dokumentu, v label název souboruid existujícího dokumentu
Číselníkhodnota položky číselníku (ne její překlad)hodnota existující položky číselníku
Dynamická tabulkaklíč řádku dynamické tabulky, v label zobrazovaný textklíč existujícího řádku

Sloupec s více hodnotami vrací a přijímá pole hodnot (a pole popisků v label). Pole poslané do sloupce s jednou hodnotou skončí chybou.

Metody objektu di

MetodaVracíPopisPříklad
from(variable)diNastaví proměnnou, se kterou pracují další volání. Přijímá název proměnné nebo objekt vars['...']. Proměnná jiného typu než Dynamické položky skončí chybou.di.from(vars['items']);
getRows()Promise<object[]>Všechny řádky proměnné v pořadí podle pozice.const rows = await di.from('items').getRows();
queryRows(query)Promise<object>Stránka řádků vybraných filtrem, v pořadí podle pozice. Popis dotazu je níže.await di.from('items').queryRows({ filters: [{ field: 'urgent', op: 'eq', value: true }] });
addRow(row)Promise<void>Přidá řádek na konec tabulky (nebo na zadanou position). Řádek ve tvaru { position?, cells }.await di.from('items').addRow({ cells: [{ columnName: 'item', value: 'Shipping' }] });
updateRow(id, row)Promise<void>Přepíše buňky řádku s daným id. Buňky, které v row.cells nejsou, se vyprázdní. Bez position zůstane řádek na svém místě.await di.from('items').updateRow(1534, { cells });
deleteRow(id)Promise<void>Smaže řádek s daným id.await di.from('items').deleteRow(1534);
setRows(rows)Promise<void>Hromadný zápis změn v jednom kroku: řádek s id se přepíše, řádek bez id se přidá, řádek s id a deleted: true se smaže. Řádky, které v poli nejsou, zůstanou beze změny.await di.from('items').setRows([{ id: 1534, deleted: true }, { cells: [...] }]);
updateRow přepisuje celý řádek
Když chcete změnit jen jednu buňku, přečtěte řádek, upravte buňku a pošlete zpět všechny buňky. Jinak přijdete o hodnoty ostatních sloupců.
// Označí jako spěšné všechny položky dražší než 20 000 Kč
const rows = await di.from('items').getRows();
for (const row of rows) {
    const price = row.cells.find((c) => c.columnName === 'unitPrice')?.value ?? 0;
    if (price > 20000) {
        const cells = row.cells.filter((c) => c.columnName !== 'urgent');
        cells.push({ columnName: 'urgent', value: true });
        await di.updateRow(row.id, { cells });
    }
}

queryRows – výběr řádků filtrem

Dotaz má tvar { filters: [{ field, op, value }], page: { limit, cursor, includeTotalCount } }. Všechny filtry musí platit současně. Bez filtrů vrací queryRows() všechny řádky po stránkách.

VlastnostPopis
fieldTechnický název sloupce. Neznámý sloupec skončí chybou.
opOperátor: eq, ne, in, nin, contains, startsWith, endsWith, gt, gte, lt, lte, isNull, isNotNull.
valuePorovnávaná hodnota. U in a nin pole hodnot, u isNull a isNotNull se vynechává.
page.limitPočet řádků na stránce, 1 až 100. Bez zadání platí výchozí limit aplikace.
page.cursorHodnota nextCursor z předchozí stránky. Pro první stránku ji vynechte.
page.includeTotalCounttrue doplní do výsledku celkový počet vyhovujících řádků. Výchozí je false.

Výsledek má tvar { items, limit, totalCount, hasMore, nextCursor }, kde items jsou řádky ve tvaru popsaném výše, totalCount je null, pokud jste počet nežádali, a hasMore říká, jestli existuje další stránka.

  • contains, startsWith a endsWith fungují jen u textových sloupců a u sloupců s popiskem (uživatel, role, organizační jednotka, soubor, číselník, dynamická tabulka), kde porovnávají popisek. U čísla, data a zaškrtávacího pole skončí chybou.
  • Ostatní operátory porovnávají uloženou hodnotu: u uživatele, role, jednotky a souboru id, u číselníku hodnotu položky, u dynamické tabulky klíč řádku.
  • ne a nin vrací i řádky, kde je buňka prázdná. Filtr zaškrtávacího pole eq false vrací nezaškrtnuté i prázdné buňky.
  • Řazení podle sloupce není k dispozici. Dotaz s vlastností sort skončí chybou a řádky se vždy vracejí podle pozice.
// Projde všechny spěšné položky po stránkách
let cursor;
let urgentCount = 0;
do {
    const page = await di.from('items').queryRows({
        filters: [{ field: 'urgent', op: 'eq', value: true }],
        page: { limit: 100, cursor },
    });
    urgentCount += page.items.length;
    cursor = page.nextCursor;
} while (cursor);
await vars['approverComment'].setValue(`Spěšných položek: ${urgentCount}`);

setRows – hromadné změny

setRows() zapíše všechny změny v jednom kroku: přidané, přepsané i smazané řádky. Hodí se, když měníte více řádků najednou.

// Smaže položky s nulovým množstvím a přidá řádek s dopravou
const rows = await di.from('items').getRows();
const changes = rows
    .filter((row) => !row.cells.find((c) => c.columnName === 'quantity')?.value)
    .map((row) => ({ id: row.id, deleted: true, cells: [] }));
changes.push({ cells: [
    { columnName: 'item', value: 'Shipping' },
    { columnName: 'quantity', value: 1 },
    { columnName: 'unitPrice', value: 350 },
    { columnName: 'vatRate', value: '21' },
] });
await di.setRows(changes);

Každý řádek musí obsahovat pole cells, i mazaný (stačí prázdné). Řádek s id, který do proměnné nepatří, skončí chybou. Řádek s deleted: true bez id také.

Proměnná Dynamické položky přes vars

S proměnnou lze pracovat i přes vars['items'], ale jen několika metodami:

MetodaVracíPopis
getValue()Promise<object>Celá tabulka: { columns, items, options, rules, script }. items jsou řádky ve tvaru výše, columns definice sloupců. Volejte s await.
getJSON()Promise<object>Totéž co getValue().
setValue(value)PromisePřijímá pole řádků, nebo tabulku vrácenou z getValue() (použije se její items). Zápis se chová stejně jako setRows(): řádky s id se přepíšou, bez id přidají, s deleted: true smažou, ostatní zůstanou.
Vynechaný řádek se nesmaže
Když z getValue().items řádek odfiltrujete a výsledek pošlete do setValue(), řádek v proměnné zůstane. Ke smazání použijte deleted: true nebo di.deleteRow().

Metody setAttribute, setJSONAttr, getJSONAttr, getDR a getDRObject nejsou pro proměnnou Dynamické položky dostupné a skončí chybou. Proměnnou nelze použít tam, kde se čeká jedna hodnota, například ji předat do setValue() jiné proměnné.

Omezení

  • Počet řádků: tabulka pojme nejvýše tolik řádků, kolik povoluje konfigurace featureFlag.dynamicItems.maxRows (výchozí 2000). Zápis, po kterém by tabulka měla víc řádků, skončí chybou DYNAMIC_ITEMS_MAX_ROWS a neuloží se nic.
  • Vypočtené sloupce a pravidla: vzorce, podmíněné výchozí hodnoty a validační pravidla sloupců vyhodnocuje formulář v prohlížeči. Při zápisu přes di se nepřepočítají ani nekontrolují. Hodnotu vypočteného sloupce zapište sami, nebo ji přepočte formulář, až ho uživatel otevře.
  • Povinné sloupce se kontrolují až při splnění úkolu, jehož formulář tabulku vyžaduje. Zápis přes di může povinný sloupec nechat prázdný.
  • Hodnoty odkazů (uživatel, role, jednotka, soubor, položka číselníku, řádek dynamické tabulky) musí existovat, jinak zápis skončí chybou s názvem sloupce.
  • Proměnná Dynamické položky nemá snímky (snaps). Všechny instance vícenásobného úkolu pracují se stejnými řádky.

Související: Proměnná Dynamické položky, Tabulka dynamických položek ve formuláři, Reference API výpočtů: proměnné a případ, Reference API výpočtů: knihovna lib, Jak a kdy běží výpočty.

Jak a kdy běží výpočty

Reference API výpočtů: knihovna lib

Team assistant (opens in a new tab)

Powered by HelpDocs (opens in a new tab)