Přepočítávání a GUI faktury.
parent
3257006a02
commit
e1da2619a8
|
|
@ -69,7 +69,7 @@
|
||||||
<th style="width: 90px;">Jedn.</th>
|
<th style="width: 90px;">Jedn.</th>
|
||||||
<th style="width: 130px;">Cena/Jedn.</th>
|
<th style="width: 130px;">Cena/Jedn.</th>
|
||||||
<th style="width: 100px;">Sleva %</th>
|
<th style="width: 100px;">Sleva %</th>
|
||||||
<th style="width: 130px;" class="text-end">Celkem</th>
|
<th style="width: 170px;" class="text-end">Celkem</th>
|
||||||
<th style="width: 50px;"></th>
|
<th style="width: 50px;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -80,11 +80,11 @@
|
||||||
<i class="bi bi-grip-vertical text-muted fs-5"></i>
|
<i class="bi bi-grip-vertical text-muted fs-5"></i>
|
||||||
</td>
|
</td>
|
||||||
<td data-label="Název"><input type="text" name="polozky[{$index}][NAZEV]" value="{$p->NAZEV}" class="form-control item-nazev" placeholder="Začněte psát název práce nebo zboží" required autocomplete="off"></td>
|
<td data-label="Název"><input type="text" name="polozky[{$index}][NAZEV]" value="{$p->NAZEV}" class="form-control item-nazev" placeholder="Začněte psát název práce nebo zboží" required autocomplete="off"></td>
|
||||||
<td data-label="Počet"><input type="number" step="0.01" name="polozky[{$index}][POCET]" value="{$p->POCET}" class="form-control item-pocet text-end" required></td>
|
<td data-label="Počet"><input type="number" step="any" name="polozky[{$index}][POCET]" value="{$p->POCET}" class="form-control item-pocet text-end" required></td>
|
||||||
<td data-label="Jedn."><input type="text" name="polozky[{$index}][JEDNOTKA]" value="{$p->JEDNOTKA}" class="form-control"></td>
|
<td data-label="Jedn."><input type="text" name="polozky[{$index}][JEDNOTKA]" value="{$p->JEDNOTKA}" class="form-control"></td>
|
||||||
<td data-label="Cena/Jedn."><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 data-label="Cena/Jedn."><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 data-label="Sleva %"><input type="number" step="0.1" name="polozky[{$index}][SLEVA]" value="{$p->SLEVA}" class="form-control item-sleva text-end"></td>
|
<td data-label="Sleva %"><input type="number" step="0.1" name="polozky[{$index}][SLEVA]" value="{$p->SLEVA}" class="form-control item-sleva text-end"></td>
|
||||||
<td data-label="Celkem" class="text-end fw-bold item-celkem-text">{$p->CENA|number:2, ',', ' '} CZK</td>
|
<td data-label="Celkem"><input type="number" step="0.01" value="{$p->CENA}" class="form-control item-celkem text-end fw-bold" title="Úprava přepočítá počet"></td>
|
||||||
<td class="text-center cell-actions">
|
<td class="text-center cell-actions">
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
|
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -94,8 +94,7 @@
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-end fw-bold fs-5 cell-span">Celková částka:</td>
|
<td colspan="6" class="text-end fw-bold fs-5 cell-span">Celková částka:</td>
|
||||||
<td class="text-end fw-bold fs-5 text-primary" id="total-sum">0,00 CZK</td>
|
<td colspan="2" class="text-end fw-bold fs-5 text-primary text-nowrap" id="total-sum">0,00 CZK</td>
|
||||||
<td class="cell-actions"></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -244,24 +243,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Výpočet součtů
|
// 3. Výpočet součtů (celkem ← počet × cena × (1 − sleva))
|
||||||
|
function roundMoney(value) {
|
||||||
|
return Math.round((value + Number.EPSILON) * 100) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function roundPocet(value) {
|
||||||
|
return Math.round((value + Number.EPSILON) * 10000) / 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowCelkem(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;
|
||||||
|
return (pocet * cena) * (1 - (sleva / 100));
|
||||||
|
}
|
||||||
|
|
||||||
function calculateTotals() {
|
function calculateTotals() {
|
||||||
let grandTotal = 0;
|
let grandTotal = 0;
|
||||||
|
|
||||||
document.querySelectorAll('.item-row').forEach(row => {
|
document.querySelectorAll('.item-row').forEach(row => {
|
||||||
const pocet = parseFloat(row.querySelector('.item-pocet').value) || 0;
|
const celkem = rowCelkem(row);
|
||||||
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;
|
grandTotal += celkem;
|
||||||
|
|
||||||
row.querySelector('.item-celkem-text').textContent = celkem.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
|
const celkemInput = row.querySelector('.item-celkem');
|
||||||
|
if (celkemInput && document.activeElement !== celkemInput) {
|
||||||
|
celkemInput.value = roundMoney(celkem).toFixed(2);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('total-sum').textContent = grandTotal.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
|
document.getElementById('total-sum').textContent = grandTotal.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Úprava celkově: přepočítá počet, cena/jedn. a sleva zůstávají
|
||||||
|
function recalculatePocetFromCelkem(row) {
|
||||||
|
const celkem = parseFloat(row.querySelector('.item-celkem').value) || 0;
|
||||||
|
const cena = parseFloat(row.querySelector('.item-cena').value) || 0;
|
||||||
|
const sleva = parseFloat(row.querySelector('.item-sleva').value) || 0;
|
||||||
|
const faktor = cena * (1 - (sleva / 100));
|
||||||
|
const pocetInput = row.querySelector('.item-pocet');
|
||||||
|
|
||||||
|
if (!pocetInput || Math.abs(faktor) < 1e-9) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pocetInput.value = String(roundPocet(celkem / faktor));
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGrandTotalFromInputs() {
|
||||||
|
let grandTotal = 0;
|
||||||
|
document.querySelectorAll('.item-row').forEach(row => {
|
||||||
|
const celkemInput = row.querySelector('.item-celkem');
|
||||||
|
if (celkemInput && document.activeElement === celkemInput) {
|
||||||
|
grandTotal += parseFloat(celkemInput.value) || 0;
|
||||||
|
} else {
|
||||||
|
grandTotal += rowCelkem(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById('total-sum').textContent = grandTotal.toLocaleString('cs-CZ', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' CZK';
|
||||||
|
}
|
||||||
|
|
||||||
function fold(value) {
|
function fold(value) {
|
||||||
return String(value).normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
return String(value).normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
@ -593,11 +634,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
<i class="bi bi-grip-vertical text-muted fs-5"></i>
|
<i class="bi bi-grip-vertical text-muted fs-5"></i>
|
||||||
</td>
|
</td>
|
||||||
<td data-label="Název"><input type="text" name="polozky[${rowIndex}][NAZEV]" class="form-control item-nazev" placeholder="Začněte psát název práce nebo zboží" required autocomplete="off"></td>
|
<td data-label="Název"><input type="text" name="polozky[${rowIndex}][NAZEV]" class="form-control item-nazev" placeholder="Začněte psát název práce nebo zboží" required autocomplete="off"></td>
|
||||||
<td data-label="Počet"><input type="number" step="0.01" name="polozky[${rowIndex}][POCET]" value="1" class="form-control item-pocet text-end" required></td>
|
<td data-label="Počet"><input type="number" step="any" name="polozky[${rowIndex}][POCET]" value="1" class="form-control item-pocet text-end" required></td>
|
||||||
<td data-label="Jedn."><input type="text" name="polozky[${rowIndex}][JEDNOTKA]" value="ks" class="form-control"></td>
|
<td data-label="Jedn."><input type="text" name="polozky[${rowIndex}][JEDNOTKA]" value="ks" class="form-control"></td>
|
||||||
<td data-label="Cena/Jedn."><input type="number" step="0.01" name="polozky[${rowIndex}][CENA_JEDNOTKA]" value="0" class="form-control item-cena text-end" required></td>
|
<td data-label="Cena/Jedn."><input type="number" step="0.01" name="polozky[${rowIndex}][CENA_JEDNOTKA]" value="0" class="form-control item-cena text-end" required></td>
|
||||||
<td data-label="Sleva %"><input type="number" step="0.1" name="polozky[${rowIndex}][SLEVA]" value="0" class="form-control item-sleva text-end"></td>
|
<td data-label="Sleva %"><input type="number" step="0.1" name="polozky[${rowIndex}][SLEVA]" value="0" class="form-control item-sleva text-end"></td>
|
||||||
<td data-label="Celkem" class="text-end fw-bold item-celkem-text">0,00 CZK</td>
|
<td data-label="Celkem"><input type="number" step="0.01" value="0" class="form-control item-celkem text-end fw-bold" title="Úprava přepočítá počet"></td>
|
||||||
<td class="text-center cell-actions">
|
<td class="text-center cell-actions">
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
|
<button type="button" class="btn btn-outline-danger btn-sm btn-remove-row"><i class="bi bi-trash"></i></button>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -621,11 +662,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
tbody.addEventListener('input', (e) => {
|
tbody.addEventListener('input', (e) => {
|
||||||
|
if (e.target.matches('.item-celkem')) {
|
||||||
|
recalculatePocetFromCelkem(e.target.closest('.item-row'));
|
||||||
|
updateGrandTotalFromInputs();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (e.target.matches('.item-pocet, .item-cena, .item-sleva')) {
|
if (e.target.matches('.item-pocet, .item-cena, .item-sleva')) {
|
||||||
calculateTotals();
|
calculateTotals();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tbody.addEventListener('focusout', (e) => {
|
||||||
|
if (e.target.matches('.item-celkem')) {
|
||||||
|
recalculatePocetFromCelkem(e.target.closest('.item-row'));
|
||||||
|
calculateTotals();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (document.querySelectorAll('.item-row').length === 0) {
|
if (document.querySelectorAll('.item-row').length === 0) {
|
||||||
btnAdd.click();
|
btnAdd.click();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue