Kufrik/app/UI/FakturaEdit/edit.latte

217 lines
10 KiB
Plaintext

{block content}
<!-- Načtení SortableJS pro Drag & Drop -->
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.2/Sortable.min.js"></script>
<div class="container-fluid">
<div class="content-card my-3">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="h4 mb-0">
<i class="bi {if $isEdit}bi-pencil-square{else}bi-file-earmark-plus-fill{/if} me-2"></i>
{if $isEdit}Úprava faktury{else}Nová faktura{/if}
</h2>
<a n:href="Faktura:default" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left me-1"></i>Zpět na seznam
</a>
</div>
<form n:name="fakturaForm" id="faktura-form" class="row g-3">
<div n:if="$form->hasErrors()" class="col-12">
<div class="alert alert-danger mb-0">
<ul class="mb-0">
<li n:foreach="$form->errors as $error">{$error}</li>
</ul>
</div>
</div>
<!-- Hlavička Faktury -->
<div class="col-md-6">
<label n:name="ZAKAZNIK_ID" class="form-label fw-bold">Odběratel *</label>
<select n:name="ZAKAZNIK_ID" class="form-select"></select>
</div>
<div class="col-md-6">
<label n:name="CISLO" class="form-label fw-bold">Číslo faktury *</label>
<input n:name="CISLO" class="form-control">
</div>
<div class="col-md-4">
<label n:name="DATUM_VYSTAVENI" class="form-label">Datum vystavení</label>
<input n:name="DATUM_VYSTAVENI" class="form-control">
</div>
<div class="col-md-4">
<label n:name="DATUM_SPLATNOSTI" class="form-label">Datum splatnosti</label>
<input n:name="DATUM_SPLATNOSTI" class="form-control">
</div>
<div class="col-md-4">
<label n:name="STAV" class="form-label">Stav úhrady</label>
<select n:name="STAV" class="form-select"></select>
</div>
<hr class="my-4">
<!-- Položky Faktury -->
<div class="col-12">
<h5 class="mb-3"><i class="bi bi-list-check me-2"></i>Položky faktury</h5>
<div class="table-responsive">
<table class="table table-bordered align-middle" id="items-table">
<thead class="table-light">
<tr>
<th style="width: 40px;" class="text-center"></th> <!-- Sloupec pro Drag Handle -->
<th>Název položky / služby</th>
<th style="width: 100px;">Počet</th>
<th style="width: 90px;">Jedn.</th>
<th style="width: 130px;">Cena/Jedn.</th>
<th style="width: 100px;">Sleva %</th>
<th style="width: 130px;" class="text-end">Celkem</th>
<th style="width: 50px;"></th>
</tr>
</thead>
<tbody id="items-body">
{foreach $polozky as $index => $p}
<tr class="item-row">
<td class="text-center align-middle drag-handle" style="cursor: grab;">
<i class="bi bi-grip-vertical text-muted fs-5"></i>
</td>
<td><input type="text" name="polozky[{$index}][NAZEV]" value="{$p->NAZEV}" class="form-control item-nazev" required></td>
<td><input type="number" step="0.01" name="polozky[{$index}][POCET]" value="{$p->POCET}" class="form-control item-pocet text-end" required></td>
<td><input type="text" name="polozky[{$index}][JEDNOTKA]" value="{$p->JEDNOTKA}" class="form-control"></td>
<td><input type="number" step="0.01" name="polozky[{$index}][CENA_JEDNOTKA]" value="{$p->CENA_JEDNOTKA}" class="form-control item-cena text-end" required></td>
<td><input type="number" step="0.1" name="polozky[{$index}][SLEVA]" value="{$p->SLEVA}" class="form-control item-sleva text-end"></td>
<td class="text-end fw-bold item-celkem-text">{$p->CENA|number:2, ',', ' '} CZK</td>
<td class="text-center">
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
</td>
</tr>
{/foreach}
</tbody>
<tfoot>
<tr>
<td colspan="6" class="text-end fw-bold fs-5">Celková částka:</td>
<td class="text-end fw-bold fs-5 text-primary" id="total-sum">0,00 CZK</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<button type="button" class="btn btn-outline-success btn-sm" id="btn-add-item">
<i class="bi bi-plus-circle me-1"></i>Přidat položku
</button>
</div>
<hr class="my-4">
<div class="col-12">
<label n:name="CINNOSTI" class="form-label fw-bold">Činnosti / Popis plnění</label>
<textarea n:name="CINNOSTI" class="form-control" rows="3" placeholder="Rozsah vykonaných prací..."></textarea>
</div>
<div class="col-12 mt-4">
<button n:name="save" class="btn btn-primary me-2">
<i class="bi bi-check-lg me-1"></i>Uložit fakturu
</button>
<a n:href="Faktura:default" class="btn btn-outline-secondary">Zrušit</a>
</div>
</form>
</div>
</div>
{syntax off}
<script>
document.addEventListener('DOMContentLoaded', () => {
let rowIndex = document.querySelectorAll('.item-row').length;
const tbody = document.getElementById('items-body');
const btnAdd = document.getElementById('btn-add-item');
// 1. Inicializace SortableJS na <tbody>
if (typeof Sortable !== 'undefined') {
new Sortable(tbody, {
handle: '.drag-handle', // Přetahovat lze uchopením za ikonu
animation: 150,
ghostClass: 'table-active', // Zvýraznění přetahovaného řádku
onEnd: function () {
reindexRows();
calculateTotals();
}
});
}
// 2. Přereindexování name atributů podle nového pořadí řádků v DOMu
function reindexRows() {
document.querySelectorAll('.item-row').forEach((row, index) => {
row.querySelectorAll('input').forEach(input => {
const name = input.getAttribute('name');
if (name) {
input.setAttribute('name', name.replace(/polozky\[\d+\]/, `polozky[${index}]`));
}
});
});
}
// 3. Výpočet součtů
function calculateTotals() {
let grandTotal = 0;
document.querySelectorAll('.item-row').forEach(row => {
const pocet = parseFloat(row.querySelector('.item-pocet').value) || 0;
const cena = parseFloat(row.querySelector('.item-cena').value) || 0;
const sleva = parseFloat(row.querySelector('.item-sleva').value) || 0;
const celkem = (pocet * cena) * (1 - (sleva / 100));
grandTotal += celkem;
row.querySelector('.item-celkem-text').textContent = celkem.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
});
document.getElementById('total-sum').textContent = grandTotal.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
}
// Přidání nového řádku
btnAdd.addEventListener('click', () => {
const tr = document.createElement('tr');
tr.className = 'item-row';
tr.innerHTML = `
<td class="text-center align-middle drag-handle" style="cursor: grab;">
<i class="bi bi-grip-vertical text-muted fs-5"></i>
</td>
<td><input type="text" name="polozky[${rowIndex}][NAZEV]" class="form-control item-nazev" placeholder="Popis práce / zboží" required></td>
<td><input type="number" step="0.01" name="polozky[${rowIndex}][POCET]" value="1" class="form-control item-pocet text-end" required></td>
<td><input type="text" name="polozky[${rowIndex}][JEDNOTKA]" value="ks" class="form-control"></td>
<td><input type="number" step="0.01" name="polozky[${rowIndex}][CENA_JEDNOTKA]" value="0" class="form-control item-cena text-end" required></td>
<td><input type="number" step="0.1" name="polozky[${rowIndex}][SLEVA]" value="0" class="form-control item-sleva text-end"></td>
<td class="text-end fw-bold item-celkem-text">0,00 CZK</td>
<td class="text-center">
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
</td>
`;
tbody.appendChild(tr);
rowIndex++;
reindexRows();
calculateTotals();
});
// Event delegation pro smazání a přepočet
tbody.addEventListener('click', (e) => {
if (e.target.closest('.btn-remove-row')) {
e.target.closest('.item-row').remove();
reindexRows();
calculateTotals();
}
});
tbody.addEventListener('input', (e) => {
if (e.target.matches('.item-pocet, .item-cena, .item-sleva')) {
calculateTotals();
}
});
if (document.querySelectorAll('.item-row').length === 0) {
btnAdd.click();
} else {
calculateTotals();
}
});
</script>
{/syntax}