Dokumenty ve výpočtech — kompletní průvodce
Tento článek je kompletním průvodcem prací s dokumenty v rámci backend výpočtů platformy TeamAssistant (TAS). Pokrývá čtení a ukládání dokumentů, generování DOCX ze šablon, tvorbu PDF a Excel souborů, práci se ZIP archivy, organizaci dokumentů v DMS a ukládání výsledků do proměnných. Každá kapitola obsahuje praktické příklady a reálné use case z implementací.
vault.* od 5.17, ai.* od 5.15).Základní pojmy
DMS (Document Management System) — centrální úložiště dokumentů TAS. Každý dokument je vázán na případ (IPROC_ID), má unikátní ID (DMSF_ID), název, revize a volitelné atributy (tagy, složky, logický typ).
Proměnná typu Příloha (Attachment) — proměnná na šabloně, přes kterou uživatel nahrává soubory na formuláři úkolu. Ve výpočtu je dostupná přes vars['NAZEV_PROMENNE'] a její hodnota je pole souborů.
Identifikátor souboru — většina dokumentových funkcí přijímá soubor třemi způsoby, které lze libovolně zaměňovat:
- název souboru — např.
'smlouva.pdf'(hledá se na aktuálním případu, poté v podprocesech a hlavním procesu), - ID souboru — číselné
DMSF_ID, - proměnná typu příloha — např.
vars['ATTACHMENT'](pokud obsahuje více souborů, použije se první).
Dms file does not belong to process.Pravidla pro dokumentové výpočty
Pro výpočty pracující s dokumenty platí stejná absolutní pravidla jako pro všechny TAS výpočty:
- Žádné
async/await/Promise/.then()— TAS provádí vlastní transpilaci kódu. Všechna volání (i souborová) se píší synchronně:const content = storage.getDmsContent('faktura.pdf', 'buffer'); - Logování pouze přes
proc.info/proc.warn/proc.error— nikdyconsole.log. debug.error('zpráva')— zobrazí chybu uživateli a zablokuje dokončení úkolu (např. „Nelze vygenerovat dokument, chybí podpis").- ID případu vždy přes
lib.iprocId(). - Opakovanou logiku (generátory dokumentů, konektory) přesouvejte do Skriptů na úrovni prostředí — lze je pak volat z libovolné šablony.
Čtení dokumentů a jejich obsahu
Základní funkce pro získání dokumentu a jeho obsahu z DMS:
Funkce | Popis |
| Vrátí entitu souboru (metadata — |
| Vrátí obsah souboru. Encoding: |
| Absolutní cesta souboru na filesystému serveru — vstup pro konverze a další zpracování. |
| Přečte soubor přímo z cesty na disku (typicky šablona v DMS úložišti nebo public soubor). |
| Stream souboru z proměnné typu příloha. |
| Vytěží textový obsah PDF dokumentu na případu — základ pro parsování a klasifikaci. |
| Vrátí typ souboru podle přípony. |
Příklad — načtení přílohy nahrané uživatelem a uložení textu PDF do proměnné:
// Read the attachment uploaded by the user on the task form
const invoiceFile = storage.getDmsEntity(vars['INVOICE_ATTACHMENT']);
if (!invoiceFile) {
debug.error('Do úkolu nebyla nahrána faktura.');
}
// Extract text content from the PDF
const pdfContent = lib.pdfToText(invoiceFile.NAME);
vars['INVOICE_TEXT'].setValue(JSON.stringify(pdfContent));
proc.info('Invoice text extracted', { file: invoiceFile.NAME, caseId: lib.iprocId() });
lib.countFiles(vars['INVOICE_ATTACHMENT']) — vrací počet souborů v proměnné typu příloha.Ukládání dokumentů do případu
Pro vytvoření nového dokumentu na případu existují dvě hlavní cesty:
lib.storeAttachment(fileName, content, convertToBase64, lastRevisionId)
Uloží obsah (string nebo Buffer) jako nový dokument případu. Vrací DMSF_ID nového souboru. Parametr convertToBase64 je defaultně true — pokud předáváte Buffer (např. výstup docx.docxTemplater), předejte false.
lib.storeAttachmentAsRevision(fileName, content, convertToBase64, revisionFileName)
Uloží obsah jako novou revizi existujícího dokumentu — historie verzí zůstane pohromadě (uživatel je vidí v okně dokumentu v sekci Revize).
storage.saveToDms(filePath, fileName)
Uloží do DMS soubor, který již fyzicky existuje na disku (typicky výstup konverze nebo dočasný soubor). Vrací ID nového souboru.
Příklad — vygenerování textového protokolu a uložení ID do proměnné:
const protocol = [
`Protokol případu č. ${vars['CASE_NUMBER'].getValue()}`,
`Vytvořil: ${lib.usersToDisplayName(lib.initiator())}`,
`Datum: ${moment().format('DD.MM.YYYY HH:mm')}`
].join('\n');
const fileId = lib.storeAttachment('protokol.txt', protocol);
// Store the document ID into a variable for later use
vars['PROTOCOL_FILE_ID'].setValue(fileId);
proc.info('Protocol stored', { fileId });
DMSF_ID v proměnné je nejspolehlivější způsob, jak s dokumentem pracovat v dalších úkolech procesu — název se může změnit, ID nikoli.Generování DOCX dokumentů ze šablony
Nejčastější use case: generování smluv, protokolů, podpisových listů či objednávek z předem připravené Word šablony, do které se automaticky doplní data z případu.
Dvě varianty generování
Funkce | Syntax placeholderů | Kdy použít |
|
| Jednoduché nahrazení textů. Šablona je dokument v DMS, výstup se rovnou uloží k případu a vrátí se jeho ID. |
|
| Pokročilé šablony — cykly (FOR), obrázky, tabulky, podmínky, vlastní JS funkce. Vrací Buffer, který uložíte přes |
Varianta 1 — docx.generate (jednoduché nahrazení)
Šablona je dokument nahraný na případu (nebo dostupný z něj). V šabloně se používají placeholdery ve složených závorkách, např. {companyName}.
const newFileId = docx.generate(
'sablona-smlouva.docx', // template in DMS (name, ID or attachment variable)
{
companyName: vars['COMPANY'].getTitle(),
contractDate: moment().format('DD.MM.YYYY'),
amount: vars['AMOUNT'].getValue()
},
'smlouva-vygenerovana.docx' // new file name
);
if (!newFileId) {
debug.error('Generování smlouvy selhalo.');
}
vars['CONTRACT_FILE_ID'].setValue(newFileId);
Varianta 2 — docx.docxTemplater (pokročilé šablony)
Word šablona používá značky s trojitým plus +++. Název proměnné definovaný v datech výpočtu je umístěn mezi tagy.
+++companyName+++ vloží hodnotu klíče companyName z objektu data.Postup přípravy a nasazení šablony:
- Vytvořte Word dokument s pevným obsahem (záhlaví, zápatí, struktura) a značkami
+++nazev+++v místech pro data. - Nahrajte dokument do TAS v sekci Dokumenty (Nahrát soubor).
- Najděte nahraný dokument přes filtry v části Dokumenty > Vše.
- Otevřete konzoli prohlížeče (F12), záložku Síť, a vyfiltrujte nahraný dokument.
- Zkopírujte hodnotu odpovědi za
"DMS:"— např._7d5/template-podaciArch.docx.7d5fd45a805c10856ed4b07b9ce9048b.1.1655895144727 - Cestu použijte ve výpočtu pro načtení šablony.
Kompletní výpočet generování:
// 1) Collect data from the case
const companyName = vars['companyName'].getValue();
const date = moment(vars['today'].getValue()).format('D. M. YYYY');
const items = vars['itemsDR'].getJSON(); // Dynamic Rows
const typeOfCost = dt.from('001-typeOfCost').get(); // Dynamic Table rows
const internalCaseNr = vars['internalCaseNr'].getValue();
// 2) Load the Word template from the DMS storage path
const template = lib.getFileContents(
'/app/tas/dms/_7d5/template-podaciArch.docx.7d5fd45a805c10856ed4b07b9ce9048b.1.1655895144727',
'binary'
);
// 3) Generate the document
const generated = docx.docxTemplater({
template,
data: { companyName, date, items, typeOfCost, internalCaseNr }
});
// 4) Store the generated file on the case
const fileId = lib.storeAttachment('protokol_vygenerovany.docx', generated, false);
vars['GENERATED_DOC_ID'].setValue(fileId);
Seznamy s odrážkami v šabloně
Ve Word šabloně:
+++FOR myBullet IN myBullets+++
• +++= $myBullet+++
+++END-FOR myBullet+++
Ve výpočtu stačí předat pole do data: const myBullets = vars['list'].getValue();
Tabulky z dynamické tabulky
V tabulce Word šablony se iteruje přes řádky — první buňka řádku obsahuje otvírací tag, poslední řádek zavírací:
+++FOR row IN typeOfCost+++
+++= $row.DTV_INDEX+++ +++= $row.COL_1+++ +++= $row.COL_2+++
+++END-FOR row+++
Ve výpočtu: const typeOfCost = dt.from('001-typeOfCost').get();
Tabulky z dynamických řádků (DR)
DR má sloupcovou strukturu (objekt polí), proto se iteruje přes index:
+++FOR index IN Array.from(Array(items.itemName.length).keys())+++
+++= items.itemName[$index]+++ +++= items.unitPrice[$index]+++ Kč
+++END-FOR index+++
Ve výpočtu: const items = vars['itemsDR'].getJSON();
Obrázky v šabloně (podpisy, razítka)
Ve Word šabloně: +++IMAGE workerSignature()+++
const signatureBase64 = signatureFileName
? lib.getFileContents(`${signaturesPath}/${signatureFileName}`, 'base64')
: '';
const generated = docx.docxTemplater({
template,
data: docxData,
processLineBreaksAsNewText: true,
additionalJsContext: {
workerSignature: func => ({
width: 4,
height: 2,
data: signatureBase64,
extension: '.png'
})
}
});
Generování PDF — tisky a konverze
PDF z tiskové šablony procesu
Pokud má šablona definovaný Tisk (sekce Tisk v šabloně — HTML/CSS nebo React), lze ho z výpočtu vyrenderovat do PDF a uložit jako dokument případu:
lib.printToFantomPdf(printName, fileName, forceNewPrint)
Vygeneruje PDF z tiskové šablony daného názvu a uloží ho na případ pod fileName. Parametr forceNewPrint = true vynutí generování přes Puppeteer (Nové tisky) — doporučeno pro moderní React tisky.
lib.printToFantomPdf('Objednávka - tisk', `objednavka_${vars['ORDER_NUMBER'].getValue()}.pdf`, true);lib.savePrintForm(id, docType, fileName)
Uloží tiskový report případu. Parametr id je PRNT_ID tisku (-1 = výchozí tisk), docType je 'pdf', 'doc', 'html' nebo 'printer'.
Konverze dokumentů do PDF (LibreOffice)
lib.libreConvertDmsFile(fileVariable, outFormat, filter)
Zkonvertuje soubory z proměnné typu příloha do jiného formátu (default 'pdf') a uloží je k případu. Typické použití: uživatel nahraje DOCX, proces potřebuje PDF k podpisu.
lib.libreConvertDmsFile(vars['CONTRACT_DOCX'], 'pdf');
lib.libreConvert(srcFile, outFile, filter) — stejná konverze nad cestami na disku.
Sloučení více PDF do jednoho
lib.dmsMergePdfs(inFileNames, outFileName, isOrdered)
Sloučí PDF dokumenty případu do jednoho výsledného souboru. Při isOrdered = true je pořadí stran dáno pořadím názvů v poli inFileNames.
lib.dmsMergePdfs(
['smlouva.pdf', 'priloha_1.pdf', 'podpisovy_list.pdf'],
'smlouva_komplet.pdf',
true
);
Razítka, podpisy a QR kódy do PDF
lib.modifyPdfAddImage(...)/lib.modifyPdfAddImageBase64(...)— vloží obrázek (razítko, podpis) na zvolenou pozici v PDF.lib.createQrCodeBase64(text, options)— vygeneruje QR kód (např. QR platba) jako base64 — lze vložit do PDF nebo DOCX šablony přes+++IMAGE+++.lib.createBarcodeBase64(text, options)— totéž pro čárový kód.
Práce s Excel soubory
API excel obaluje knihovnu SheetJS (xlsx). Umožňuje Excel soubory číst i vytvářet.
Čtení Excelu nahraného uživatelem
// Load the attachment content as buffer and parse the workbook
const content = storage.getDmsContent(vars['IMPORT_XLSX'], 'buffer');
const workbook = excel.read(content, { type: 'buffer' });
// Convert the first sheet to JSON rows
const sheetName = workbook.SheetNames[0];
const rows = excel.utils().sheet_to_json(workbook.Sheets[sheetName]);
proc.info('Imported rows', { count: rows.length });
Vytvoření Excelu a uložení k případu
// Build report data (e.g. from a Dynamic Table)
const data = dt.from('001-orders', ['COL_1', 'COL_2', 'COL_3'])
.whereCol('COL_3', 'APPROVED')
.get()
.map(row => ({
'Objednávka': row['COL_1'],
'Dodavatel': row['COL_2'],
'Stav': row['COL_3']
}));
// Create workbook + worksheet and store to DMS
const wb = excel.workbook();
const ws = excel.jsonToSheet(data, { skipHeader: false });
excel.appendWorksheet(wb, ws, 'Report');
excel.writeToDms(wb, 'report_objednavky.xlsx', { bookType: 'xlsx' });
excel.setCell(worksheet, 'A1', { t: 's', v: 'Nadpis' }) — typ t je 's' (string), 'n' (number) apod.Práce s CSV
storage.getCsvFile(filename, options)— načte uložený CSV soubor z CSV úložiště prostředí; options:{ firstLineHeaders, returnAsObject, delimiter, quotes }. Vrací pole objektů.lib.csvToArray(file)/lib.csvToJson(data, delimiter, firstLineColNames, parameters)— parsování CSV obsahu.lib.jsonToCsv(data, mapping)— převod dat na CSV string, který lze uložit přeslib.storeAttachment('export.csv', csvString).lib.updateDTFromCsv(dynTableName, csv, firstLineHeaders, delimiter, operation, fileName)— naplní dynamickou tabulku obsahem CSV (operacereplace/merge/append).
Příklad — import ceníku z nahraného CSV do dynamické tabulky:
const csvContent = storage.getDmsContent(vars['PRICE_CSV'], 'utf-8');
lib.updateDTFromCsv('001-pricelist', csvContent, true, ';', 'replace', 'pricelist.csv');
proc.info('Pricelist updated from CSV');
Práce se ZIP archivy
API zip slouží k balení dokumentů případu do archivu i k rozbalování přijatých archivů.
Vytvoření ZIP z dokumentů případu
// Collect IDs of all PDF documents on the case
const fileIds = lib.getDMSFileIds('*.pdf', '|').split('|').filter(Boolean);
zip.start();
zip.addDmsFiles(fileIds);
zip.storeZip(); // saves to temp folder
// Store the zip on the case as a document
const zipId = storage.saveToDms(zip.getTempFilePath(), 'dokumentace_pripadu.zip');
zip.deleteTempZip();
vars['ARCHIVE_FILE_ID'].setValue(zipId);
Rozbalení ZIP archivu
zip.unzipDmsFile(id)— rozbalí ZIP z DMS a jednotlivé soubory přiloží k případu jako dokumenty.zip.unzipAndExport(id, exportPath, flattening)— rozbalí ZIP z DMS a obsah exportuje na zadanou cestu na disku.zip.gzip(data)/zip.gunzip(data)— komprese a dekomprese dat (např. pro integrace).
Organizace dokumentů — složky, atributy, revize
Složky DMS
storage.createDmsFolder(folderName, parentFolderId)— vytvoří složku (pokud neexistuje) a vrátí ji.storage.getDmsFolder(folderName, parentFolderId)— najde složku;result.FOLDER_IDlze použít jako parent.storage.setDmsFileFolder(id, folderName, parentId)— zařadí dokument do složky (složka se automaticky vytvoří, pokud neexistuje).
const contractId = docx.generate('sablona.docx', data, 'smlouva.docx');
storage.setDmsFileFolder(contractId, 'Smlouvy');DMS atributy (tagy) a logický typ
storage.setDmsTagValue(tagId, value, files)— nastaví hodnotu DMS atributu (text / číslo / datum / číselník) pro dané dokumenty. Bez parametrufilesse nastaví všem dokumentům případu.lib.setDocumentLogicalType(fileName, logicTypeKey)— nastaví logický typ dokumentu (číselník spravuje$Administratorv Administrace > DMS atributy).
Revize, existence, mazání a export
lib.storeAttachmentAsRevision(...)— nová verze existujícího dokumentu (viz kapitola Ukládání).storage.getDmsEntityByName(name, searchRevisions)— ssearchRevisions = truehledá i mezi staršími revizemi.storage.dmsFileExists(id)— ověří fyzickou existenci souboru.storage.dmsDeletePermanently(id)— trvale smaže dokument včetně všech revizí (nevratné!).storage.exportDmsFile(id, destination)— zkopíruje dokument na cestu na disku (např. pro předání externímu systému přes sdílený adresář).lib.exportAttachmentToTMP(identifier, exportDocName, encoding)— export do TMP složky; po zpracování uklidit přeslib.cleanupTMP(tmpFolder).storage.getAttachmentsSize(ids)— celková velikost souborů v bytech (např. kontrola limitu příloh emailu).
storage.dmsDeletePermanently maže dokument nevratně včetně všech revizí. Používejte pouze u dočasných / generovaných souborů, nikdy u dokumentů nahraných uživateli, pokud to není výslovný požadavek procesu.Vyhledávání dokumentů na případu
lib.getDMSFiles(nameFilter, glue, attrNames)— najde přílohy případu podle filtru názvu ('*'= všechny, jinak case-sensitive porovnání) a vrátí zvolené atributy spojené znakemglue.lib.getDMSFileNames(nameFilter, glue)— vrátí názvy nalezených souborů.lib.getDMSFileIds(nameFilter, glue)— vrátí ID nalezených souborů.
// All PDF files on the case as an array of IDs
const pdfIds = lib.getDMSFileIds('*.pdf', ';').split(';').filter(Boolean);
// Total size check before sending by email (limit 10 MB)
const totalSize = storage.getAttachmentsSize(pdfIds);
if (totalSize > 10 * 1024 * 1024) {
debug.error('Dokumenty přesahují limit 10 MB pro odeslání emailem.');
}
Odesílání dokumentů
lib.addMailNotifsAttachment(dmsfName)— přiloží dokument případu k odchozí emailové notifikaci úkolu. Volá se ve výpočtu úkolu, jehož notifikace má dokument obsahovat.lib.copySharedFileLink(iprocId, varName)— zkopíruje odkaz na sdílený soubor mezi případy.lib.addPublicFileToAttachment(publicFileName, dmsAttachmentName)— přiloží veřejný soubor prostředí (např. obchodní podmínky) jako dokument případu.- Odeslání souboru do externího systému přes HTTP — axios klient z konektoru ve Skriptech umožňuje odeslat i soubor (viz axios dokumentace, metody pro soubory /
Buffer.from).
AI vytěžení dokumentů
ai.processDocument(fileName, schema)
Od TAS 5.15 (s aktivovanou AI integrací) odešle dokument případu do AI, vytěží z něj strukturovaná data podle schématu a naplní proměnné případu. Typické použití: automatické vytěžení přijaté faktury (dodavatel, částka, datum splatnosti, položky) po jejím nahrání nebo přijetí emailem.
Reálné use case — kompletní příklady
Use case 1 — Generování smlouvy a konverze do PDF k podpisu
Scénář: Po schválení objednávky se ze šablony vygeneruje smlouva (DOCX), zkonvertuje do PDF, zařadí do složky a její ID se uloží do proměnné pro podpisový úkol.
// 1) Generate the contract from a Word template stored on the case
const contractId = docx.generate('sablona-smlouva.docx', {
supplierName: vars['SUPPLIER'].getTitle(),
orderNumber: vars['ORDER_NUMBER'].getValue(),
totalAmount: vars['TOTAL_AMOUNT'].getValue(),
signDate: moment().format('DD.MM.YYYY')
}, `smlouva_${vars['ORDER_NUMBER'].getValue()}.docx`);
if (!contractId) {
debug.error('Generování smlouvy selhalo — zkontrolujte šablonu.');
}
// 2) Convert the generated DOCX to PDF (stored back on the case)
vars['CONTRACT_DOCX_ID'].setValue(contractId);
lib.libreConvertDmsFile(vars['CONTRACT_DOCX_ID'], 'pdf');
// 3) Organize into a folder and log
storage.setDmsFileFolder(contractId, 'Smlouvy');
proc.info('Contract generated and converted', { contractId, caseId: lib.iprocId() });
Use case 2 — Měsíční Excel report z dynamické tabulky (cron)
Scénář: Plánovaný výpočet každý měsíc sestaví přehled schválených objednávek do Excelu a uloží ho na reportingový případ.
const monthLabel = moment().subtract(1, 'month').format('YYYY-MM');
const rows = dt.from('001-orders', ['COL_1', 'COL_2', 'COL_4', 'COL_5'])
.whereCol('COL_5', 'APPROVED')
.orderBy('COL_1', 'asc')
.get()
.map(r => ({
'Číslo objednávky': r['COL_1'],
'Dodavatel': r['COL_2'],
'Částka': r['COL_4']
}));
const wb = excel.workbook();
excel.appendWorksheet(wb, excel.jsonToSheet(rows, { skipHeader: false }), monthLabel);
excel.writeToDms(wb, `report_${monthLabel}.xlsx`, { bookType: 'xlsx' });
proc.info('Monthly report generated', { month: monthLabel, rows: rows.length });Use case 3 — Kompletace dokumentace: merge PDF + ZIP archiv
Scénář: Na konci procesu se všechny PDF dokumenty sloučí do jednoho „kompletu" a zároveň se všechny dokumenty zabalí do ZIP pro archivaci.
// 1) Merge key PDFs into one document (order preserved)
lib.dmsMergePdfs(
['smlouva.pdf', 'priloha_1.pdf', 'akceptacni_protokol.pdf'],
'komplet_dokumentace.pdf',
true
);
// 2) Zip all case documents
const allIds = lib.getDMSFileIds('*', '|').split('|').filter(Boolean);
zip.start();
zip.addDmsFiles(allIds);
zip.storeZip();
const zipId = storage.saveToDms(zip.getTempFilePath(), `archiv_${lib.iprocId()}.zip`);
zip.deleteTempZip();
storage.setDmsFileFolder(zipId, 'Archiv');
vars['ARCHIVE_ID'].setValue(zipId);
Use case 4 — Import dat z nahraného Excelu do dynamických řádků
Scénář: Uživatel nahraje Excel s položkami objednávky, výpočet je načte a naplní jimi DR proměnnou na formuláři.
const content = storage.getDmsContent(vars['ITEMS_XLSX'], 'buffer');
const workbook = excel.read(content, { type: 'buffer' });
const rows = excel.utils().sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
// Derive the DR column structure from the existing variable (never hardcode)
const existingDR = vars['ORDER_ITEMS'].getJSON();
const newDR = Object.fromEntries(Object.keys(existingDR).map(key => [key, []]));
rows.forEach(row => {
newDR.itemName.push(row['Název']);
newDR.quantity.push(row['Množství']);
newDR.unitPrice.push(row['Cena/ks']);
});
vars['ORDER_ITEMS'].setValue(JSON.stringify(newDR));
proc.info('Items imported from Excel', { count: rows.length });
Souhrnný přehled funkcí
Oblast | Funkce |
Čtení |
|
Ukládání |
|
Generování DOCX |
|
| |
Excel / CSV |
|
ZIP |
|
Organizace |
|
Vyhledávání / kontrola |
|
Export / mazání |
|
Odesílání / AI |
|
StorageApi, DocxApi, ExcelApi, ZipApi, EvalMathApi) na instalaci klienta.
Updated
by Frantisek Brych