Tak som si vyskúšal napísať malú utilitu Faktura v1 pomocou jazyka Rust a systému Tauri v2, užívajte v zdraví ;)

Tak som si vyskúšal napísať malú utilitu Faktura v1 pomocou jazyka Rust a systému Tauri v2, užívajte v zdraví ;)

https://hrubos.tech/blogy/content/images/20260315233355-fakturav1-running-program.png

AppImage a Windows64 exe stiahnete zadarmo na: https://hrubos.tech/repository/faktura1-release-appimage-win64.zip

Webová verzia beží na: https://projects.hrubos.tech/ Prepísal som ju do Tauri v2 :)

Takto vyzerá generovaná faktúrka:

faktura generovana programom faktura v1

fakturav1 running on windows11

https://hrubos.tech/blogy/content/images/20260315233530-Sn%C3%ADmka%20obrazovky%202026-03-15%20232322.png

faktura generovana windows11

https://hrubos.tech/blogy/content/images/20260315233623-Sn%C3%ADmka%20obrazovky%202026-03-15%20232421.png

<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<title>Faktúra PDF</title>
<script src="/jspdf.umd.min.js"></script>
<script src="/html2canvas.min.js"></script>
<script src="/index.js" defer></script>
<style>
body{
    font-family: DejaVu Sans, sans-serif;
    margin:50px;
    color:#333;
    font-size:18px;
    line-height:1.6;
}
.header{
    display:flex;
    justify-content:space-between;
    margin-bottom:50px;
}
.company{
    font-size:24px;
    font-weight:bold;
    margin:10px 0;
}
.invoice-title{
    font-size:36px;
    font-weight:bold;
    margin:10px 0;
}
.meta{
    margin:10px 0;
}
.table{
    width:100%;
    border-collapse:collapse;
    margin-top:40px;
}
.table th{
    background:#f2f2f2;
    padding:12px;
    text-align:left;
    border-bottom:2px solid #ddd;
}
.table td{
    padding:12px;
    border-bottom:1px solid #eee;
}
.total{
    margin-top:40px;
    width:350px;
    float:right;
}
.total td{
    padding:4px;
}
.grand{
    font-size:20px;
    font-weight:bold;
    margin:5px 0;
}
.footer{
    margin-top:120px;
    text-align:center;
    font-size:14px;
    color:#777;
}
input { 
    width: 100%; 
    padding:5px;
    margin:8px 0;
    border:none;
    font-size:16px;
}
.item { 
    display: flex;
    gap:10px;
    margin:10px 0;
}
button { 
    margin-top:15px;
    padding:10px 16px;
    cursor:pointer;
    font-size:16px;
}
</style>
</head>
<body>

<div id="invoice-form">

<div class="header">
  <div>
    <div class="company"><input type="text" id="company-name" value="Firma s.r.o."></div>
    <div><input type="text" id="company-address" value="Hlavná 123"></div>
    <div><input type="text" id="company-city" value="Bratislava"></div>
  </div>
  <div>
    <div class="invoice-title">FAKTÚRA</div>
    <div class="meta">
      Faktúra č.: <input type="text" id="invoice-number" value="2026-001"><br>
      Dátum vystavenia: <input type="date" id="invoice-date" value="2026-03-15"><br>
      Do kedy splatná: <input type="date" id="invoice-due" value="2026-03-22"><br>
      DPH (%): <input type="number" id="vat-rate" value="23">
    </div>
  </div>
</div>

<div>
<strong>Účtovaná komu:</strong><br>
<input type="text" id="customer-name" value="Zákazník s.r.o."><br>
<input type="text" id="customer-address" value="Vedľajšia 45"><br>
<input type="text" id="customer-city" value="Košice">
</div>

<h3>Položky</h3>
<div id="items">
  <div class="item">
    <input type="text" placeholder="Popis" value="Programovanie">
    <input type="number" placeholder="Množ." value="10">
    <input type="number" placeholder="Cena" value="50">
  </div>
</div>
<button id="add-item">Pridať položku</button><br><br>

<button id="save-json">Uložiť do JSON</button>
<button id="load-json">Načítať z JSON</button><br><br>

<button id="generate-pdf">Generovať PDF</button>

</div>

