/* * AGS 92 B2B – náhľad faktúry + QR platba * Súbor: /buxus/docs/faktury-nahlad.js.txt (načítaný v pätičke, Container 22 → Content after) * * Na stránke „Moje faktúry“ (page_id 257) pridá ku každej faktúre odkaz „Náhľad“ (okno s vykreslenou faktúrou, * tlačidlá Stiahnuť / Tlačiť / Reklamovať) a pri nezaplatených faktúrach „QR platba“ – platobný QR kód * vyrezaný priamo z PDF faktúry (Money: SK PAY by square, CZ QR Platba). Nič sa negeneruje, údaje sú * vždy z tej faktúry, ktorú partner vidí. Ak PDF QR neobsahuje (HU), zobrazia sa len platobné údaje. * * Verejné rozhranie pre ďalšie skripty: window.agsFaktura.openPreview(pdfUrl, cislo, zostatok), .openQR(...) */ (function () { 'use strict'; if (window.__agsFakturaNahladLoaded) return; window.__agsFakturaNahladLoaded = true; var PDFJS = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js'; var PDFJS_WORKER = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; var QR_MARKETS = { sk: 1, cz: 1 }; // kde PDF faktúry obsahuje platobný QR (HU/PL doplniť po zapnutí v Money) var REKLAMACIE_PAGE = 652491; var QR_CACHE_MAX = 40; // koľko QR kódov držať v localStorage (per prehliadač) var lang = (location.pathname.split('/')[1] || '').toLowerCase(); if (!/^(sk|cz|hu|pl|com)$/.test(lang)) return; var L = lang === 'com' ? 'en' : lang; if (!document.querySelector('.header-basic-info h3')) return; // len prihlásený partner var T = { sk: { preview: 'Náhľad', qr: 'QR platba', download: 'Stiahnuť PDF', print: 'Tlačiť', claim: 'Reklamovať', close: 'Zavrieť', loading: 'Načítavam faktúru…', qrTitle: 'QR platba – faktúra', scan: 'Naskenujte QR kód v mobilnej bankovej aplikácii.', remaining: 'Zostáva uhradiť', total: 'Suma na faktúre', partial: 'Faktúra je čiastočne uhradená – v bankovej aplikácii upravte sumu na zostatok.', iban: 'IBAN', swift: 'SWIFT', vs: 'Variabilný symbol', copy: 'Kopírovať', copied: 'Skopírované', save: 'Uložiť QR', noQr: 'Táto faktúra neobsahuje platobný QR kód. Použite platobné údaje nižšie.', err: 'Faktúru sa nepodarilo načítať. Skúste to znova alebo si ju stiahnite.', page: 'Strana', of: 'z' }, cz: { preview: 'Náhled', qr: 'QR platba', download: 'Stáhnout PDF', print: 'Tisknout', claim: 'Reklamovat', close: 'Zavřít', loading: 'Načítám fakturu…', qrTitle: 'QR platba – faktura', scan: 'Naskenujte QR kód v mobilní bankovní aplikaci.', remaining: 'Zbývá uhradit', total: 'Částka na faktuře', partial: 'Faktura je částečně uhrazena – v bankovní aplikaci upravte částku na zůstatek.', iban: 'IBAN', swift: 'SWIFT', vs: 'Variabilní symbol', copy: 'Kopírovat', copied: 'Zkopírováno', save: 'Uložit QR', noQr: 'Tato faktura neobsahuje platební QR kód. Použijte platební údaje níže.', err: 'Fakturu se nepodařilo načíst. Zkuste to znovu nebo si ji stáhněte.', page: 'Strana', of: 'z' }, hu: { preview: 'Előnézet', qr: 'QR fizetés', download: 'PDF letöltése', print: 'Nyomtatás', claim: 'Reklamáció', close: 'Bezárás', loading: 'Számla betöltése…', qrTitle: 'QR fizetés – számla', scan: 'Olvassa be a QR kódot a mobilbanki alkalmazásban.', remaining: 'Fizetendő', total: 'Számla összege', partial: 'A számla részben ki van fizetve – a banki alkalmazásban módosítsa az összeget.', iban: 'IBAN', swift: 'SWIFT', vs: 'Közlemény / azonosító', copy: 'Másolás', copied: 'Másolva', save: 'QR mentése', noQr: 'Ez a számla nem tartalmaz fizetési QR kódot. Használja az alábbi adatokat.', err: 'A számla betöltése nem sikerült. Próbálja újra vagy töltse le.', page: 'Oldal', of: '/' }, pl: { preview: 'Podgląd', qr: 'Płatność QR', download: 'Pobierz PDF', print: 'Drukuj', claim: 'Reklamacja', close: 'Zamknij', loading: 'Ładowanie faktury…', qrTitle: 'Płatność QR – faktura', scan: 'Zeskanuj kod QR w aplikacji bankowej.', remaining: 'Do zapłaty', total: 'Kwota faktury', partial: 'Faktura jest częściowo opłacona – w aplikacji bankowej zmień kwotę.', iban: 'IBAN', swift: 'SWIFT', vs: 'Tytuł / numer', copy: 'Kopiuj', copied: 'Skopiowano', save: 'Zapisz QR', noQr: 'Ta faktura nie zawiera kodu QR. Użyj danych poniżej.', err: 'Nie udało się wczytać faktury. Spróbuj ponownie lub pobierz ją.', page: 'Strona', of: 'z' }, en: { preview: 'Preview', qr: 'QR payment', download: 'Download PDF', print: 'Print', claim: 'Claim', close: 'Close', loading: 'Loading invoice…', qrTitle: 'QR payment – invoice', scan: 'Scan the QR code in your mobile banking app.', remaining: 'Amount due', total: 'Invoice amount', partial: 'The invoice is partially paid – adjust the amount in your banking app.', iban: 'IBAN', swift: 'SWIFT', vs: 'Payment reference', copy: 'Copy', copied: 'Copied', save: 'Save QR', noQr: 'This invoice has no payment QR code. Use the payment details below.', err: 'The invoice could not be loaded. Try again or download it.', page: 'Page', of: 'of' } }[L]; // ---------- pomocné ---------- function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } function parseAmount(s) { s = (s || '').replace(/[^\d,.\-]/g, ''); if (s.indexOf(',') > -1 && s.indexOf('.') > -1) s = s.replace(/,/g, ''); else s = s.replace(',', '.'); var v = parseFloat(s); return isNaN(v) ? 0 : v; } function lsGet(k) { try { return JSON.parse(localStorage.getItem(k) || 'null'); } catch (e) { return null; } } function lsSet(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); } catch (e) {} } function el(tag, cls, html) { var e = document.createElement(tag); if (cls) e.className = cls; if (html != null) e.innerHTML = html; return e; } // IBAN: z textu odstráni medzery a prípadný text nalepený za IBANom, overí kontrolný súčet (mod 97) function validIban(s) { s = (s || '').replace(/\s+/g, '').toUpperCase(); for (var len = Math.min(s.length, 34); len >= 15; len--) { var c = s.slice(0, len), r = c.slice(4) + c.slice(0, 4), n = ''; for (var i = 0; i < r.length; i++) { var ch = r.charCodeAt(i); n += ch >= 65 ? String(ch - 55) : r[i]; } var m = 0; for (var j = 0; j < n.length; j++) m = (m * 10 + (+n[j])) % 97; if (m === 1) return c; } return ''; } function invoiceId(url) { return ((url || '').match(/invoice_id=([A-Za-z0-9\-]+)/) || ['', ''])[1]; } function copyText(t, btn) { var done = function () { var o = btn.textContent; btn.textContent = T.copied; setTimeout(function () { btn.textContent = o; }, 1500); }; if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(t).then(done, function () { fallback(); }); else fallback(); function fallback() { var ta = document.createElement('textarea'); ta.value = t; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); done(); } catch (e) {} ta.remove(); } } // ---------- pdf.js ---------- var pdfjsP = null; function loadPdfJs() { if (window.pdfjsLib) { window.pdfjsLib.GlobalWorkerOptions.workerSrc = window.pdfjsLib.GlobalWorkerOptions.workerSrc || PDFJS_WORKER; return Promise.resolve(window.pdfjsLib); } if (pdfjsP) return pdfjsP; pdfjsP = new Promise(function (res, rej) { var def = window.define; window.define = undefined; // pdf.js by sa inak zaregistroval do requirejs stránky var s = document.createElement('script'); s.src = PDFJS; s.onload = function () { window.define = def; window.pdfjsLib.GlobalWorkerOptions.workerSrc = PDFJS_WORKER; res(window.pdfjsLib); }; s.onerror = function () { window.define = def; pdfjsP = null; rej(new Error('pdfjs')); }; document.head.appendChild(s); }); return pdfjsP; } // PDF dokumenty držíme v pamäti stránky (nie v localStorage) – server ich generuje ~3 s var docCache = {}; function getDoc(url) { if (docCache[url]) return docCache[url]; docCache[url] = loadPdfJs().then(function (lib) { return fetch(url, { credentials: 'same-origin' }).then(function (r) { if (!r.ok) throw new Error('http ' + r.status); return r.arrayBuffer(); }) .then(function (buf) { return lib.getDocument({ data: buf }).promise.then(function (pdf) { return { pdf: pdf, buf: buf }; }); }); }); docCache[url].catch(function () { delete docCache[url]; }); return docCache[url]; } // ---------- platobné údaje + QR z PDF ---------- var QR_KEY = 'ags_qr_' + lang; function qrCacheGet(id) { var c = lsGet(QR_KEY) || {}; return c[id] || null; } function qrCachePut(id, v) { var c = lsGet(QR_KEY) || {}; v.t = Date.now(); c[id] = v; var keys = Object.keys(c); if (keys.length > QR_CACHE_MAX) { keys.sort(function (a, b) { return c[a].t - c[b].t; }).slice(0, keys.length - QR_CACHE_MAX).forEach(function (k) { delete c[k]; }); } lsSet(QR_KEY, c); } function extractPayment(url) { var id = invoiceId(url) || url; var cached = qrCacheGet(id); if (cached) return Promise.resolve(cached); return getDoc(url).then(function (d) { var pdf = d.pdf, lib = window.pdfjsLib; var pageNums = []; for (var p = 1; p <= Math.min(pdf.numPages, 4); p++) pageNums.push(p); // text zo všetkých strán (IBAN/VS sú na 1., súčty na poslednej); QR býva na poslednej strane (CZ) alebo na 1. (SK) return Promise.all(pageNums.map(function (pn) { return pdf.getPage(pn).then(function (page) { return page.getTextContent().then(function (tc) { var text = tc.items.map(function (i) { return i.str; }).join(' ').replace(/\s+/g, ' '); return withTimeout(page.getOperatorList(), 8000).then(function (ops) { var names = []; for (var i = 0; i < ops.fnArray.length; i++) if (ops.fnArray[i] === lib.OPS.paintImageXObject || ops.fnArray[i] === lib.OPS.paintJpegXObject) names.push(ops.argsArray[i][0]); return Promise.all(names.map(function (n) { return withTimeout(new Promise(function (res) { try { page.objs.get(n, res); } catch (e) { res(null); } }), 4000).catch(function () { return null; }); })); }).catch(function () { return []; }).then(function (imgs) { return { text: text, imgs: imgs }; }); }); }); })).then(function (pages) { var text = pages.map(function (x) { return x.text; }).join(' '); var g = function (re) { var m = text.match(re); return m ? m[1].replace(/\s+/g, '') : ''; }; var info = { iban: validIban(g(/IBAN:?\s*([A-Z]{2}\d{2}[A-Z0-9 ]{10,40})/)), swift: g(/SWIFT:?\s*([A-Z0-9]{8,11})/), account: g(/(?:Číslo účtu|Číslo účtu|Účet|Számlaszám|Nr rachunku|Account):?\s*([A-Z0-9\-\/ ]{8,34}?)(?=\s{2}|\s[A-ZÁ-Ž])/), vs: g(/Variabiln[ýí] symbol:?\s*(\d{4,12})/i) || g(/Var\.?\s*(?:symbol|kód):?\s*(\d{4,12})/i) }; // suma na faktúre: „Zostáva uhradiť / Zbývá uhradit / Fizetendő összeg“ (CZ zostava má číslo PRED „Celková částka“, preto nie ten riadok) var tm = text.match(/(?:Zostáva uhradiť|Zbývá uhradit|Fizetendő összeg|Do zapłaty|Amount due)\s*:?\s*(\d[\d\s]*[,.]\d{2})\s*(EUR|CZK|Kč|HUF|Ft|PLN|zł)?/i); info.totalTxt = tm ? (tm[1].replace(/\s+/g, ' ') + ' ' + (tm[2] || '')).trim() : ''; // platobný QR = najväčší približne štvorcový obrázok (logo je široké, čiarový kód veľmi široký); hľadá sa od poslednej strany var best = null, bestScore = 0; pages.slice().reverse().forEach(function (pg) { pg.imgs.forEach(function (img) { if (!img || !img.width || !img.height || img.width < 120) return; var r = img.width / img.height; if (r < 0.6 || r > 1.4) return; var score = img.width * img.height * (1 - Math.abs(1 - r)); if (score > bestScore) { bestScore = score; best = img; } }); }); if (best) { var c = document.createElement('canvas'); c.width = best.width; c.height = best.height; var ctx = c.getContext('2d'); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, c.width, c.height); if (best.bitmap) ctx.drawImage(best.bitmap, 0, 0); else if (best.data) { var imd = ctx.createImageData(best.width, best.height); if (best.data.length === imd.data.length) imd.data.set(best.data); else { for (var p = 0, q = 0; p < imd.data.length; p += 4, q += 3) { imd.data[p] = best.data[q]; imd.data[p + 1] = best.data[q + 1]; imd.data[p + 2] = best.data[q + 2]; imd.data[p + 3] = 255; } } ctx.putImageData(imd, 0, 0); } info.qr = c.toDataURL('image/png'); } qrCachePut(id, info); return info; }); }); } function withTimeout(p, ms) { return Promise.race([p, new Promise(function (_, rej) { setTimeout(function () { rej(new Error('timeout')); }, ms); })]); } // ---------- UI ---------- function ico(path) { return 'url("data:image/svg+xml;utf8,' + encodeURIComponent("" + path + "") + '")'; } var CSS = '' + '.ags-fx-cell{white-space:nowrap;vertical-align:top}.ags-fx-cell a{display:block;font-size:12px;line-height:1.75;cursor:pointer;text-decoration:none;color:#1c84c6}' + '.ags-fx-cell a:before{content:"";display:inline-block;width:13px;height:13px;margin-right:5px;vertical-align:-2px;background-repeat:no-repeat;background-size:13px 13px}' + '.ags-fx-cell a.ags-fx-prev:before{background-image:' + ico("") + '}' + '.ags-fx-cell a.ags-fx-dl:before{background-image:' + ico("") + '}' + '.ags-fx-cell a.qr{font-weight:bold}.ags-fx-cell a.qr:before{background-image:' + ico("") + '}' + '.ags-fx-cell a.ags-inv-btn:before{background-image:' + ico("") + '}' + '.ags-fx-orig{display:none}.ags-fx-date{white-space:nowrap}' + '.ags-fx-ov{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:100001;display:flex;align-items:flex-start;justify-content:center;padding:20px 12px;overflow:auto}' + '.ags-fx-md{background:#fff;color:#222;width:100%;max-width:900px;border-radius:6px;box-shadow:0 10px 40px rgba(0,0,0,.35);font:14px/1.45 Arial,Helvetica,sans-serif;display:flex;flex-direction:column;max-height:calc(100vh - 40px)}' + '.ags-fx-hd{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid #e3e3e3;flex-wrap:wrap}' + '.ags-fx-hd b{font-size:15px;margin-right:auto}' + '.ags-fx-hd a,.ags-fx-hd button{display:inline-block;padding:6px 12px;border-radius:4px;border:1px solid #c9d6e2;background:#fff;color:#1c84c6;font-size:13px;cursor:pointer;text-decoration:none;line-height:1.2}' + '.ags-fx-hd a.pri,.ags-fx-hd button.pri{background:#1c84c6;border-color:#1c84c6;color:#fff}' + '.ags-fx-hd button.x{border:0;background:none;color:#666;font-size:20px;padding:0 4px}' + '.ags-fx-bd{overflow:auto;background:#777;padding:12px;text-align:center;flex:1}' + '.ags-fx-bd canvas{display:block;margin:0 auto 12px;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,.4);max-width:100%;height:auto}' + '.ags-fx-bd .msg{color:#fff;padding:30px 10px}' + '.ags-fx-qr{background:#fff;padding:16px;display:flex;gap:20px;flex-wrap:wrap;justify-content:center;align-items:flex-start;text-align:left}' + '.ags-fx-qr img{width:260px;max-width:100%;image-rendering:pixelated;border:1px solid #ddd;border-radius:4px}' + '.ags-fx-qr .info{min-width:260px;flex:1;max-width:420px}' + '.ags-fx-qr .amt{font-size:22px;font-weight:bold;color:#c0392b;margin:0 0 4px}' + '.ags-fx-qr .lbl{font-size:12px;color:#666}' + '.ags-fx-qr .pr{display:flex;align-items:center;justify-content:space-between;gap:8px;border-bottom:1px solid #eee;padding:6px 0}' + '.ags-fx-qr .pr code{font-size:14px;letter-spacing:.3px;color:#222;background:none;padding:0}' + '.ags-fx-qr .pr button{padding:3px 8px;font-size:12px;border:1px solid #c9d6e2;background:#f7f9fb;border-radius:3px;cursor:pointer}' + '.ags-fx-qr .warn{background:#fff6e5;border:1px solid #f0c36d;padding:8px 10px;border-radius:4px;margin:10px 0;font-size:13px}' + '.ags-fx-qr .save{display:inline-block;margin-top:10px;font-size:13px}' + '@media print{.ags-fx-ov{display:none!important}}'; function injectCss() { if (document.getElementById('ags-fx-css')) return; var s = el('style'); s.id = 'ags-fx-css'; s.textContent = CSS; document.head.appendChild(s); } var overlay = null; function closeModal() { if (overlay) { overlay.remove(); overlay = null; document.body.style.overflow = ''; } } document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeModal(); }); function openModal(ctx, mode) { injectCss(); closeModal(); overlay = el('div', 'ags-fx-ov'); var md = el('div', 'ags-fx-md'); var hd = el('div', 'ags-fx-hd'); hd.appendChild(el('b', '', esc(mode === 'qr' ? T.qrTitle + ' ' + ctx.no : ctx.no))); var btns = []; if (mode === 'qr') { var bP = el('button', '', esc(T.preview)); bP.addEventListener('click', function () { openModal(ctx, 'preview'); }); btns.push(bP); } else if (ctx.unpaid > 0 && QR_MARKETS[lang]) { var bQ = el('button', 'pri', esc(T.qr)); bQ.addEventListener('click', function () { openModal(ctx, 'qr'); }); btns.push(bQ); } var aD = el('a', '', esc(T.download)); aD.href = ctx.pdf; btns.push(aD); var bT = el('button', '', esc(T.print)); bT.addEventListener('click', function () { printPdf(ctx); }); btns.push(bT); var aR = el('a', '', esc(T.claim)); aR.href = '/' + lang + '/buxus/generate_page.php?page_id=' + REKLAMACIE_PAGE + '&faktura=' + encodeURIComponent(ctx.no) + '&zdroj=faktury'; btns.push(aR); var bX = el('button', 'x', '×'); bX.setAttribute('aria-label', T.close); bX.addEventListener('click', closeModal); btns.push(bX); btns.forEach(function (b) { hd.appendChild(b); }); md.appendChild(hd); var bd = el('div', 'ags-fx-bd', '
' + esc(T.loading) + '
'); md.appendChild(bd); overlay.appendChild(md); overlay.addEventListener('click', function (e) { if (e.target === overlay) closeModal(); }); document.body.appendChild(overlay); document.body.style.overflow = 'hidden'; if (mode === 'qr') renderQR(ctx, bd); else renderPreview(ctx, bd); } function renderPreview(ctx, bd) { getDoc(ctx.pdf).then(function (d) { var pdf = d.pdf; bd.innerHTML = ''; var width = Math.min(860, bd.clientWidth - 24), dpr = Math.min(window.devicePixelRatio || 1, 2); var chain = Promise.resolve(); for (var p = 1; p <= pdf.numPages; p++) (function (pn) { chain = chain.then(function () { return pdf.getPage(pn).then(function (page) { var vp0 = page.getViewport({ scale: 1 }), scale = width / vp0.width, vp = page.getViewport({ scale: scale * dpr }); var c = el('canvas'); c.width = vp.width; c.height = vp.height; c.style.width = Math.round(vp.width / dpr) + 'px'; bd.appendChild(c); return page.render({ canvasContext: c.getContext('2d'), viewport: vp }).promise; }); }); })(p); return chain; }).catch(function () { bd.innerHTML = '
' + esc(T.err) + '
'; }); } function renderQR(ctx, bd) { extractPayment(ctx.pdf).then(function (info) { bd.innerHTML = ''; var box = el('div', 'ags-fx-qr'); if (info.qr) { var img = el('img'); img.src = info.qr; img.alt = 'QR'; box.appendChild(img); } var inf = el('div', 'info'); var h = ''; if (info.qr) h += '

' + esc(T.scan) + '

'; else h += '

' + esc(T.noQr) + '

'; if (ctx.unpaidTxt) h += '
' + esc(T.remaining) + '

' + esc(ctx.unpaidTxt) + '

'; if (info.totalTxt && ctx.unpaid > 0 && Math.abs(parseAmount(info.totalTxt) - ctx.unpaid) > 0.005) h += '
' + esc(T.partial) + ' (' + esc(T.total) + ': ' + esc(info.totalTxt) + ')
'; var rows = [[T.iban, info.iban || info.account], [T.swift, info.swift], [T.vs, info.vs || ctx.vs]]; rows.forEach(function (r) { if (r[1]) h += '
' + esc(r[0]) + '
' + esc(r[1]) + '
'; }); if (info.qr) h += '' + esc(T.save) + ''; inf.innerHTML = h; box.appendChild(inf); bd.appendChild(box); [].forEach.call(inf.querySelectorAll('button[data-copy]'), function (b) { b.addEventListener('click', function () { copyText(b.getAttribute('data-copy'), b); }); }); }).catch(function () { bd.innerHTML = '
' + esc(T.err) + '
'; }); } function printPdf(ctx) { getDoc(ctx.pdf).then(function (d) { var url = URL.createObjectURL(new Blob([d.buf], { type: 'application/pdf' })); var f = document.createElement('iframe'); f.style.cssText = 'position:fixed;right:0;bottom:0;width:0;height:0;border:0'; f.src = url; document.body.appendChild(f); f.onload = function () { try { f.contentWindow.focus(); f.contentWindow.print(); } catch (e) { window.open(url, '_blank'); } setTimeout(function () { f.remove(); URL.revokeObjectURL(url); }, 60000); }; }).catch(function () { window.open(ctx.pdf, '_blank'); }); } // ---------- zoznam faktúr ---------- function rowCtx(r) { var a = r.querySelector('a[href*="invoice_id="]'); if (!a) return null; var c = r.cells; return { no: c[0].textContent.trim(), vs: c[1].textContent.trim(), pdf: a.href, unpaidTxt: c[7].textContent.trim(), unpaid: parseAmount(c[7].textContent), credit: /dobropis/i.test(r.className) }; } function decorateRows() { injectCss(); [].forEach.call(document.querySelectorAll('table tr'), function (r) { if (r.__agsFx || !r.querySelector('td') || r.cells.length < 8) return; var ctx = rowCtx(r); if (!ctx) return; r.__agsFx = true; // dátumy: „13.Jul.2026 00:00:00“ → zobraziť „13.07.2026“ (pôvodný text zostáva skrytý pre ostatné skripty) [2, 3].forEach(function (ci) { var c = r.cells[ci]; if (!c || c.querySelector('.ags-fx-date')) return; var d = niceDate(c.textContent); if (d) c.innerHTML = '' + esc(c.textContent.trim()) + '' + esc(d) + ''; }); // akcie v poslednom stĺpci: Náhľad / Stiahnuť PDF / QR platba (+ Položky z reklamačného skriptu), každá na vlastnom riadku var cell = r.cells[r.cells.length - 1]; cell.classList.add('ags-fx-cell'); var pdfLink = cell.querySelector('a[href*="invoice_id="]'); if (pdfLink) { pdfLink.textContent = T.download; pdfLink.classList.add('ags-fx-dl'); } var aP = el('a', 'ags-fx-prev', esc(T.preview)); aP.addEventListener('click', function (e) { e.preventDefault(); openModal(ctx, 'preview'); }); if (pdfLink) cell.insertBefore(aP, pdfLink); else cell.appendChild(aP); if (ctx.unpaid > 0 && !ctx.credit && QR_MARKETS[lang]) { var aQ = el('a', 'qr', esc(T.qr)); aQ.addEventListener('click', function (e) { e.preventDefault(); openModal(ctx, 'qr'); }); if (pdfLink && pdfLink.nextSibling) cell.insertBefore(aQ, pdfLink.nextSibling); else cell.appendChild(aQ); } }); } var MONTHS = { jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6, jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12 }; function niceDate(s) { var m = (s || '').trim().match(/^(\d{1,2})\.\s*([A-Za-z]{3}|\d{1,2})\.?\s*(\d{4})/); if (!m) return ''; var mo = /\d/.test(m[2]) ? +m[2] : MONTHS[m[2].toLowerCase()]; if (!mo) return ''; var dd = ('0' + m[1]).slice(-2), mm = ('0' + mo).slice(-2); return lang === 'hu' ? m[3] + '.' + mm + '.' + dd : dd + '.' + mm + '.' + m[3]; // HU zvyk: 2026.07.13 } if (document.querySelector('a[href*="invoice_id="]')) { decorateRows(); var t = document.querySelector('a[href*="invoice_id="]').closest('table'); if (t && window.MutationObserver) new MutationObserver(function () { decorateRows(); }).observe(t, { childList: true, subtree: true }); } // rozhranie pre iné skripty (napr. upozornenie po splatnosti) window.agsFaktura = { openPreview: function (pdf, no, unpaidTxt) { openModal({ no: no, vs: '', pdf: pdf, unpaidTxt: unpaidTxt || '', unpaid: parseAmount(unpaidTxt || '') }, 'preview'); }, openQR: function (pdf, no, unpaidTxt) { openModal({ no: no, vs: '', pdf: pdf, unpaidTxt: unpaidTxt || '', unpaid: parseAmount(unpaidTxt || '') }, 'qr'); } }; })();