Kartica emulator (BE) + fiskalna verifikacija + ime/prezime korisnika

- internal/be: emulator kartice (TCP listener za L-PFR mock)
- /v/: javna stranica za verifikaciju fiskalnog računa (QR kod)
- /servis/{id}/fiskalni-racun: štampa fiskalnog računa
- Podešavanja fiskalizacije: BE status/reset, proširen UI
- Korisnik: polja ime i prezime (model, DB, handler, admin profil)
- Fisk server: ažuriran receipt.py i server.py
- Koncept.md, Magacin.md: dokumentacija
This commit is contained in:
2026-06-26 23:17:52 +02:00
parent 9197404db0
commit e6215a43fe
23 changed files with 2778 additions and 116 deletions
+21
View File
@@ -1,6 +1,27 @@
{{ template "base" . }} {{ define "naslov" }}Moj profil — NTech{{ end }}
{{ define "sadrzaj" }}
<div class="stranica-stack" style="display: flex; flex-direction: column; gap: 16px; max-width: 560px">
<!-- ime i prezime -->
<div class="kartica animiraj">
<div style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni); margin-bottom: 16px; padding-bottom: 12px; border-bottom: 0.5px solid var(--ivica)">Ime i prezime</div>
<form method="POST" action="/admin/profil/ime-prezime">
<div style="display: flex; flex-direction: column; gap: 12px">
<div>
<label class="polje-labela">Ime</label>
<input type="text" name="ime" value="{{.Ime}}" placeholder="npr. Petar" style="width: 100%; box-sizing: border-box" />
</div>
<div>
<label class="polje-labela">Prezime</label>
<input type="text" name="prezime" value="{{.Prezime}}" placeholder="npr. Petrović" style="width: 100%; box-sizing: border-box" />
</div>
<div class="pomocni-tekst">Koristi se kao „Kasir" na fiskalnom računu.</div>
<div>
<button type="submit" class="btn-primarno">Sačuvaj</button>
</div>
</div>
</form>
</div>
<!-- promena lozinke -->
<div class="kartica animiraj">
<div style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni); margin-bottom: 16px; padding-bottom: 12px; border-bottom: 0.5px solid var(--ivica)">Promena lozinke</div>
@@ -0,0 +1,232 @@
<!DOCTYPE html>
<html lang="sr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verifikacija fiskalnog računa</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; font-size: 14px; color: #1e293b; background: #f1f5f9; min-height: 100vh; }
.omotac { max-width: 520px; margin: 0 auto; padding: 0 0 48px; }
/* baner */
.baner { padding: 20px 20px 16px; text-align: center; }
.baner.ok { background: #16a34a; color: #fff; }
.baner.greska { background: #dc2626; color: #fff; }
.baner-ikona { font-size: 36px; line-height: 1; margin-bottom: 6px; }
.baner-tekst { font-size: 18px; font-weight: 700; }
.baner-podnaslov { font-size: 13px; margin-top: 4px; opacity: 0.85; }
/* zaglavlje firme */
.zaglavlje { background: #fff; padding: 16px 20px; border-bottom: 1px solid #e2e8f0; text-align: center; }
.firma-naziv { font-size: 16px; font-weight: 700; color: #0f172a; }
.firma-info { font-size: 12px; color: #64748b; margin-top: 4px; line-height: 1.6; }
/* kartica */
.kartica { background: #fff; margin: 12px 12px 0; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); overflow: hidden; }
.kartica-naslov { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.7px; color: #64748b; padding: 12px 16px 8px; border-bottom: 1px solid #f1f5f9; }
/* red podataka */
.red { display: flex; justify-content: space-between; align-items: flex-start; padding: 9px 16px; border-bottom: 1px solid #f1f5f9; gap: 12px; }
.red:last-child { border-bottom: none; }
.red-labela { font-size: 12px; color: #64748b; }
.red-vrednost { font-size: 13px; color: #0f172a; font-weight: 500; text-align: right; }
.red-vrednost.mono { font-family: monospace; font-size: 12px; word-break: break-all; }
/* stavke */
.stavke-zaglavlje { display: flex; justify-content: space-between; padding: 7px 16px; background: #f8fafc; font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; }
.stavka { display: flex; justify-content: space-between; align-items: flex-start; padding: 8px 16px; border-bottom: 1px solid #f1f5f9; gap: 8px; }
.stavka:last-child { border-bottom: none; }
.stavka-naziv { font-size: 13px; color: #1e293b; flex: 1; }
.stavka-kolicina { font-size: 12px; color: #64748b; text-align: center; min-width: 40px; }
.stavka-iznos { font-size: 13px; color: #0f172a; font-weight: 500; text-align: right; min-width: 80px; }
/* PDV tabela */
.pdv-red { display: flex; justify-content: space-between; padding: 7px 16px; border-bottom: 1px solid #f1f5f9; font-size: 12px; color: #374151; }
.pdv-red:last-child { border-bottom: none; }
.pdv-label { color: #64748b; }
/* ukupno */
.ukupno-blok { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; background: #0f172a; }
.ukupno-labela { font-size: 13px; color: #94a3b8; }
.ukupno-iznos { font-size: 22px; font-weight: 700; color: #fff; }
/* načini plaćanja */
.placanje-red { display: flex; justify-content: space-between; padding: 7px 16px; border-bottom: 1px solid #f1f5f9; font-size: 13px; }
.placanje-red:last-child { border-bottom: none; }
/* tip računa bedž */
.tip-bedz { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 11px; font-weight: 600; }
.tip-fiskalni { background: #dcfce7; color: #166534; }
.tip-nefiskalni { background: #fef3c7; color: #92400e; }
/* podnožje */
.podnozje { text-align: center; padding: 20px 16px 8px; font-size: 11px; color: #94a3b8; line-height: 1.6; }
.podnozje a { color: #64748b; text-decoration: none; }
</style>
</head>
<body>
<div class="omotac">
{{if .Greska}}
<div class="baner greska">
<div class="baner-ikona"></div>
<div class="baner-tekst">Greška pri čitanju računa</div>
<div class="baner-podnaslov">{{.Greska}}</div>
</div>
{{else}}
{{if .JeFiskalni}}
<div class="baner ok">
<div class="baner-ikona"></div>
<div class="baner-tekst">Račun je verifikovan</div>
<div class="baner-podnaslov">Fiskalni račun je evidentiran u sistemu</div>
</div>
{{else}}
<div class="baner" style="background:#f59e0b;color:#1c1917;">
<div class="baner-ikona"></div>
<div class="baner-tekst">Ovo nije fiskalni račun</div>
<div class="baner-podnaslov">{{.Podaci.InvoiceType}}</div>
</div>
{{end}}
{{with .Podaci}}
<!-- firma -->
<div class="zaglavlje">
<div class="firma-naziv">{{.Company}}</div>
<div class="firma-info">
{{if .Store}}{{.Store}}<br>{{end}}
{{if .Address}}{{.Address}}{{if .City}}, {{.City}}{{end}}<br>{{end}}
PIB: {{.TIN}}
</div>
</div>
<!-- osnovno -->
<div class="kartica">
<div class="kartica-naslov">Podaci o računu</div>
<div class="red">
<span class="red-labela">Broj računa</span>
<span class="red-vrednost mono">{{.InvoiceNumber}}</span>
</div>
<div class="red">
<span class="red-labela">Redni broj</span>
<span class="red-vrednost mono">{{.InvoiceCounter}}</span>
</div>
<div class="red">
<span class="red-labela">Datum i vreme</span>
<span class="red-vrednost">{{.DateTime}}</span>
</div>
{{if .Cashier}}
<div class="red">
<span class="red-labela">Kasir</span>
<span class="red-vrednost">{{.Cashier}}</span>
</div>
{{end}}
{{if .BuyerID}}
<div class="red">
<span class="red-labela">ID kupca</span>
<span class="red-vrednost mono">{{.BuyerID}}</span>
</div>
{{end}}
<div class="red">
<span class="red-labela">Tip</span>
<span class="red-vrednost">
{{if eq .InvoiceType "Normal"}}
<span class="tip-bedz tip-fiskalni">Promet</span>
{{else if eq .InvoiceType "Advance"}}
<span class="tip-bedz tip-fiskalni">Avans</span>
{{else if eq .InvoiceType "Copy"}}
<span class="tip-bedz tip-nefiskalni">Kopija</span>
{{else if eq .InvoiceType "Training"}}
<span class="tip-bedz tip-nefiskalni">Obuka</span>
{{else if eq .InvoiceType "Proforma"}}
<span class="tip-bedz tip-nefiskalni">Predračun</span>
{{else}}
<span class="tip-bedz tip-nefiskalni">{{.InvoiceType}}</span>
{{end}}
{{if eq .TransactionType "Refund"}}
&nbsp;<span class="tip-bedz tip-nefiskalni">Refundacija</span>
{{end}}
</span>
</div>
</div>
<!-- stavke -->
{{if .Items}}
<div class="kartica">
<div class="kartica-naslov">Stavke</div>
<div class="stavke-zaglavlje">
<span>Naziv</span>
<span>Kol.</span>
<span style="text-align:right;">Iznos</span>
</div>
{{range .Items}}
<div class="stavka">
<span class="stavka-naziv">{{.Name}}</span>
<span class="stavka-kolicina">{{printf "%.0f" .Quantity}}</span>
<span class="stavka-iznos">{{dinari .TotalAmount}}</span>
</div>
{{end}}
<div class="ukupno-blok">
<span class="ukupno-labela">Ukupno za plaćanje</span>
<span class="ukupno-iznos">{{dinari .TotalAmount}} din</span>
</div>
</div>
{{else}}
<div class="kartica">
<div class="ukupno-blok">
<span class="ukupno-labela">Ukupno za plaćanje</span>
<span class="ukupno-iznos">{{dinari .TotalAmount}} din</span>
</div>
</div>
{{end}}
<!-- načini plaćanja -->
{{if .Payments}}
<div class="kartica">
<div class="kartica-naslov">Plaćanje</div>
{{range .Payments}}
<div class="placanje-red">
<span style="color:#374151;">
{{if eq .Type "Cash"}}Gotovina
{{else if eq .Type "Card"}}Kartica
{{else if eq .Type "Check"}}Ček
{{else if eq .Type "WireTransfer"}}Prenos
{{else if eq .Type "Voucher"}}Vaučer
{{else if eq .Type "MobileMoney"}}Mobilno plaćanje
{{else}}{{.Type}}{{end}}
</span>
<span style="font-weight:600;">{{dinari .Amount}} din</span>
</div>
{{end}}
</div>
{{end}}
<!-- PDV -->
{{if .TaxItems}}
<div class="kartica">
<div class="kartica-naslov">Porez</div>
{{range .TaxItems}}
<div class="pdv-red">
<span class="pdv-label">{{if .CategoryName}}{{.CategoryName}} ({{.Label}}){{else}}{{.Label}}{{end}} {{printf "%.0f" .Rate}}%</span>
<span>Osnovica: {{dinari .Base}}</span>
<span style="font-weight:600;">PDV: {{dinari .Amount}} din</span>
</div>
{{end}}
</div>
{{end}}
{{end}}{{/* with .Podaci */}}
<div class="podnozje">
Fiskalizacija — NTech sistem<br>
<span style="font-size:10px;color:#cbd5e1;">Poreski identifikacioni broj se proverava kod Poreske uprave RS</span>
</div>
{{end}}{{/* if .Greska */}}
</div>
</body>
</html>
@@ -25,6 +25,24 @@
<div class="pomocni-tekst" style="margin-top:4px;">Trenutno podržan samo Teron L-PFR.</div>
</div>
<div>
<label for="fiskalni_pismo" class="polje-labela">Pismo fiskalnog računa</label>
<select id="fiskalni_pismo" name="fiskalni_pismo"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;">
<option value="latin" {{if ne .FiskalPismo "cyrillic"}}selected{{end}}>Latinica</option>
<option value="cyrillic" {{if eq .FiskalPismo "cyrillic"}}selected{{end}}>Ćirilica</option>
</select>
<div class="pomocni-tekst" style="margin-top:4px;">Pismo kojim Fisk štampa tekst računa. Stupi na snagu posle restarta Fisk servera. Env var <code>FISKALNI_PISMO</code> ima prednost.</div>
</div>
<div>
<label for="pfr_kasir" class="polje-labela">Kasir (ime na računu)</label>
<input type="text" id="pfr_kasir" name="pfr_kasir" value="{{.PfrKasir}}"
placeholder="npr. Petar Petrović"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;box-sizing:border-box;">
<div class="pomocni-tekst" style="margin-top:4px;">Ime koje se štampa u redu „Kasir" na fiskalnom računu. Prazno = prikazuje se „NTech".</div>
</div>
<div>
<label for="pfr_url" class="polje-labela">URL fiskalnog servera</label>
<input type="text" id="pfr_url" name="pfr_url" value="{{.PfrUrl}}"
@@ -60,6 +78,103 @@
</div>
<!-- Kartica emulator -->
<div class="kartica animiraj">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/><path d="M7 15h.01"/><path d="M11 15h2"/></svg>
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Kartica emulator (BE)</span>
</div>
<div class="pomocni-tekst" style="margin-bottom:16px;">
Bezbednosni element — drži PIN, limite i brojače. Radi kao goroutine unutar NTech-a (port 4567).
Promene PIN-a i limita stupaju na snagu tek posle restarta servera.
</div>
<form method="POST" action="/podesavanja/sacuvaj">
<input type="hidden" name="_next" value="/admin/podesavanja/fiskalizacija">
<div style="display:flex;flex-direction:column;gap:16px;max-width:480px;">
<div>
<label for="be_enabled" class="polje-labela">Kartica emulator</label>
<select id="be_enabled" name="be_enabled"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;">
<option value="true" {{if ne .BeEnabled "false"}}selected{{end}}>Uključen (mock kartica)</option>
<option value="false" {{if eq .BeEnabled "false"}}selected{{end}}>Isključen (pravi Teron uređaj)</option>
</select>
<div class="pomocni-tekst" style="margin-top:4px;">Isključi kad koristiš pravi Teron/fizički L-PFR. Stupi na snagu posle restarta servera. Env var <code>BE_ENABLED=false</code> ima prednost.</div>
</div>
<div>
<label for="be_pin" class="polje-labela">PIN kartice</label>
<input type="text" id="be_pin" name="be_pin" value="{{.BePin}}"
maxlength="8" placeholder="1234"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;box-sizing:border-box;font-family:monospace;">
<div class="pomocni-tekst" style="margin-top:4px;">PIN koji Fisk šalje pri verify_pin komandi. Podrazumevano: <code>1234</code>. Env var <code>BE_PIN</code> ima prednost.</div>
</div>
<div>
<label for="be_limit" class="polje-labela">Limit iščitavanja (din)</label>
<input type="number" id="be_limit" name="be_limit" value="{{.BeLimit}}"
min="1000" step="1000" placeholder="500000"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;box-sizing:border-box;">
<div class="pomocni-tekst" style="margin-top:4px;">Maksimalni neisčitani promet pre blokade kartice. Podrazumevano: <code>500 000</code>. Env var <code>BE_LIMIT</code> ima prednost.</div>
</div>
<div>
<label for="verify_host" class="polje-labela">Domen za verifikacioni QR link</label>
<input type="text" id="verify_host" name="verify_host" value="{{.VerifyHost}}"
placeholder="ntech.moja-firma.rs:3000"
style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;box-sizing:border-box;">
<div class="pomocni-tekst" style="margin-top:4px;">
Npr. <code>192.168.1.10:3000</code> ili <code>ntech.firma.rs</code>.
Prazno = QR vodi na <code>sandbox.suf.purs.gov.rs</code>.
Env var <code>VERIFY_HOST</code> ima prednost nad ovim poljem.
Fisk čita ovu vrednost pri pokretanju.
</div>
</div>
<div>
<button type="submit"
style="padding:9px 18px;background:var(--sb-akcent);border:none;border-radius:8px;color:#fff;font-size:13px;font-weight:500;cursor:pointer;">
Sačuvaj
</button>
</div>
</div>
</form>
<!-- Status kartice (live) -->
<div style="margin-top:20px;padding-top:16px;border-top:0.5px solid var(--ivica);">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;gap:8px;flex-wrap:wrap;">
<span style="font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;color:var(--tekst-sporedni);">Status kartice</span>
<div style="display:flex;gap:8px;">
<button type="button"
hx-post="/podesavanja/fiskalizacija/be-reset-audit"
hx-target="#be-status-panel"
hx-swap="innerHTML"
hx-confirm="Simulirati Proof of Audit? Ovo će resetovati neisčitani iznos na 0."
style="padding:5px 12px;background:transparent;border:0.5px solid var(--ivica);border-radius:6px;color:var(--tekst-sporedni);font-size:12px;cursor:pointer;">
Resetuj limit
</button>
<button type="button"
hx-get="/podesavanja/fiskalizacija/be-status"
hx-target="#be-status-panel"
hx-swap="innerHTML"
style="padding:5px 12px;background:transparent;border:0.5px solid var(--ivica);border-radius:6px;color:var(--tekst-sporedni);font-size:12px;cursor:pointer;">
Osveži
</button>
</div>
</div>
<div id="be-status-panel"
hx-get="/podesavanja/fiskalizacija/be-status"
hx-trigger="load"
hx-swap="innerHTML">
<span style="font-size:12px;color:var(--tekst-sporedni);">Učitavanje...</span>
</div>
</div>
</div>
</div>
<style>
+56 -3
View File
@@ -149,7 +149,7 @@
</div>
<div style="margin-top:10px;padding-top:10px;border-top:0.5px solid var(--ivica);">
<label class="polje-labela">Primljeno (din)</label>
<input type="number" id="primljeno" name="primljeno" min="0" step="0.01" value="0" style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;" oninput="var t=document.getElementById('za-naplatu-iznos').textContent;var zn=t?parseFloat(t.replace(/\./g,'').replace(',','.').replace(/[^0-9.]/g,''))||0:0;var p=parseFloat(this.value)||0;var k=p-zn;document.getElementById('kusur').textContent=(k>=0?k.toFixed(2):'0.00')+' din';document.getElementById('kusur-blok').style.display=k>=0?'flex':'none'">
<input type="number" id="primljeno" name="primljeno" min="0" step="0.01" placeholder="Unesite primljeni iznos" style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:14px;box-sizing:border-box;" oninput="ntechPrimljenoUpdate(this)">
</div>
<div id="kusur-blok" style="display:none;justify-content:space-between;align-items:center;padding:8px 12px;background:color-mix(in srgb,var(--uspeh) 10%,transparent);border:0.5px solid var(--uspeh);border-radius:8px;">
<span style="color:var(--uspeh);font-weight:500;">Kusur (vratiti)</span>
@@ -161,14 +161,67 @@
<input type="hidden" name="naplaceno" value="{{printf "%.2f" .PreostaloSve}}">
<div style="margin-bottom:10px;">
<label class="polje-labela">Način plaćanja</label>
<select name="nacin_placanja" style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:13px;">
<select name="nacin_placanja" id="nacin-placanja-sel" style="width:100%;padding:8px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-glavni);font-size:13px;" onchange="ntechNacinPlacanjaBroj(this)">
<option value="Gotovina">Gotovina</option>
<option value="Kartica">Kartica</option>
<option value="Virman">Virman</option>
</select>
</div>
<button type="submit" class="btn-primarno" style="width:100%;">Naplati i preuzmi</button>
<label style="display:flex;align-items:center;gap:10px;padding:10px 12px;background:var(--pozadina);border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;margin-bottom:10px;">
<input type="checkbox" id="prikazi-racun" name="prikazi_racun" value="1" checked
style="width:16px;height:16px;accent-color:var(--sb-akcent);cursor:pointer;flex-shrink:0;">
<span style="font-size:13px;color:var(--tekst-glavni);">Prikaži fiskalni račun</span>
</label>
<button type="submit" id="btn-naplati" class="btn-primarno" style="width:100%;opacity:0.4;cursor:not-allowed;" disabled>Naplati i preuzmi</button>
</form>
<script>
(function(){
function zaNaplatu() {
var t = document.getElementById('za-naplatu-iznos');
return t ? parseFloat(t.textContent.replace(/\./g,'').replace(',','.').replace(/[^0-9.]/g,'')) || 0 : 0;
}
window.ntechPrimljenoUpdate = function(inp) {
var zn = zaNaplatu();
var p = parseFloat(inp.value) || 0;
var k = p - zn;
var kusurBlok = document.getElementById('kusur-blok');
if (k >= 0 && inp.value !== '') {
document.getElementById('kusur').textContent = k.toFixed(2).replace('.',',') + ' din';
kusurBlok.style.display = 'flex';
} else {
kusurBlok.style.display = 'none';
}
var btn = document.getElementById('btn-naplati');
var ok = inp.value !== '' && p >= zn;
btn.disabled = !ok;
btn.style.opacity = ok ? '1' : '0.4';
btn.style.cursor = ok ? 'pointer' : 'not-allowed';
};
window.ntechNacinPlacanjaBroj = function(sel) {
if (sel.value !== 'Gotovina') {
var inp = document.getElementById('primljeno');
if (inp && inp.value === '') {
inp.value = zaNaplatu().toFixed(2);
ntechPrimljenoUpdate(inp);
}
}
};
var dlg = document.currentScript.closest('dialog');
var f = dlg && dlg.querySelector('form[method="POST"]');
if (!f) return;
f.addEventListener('submit', function(){
var cb = f.querySelector('#prikazi-racun');
if (!cb || !cb.checked) return;
var sadrzaj = document.getElementById('sadrzaj');
if (!sadrzaj) return;
var observer = new MutationObserver(function(){
observer.disconnect();
window.open('/servis/{{.Nalog.ID}}/fiskalni-racun', '_blank');
});
observer.observe(sadrzaj.parentElement, {childList: true});
});
})();
</script>
</div>
</dialog>
{{end}}