<script src="index.js"></script>
</body>
</html>
document.addEventListener('DOMContentLoaded', function() {

  function updateTotals() {
    const items = Array.from(document.querySelectorAll('.item'));
    let subtotal = 0;
    items.forEach(item => {
      const qty = parseFloat(item.children[1].value) || 0;
      const price = parseFloat(item.children[2].value) || 0;
      subtotal += qty * price;
    });

    const vatRate = parseFloat(document.getElementById('vat-rate').value) || 23;
    const vat = subtotal * (vatRate / 100);
    const total = subtotal + vat;

    document.querySelector('.total')?.remove();

    const totalsHtml = `
      <table class="table total">
        <tr><td>Celkom bez DPH:</td><td>${subtotal.toFixed(2)} €</td></tr>
        <tr><td>DPH ${vatRate}%:</td><td>${vat.toFixed(2)} €</td></tr>
        <tr class="grand"><td><strong>SPOLU:</strong></td><td><strong>${total.toFixed(2)} €</strong></td></tr>
      </table>
    `;
    document.getElementById('add-item').insertAdjacentHTML('afterend', totalsHtml);
  }

  // Add item
  document.getElementById('add-item').onclick = function() {
    const div = document.createElement('div');
    div.className = 'item';
    div.innerHTML = `
      <input type="text" placeholder="Popis">
      <input type="number" placeholder="Množ." step="0.1" min="0">
      <input type="number" placeholder="Cena" step="0.01" min="0">
    `;
    document.getElementById('items').appendChild(div);
    updateTotals();
  };

  // Save JSON (browser download)
  document.getElementById('save-json').onclick = function() {
    const data = {
      company: document.getElementById('company-name').value,
      invoiceNumber: document.getElementById('invoice-number').value,
      items: Array.from(document.querySelectorAll('.item')).map(i => ({
        name: i.children[0].value,
        qty: parseFloat(i.children[1].value) || 0,
        price: parseFloat(i.children[2].value) || 0
      }))
    };

    const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `faktura-${data.invoiceNumber}.json`;
    a.click();
    URL.revokeObjectURL(url);
    alert('JSON stiahnutý!');
  };




  // Načítať JSON - vlož PO save-json funkcii
document.getElementById('load-json').onclick = function() {
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json';

  input.onchange = function(e) {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = function(e) {
      try {
        const data = JSON.parse(e.target.result);

        // Naplň pole company a číslo faktúry
        if (data.company) document.getElementById('company-name').value = data.company;
        if (data.invoiceNumber) document.getElementById('invoice-number').value = data.invoiceNumber;

        // Vyčisti a naplň položky
        const itemsDiv = document.getElementById('items');
        itemsDiv.innerHTML = '';
        (data.items || []).forEach(item => {
          const div = document.createElement('div');
          div.className = 'item';
          div.innerHTML = `
            <input type="text" placeholder="Popis" value="${item.name || ''}">
            <input type="number" placeholder="Množ." step="0.1" value="${item.qty || 0}">
            <input type="number" placeholder="Cena" step="0.01" value="${item.price || 0}">
          `;
          itemsDiv.appendChild(div);
        });

        updateTotals();
        alert('✅ JSON načítaný!');
      } catch (err) {
        alert('❌ Chybný JSON súbor!');
      }
    };
    reader.readAsText(file);
  };
  input.click();
};



  // PDF (PNG export)
  document.getElementById('generate-pdf').onclick = function() {
    html2canvas(document.getElementById('invoice-form'), { 
      scale: 2,
      useCORS: true,
      backgroundColor: '#ffffff'
    }).then(canvas => {
      const inputs = document.querySelectorAll('input, button');
      inputs.forEach(el => el.style.display = 'none');

      canvas.toBlob(blob => {
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `faktura-${document.getElementById('invoice-number').value}.png`;
        a.click();
        URL.revokeObjectURL(url);

        inputs.forEach(el => el.style.display = '');
        alert('Faktúra stiahnutá ako PNG!');
      });
    });
  };

  // Real-time calculation
  document.addEventListener('input', updateTotals);
  updateTotals();
});


Author: AarNoma

The first Slovak cyborg 1 system

Comments “Tak som si vyskúšal napísať malú utilitu Faktura v1 pomocou jazyka Rust a systému Tauri v2, užívajte v zdraví ;)”