Fazla Mesai Çarpanı:
Hepsini Hesapla
CSV İndir
<tr data-name="Ayşe">
<td class="readonly">Ayşe</td>
<td><input type="number" min="0" step="0.01" class="hourly" value="120"></td>
<td><input type="number" min="0" step="0.01" class="hours" value="170"></td>
<td><input type="number" min="0" step="0.01" class="ot" value="0"></td>
<td><input type="number" min="0" step="0.01" class="deductions" value="300"></td>
<td class="originalBrut readonly">20700</td>
<td class="originalNet readonly">20400</td>
<td class="calcBrut readonly">—</td>
<td class="calcNet readonly">—</td>
<td class="status small">—</td>
</tr>
<tr data-name="Mehmet">
<td class="readonly">Mehmet</td>
<td><input type="number" min="0" step="0.01" class="hourly" value="100"></td>
<td><input type="number" min="0" step="0.01" class="hours" value="150"></td>
<td><input type="number" min="0" step="0.01" class="ot" value="5"></td>
<td><input type="number" min="0" step="0.01" class="deductions" value="0"></td>
<td class="originalBrut readonly">15750</td>
<td class="originalNet readonly">15750</td>
<td class="calcBrut readonly">—</td>
<td class="calcNet readonly">—</td>
<td class="status small">—</td>
</tr>
</tbody>
| Ad | Saatlik Ücret (TL) | Çalışma Saati | Ek Mesai Saati | Kesinti (TL) | Orijinal Brüt (TL) | Orijinal Net (TL) | Hesaplanan Brüt (TL) | Hesaplanan Net (TL) | Durum |
|---|---|---|---|---|---|---|---|---|---|
| Ahmet | 25250 | 24750 | — | — | — |
Uyuşmayanları Vurgula
Orijinalleri Geri Yükle
Tablo hücrelerindeki sayıları doğrudan düzenleyebilirsiniz. "Hepsini Hesapla" seçeneği veya numeric alanlarda değişiklik yapıldığında hesaplamalar güncellenir.
<script> (function () { const fmt = (n) => { if (Number.isNaN(n) || n === null) return "—"; // If integer, show without decimals; otherwise show up to 2 decimals const isInt = Math.abs(n - Math.round(n)) < 1e-9; return n.toLocaleString('tr-TR', { minimumFractionDigits: isInt ? 0 : 2, maximumFractionDigits: 2 }); }; const table = document.getElementById('payTable'); const tbody = table.querySelector('tbody'); const otMultiplierInput = document.getElementById('overtimeMultiplier'); const recalcBtn = document.getElementById('recalculateBtn'); const exportBtn = document.getElementById('exportCsvBtn'); const highlightBtn = document.getElementById('highlightMismatches'); const resetBtn = document.getElementById('resetOriginals'); function parseNumber(v) { const n = parseFloat(String(v).replace(',', '.')); return Number.isFinite(n) ? n : 0; } function calculateRow(tr) { const hourly = parseNumber(tr.querySelector('.hourly').value); const hours = parseNumber(tr.querySelector('.hours').value); const ot = parseNumber(tr.querySelector('.ot').value); const deductions = parseNumber(tr.querySelector('.deductions').value); const multiplier = parseNumber(otMultiplierInput.value); const brut = (hourly * hours) + (hourly * multiplier * ot); const net = brut - deductions; tr.querySelector('.calcBrut').textContent = fmt(brut); tr.querySelector('.calcNet').textContent = fmt(net); tr._computed = { brut, net, deductions }; return { brut, net }; } function recalcAll() { for (const tr of tbody.querySelectorAll('tr')) { calculateRow(tr); clearRowState(tr); } } function clearRowState(tr) { tr.classList.remove('mismatch'); tr.querySelector('.status').textContent = '—'; } function highlightMismatches() { for (const tr of tbody.querySelectorAll('tr')) { const origBrut = parseNumber(tr.querySelector('.originalBrut').textContent); const origNet = parseNumber(tr.querySelector('.originalNet').textContent); const { brut, net } = tr._computed || { brut: 0, net: 0 }; // consider mismatch if difference >= 0.5 TL const brutDiff = Math.abs(brut - origBrut); const netDiff = Math.abs(net - origNet); if (brutDiff >= 0.5 || netDiff >= 0.5) { tr.classList.add('mismatch'); tr.querySelector('.status').innerHTML = 'UYUŞMUYOR'; } else { tr.classList.remove('mismatch'); tr.querySelector('.status').innerHTML = 'UYUYOR'; } } } function exportCsv() { const rows = []; const headers = [ 'Ad', 'Saatlik Ücret (TL)', 'Çalışma Saati', 'Ek Mesai Saati', 'Kesinti (TL)', 'Orijinal Brüt (TL)', 'Orijinal Net (TL)', 'Hesaplanan Brüt (TL)', 'Hesaplanan Net (TL)' ]; rows.push(headers.join(',')); for (const tr of tbody.querySelectorAll('tr')) { const name = tr.getAttribute('data-name') || tr.querySelector('td').textContent.trim(); const hourly = parseNumber(tr.querySelector('.hourly').value); const hours = parseNumber(tr.querySelector('.hours').value); const ot = parseNumber(tr.querySelector('.ot').value); const deductions = parseNumber(tr.querySelector('.deductions').value); const origBrut = parseNumber(tr.querySelector('.originalBrut').textContent); const origNet = parseNumber(tr.querySelector('.originalNet').textContent); const brut = tr._computed ? tr._computed.brut : 0; const net = tr._computed ? tr._computed.net : 0; const csvRow = [ `"${name.replace(/"/g,'""')}"`, hourly, hours, ot, deductions, origBrut, origNet, brut.toFixed(2), net.toFixed(2) ]; rows.push(csvRow.join(',')); } const csvContent = rows.join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'bordro_hesaplanan.csv'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } // Attach listeners: recalc when inputs change tbody.addEventListener('input', (ev) => { // only react if numeric inputs changed if (ev.target.matches('input[type="number"]')) { const tr = ev.target.closest('tr'); calculateRow(tr); } }); otMultiplierInput.addEventListener('input', () => { recalcAll(); }); recalcBtn.addEventListener('click', () => { recalcAll(); }); exportBtn.addEventListener('click', () => { // ensure computed before export recalcAll(); exportCsv(); }); highlightBtn.addEventListener('click', () => { // ensure computed before highlight recalcAll(); highlightMismatches(); }); resetBtn.addEventListener('click', () => { // restore original Brüt/Net columns from the original values for (const tr of tbody.querySelectorAll('tr')) { tr.querySelector('.calcBrut').textContent = tr.querySelector('.originalBrut').textContent || '—'; tr.querySelector('.calcNet').textContent = tr.querySelector('.originalNet').textContent || '—'; tr.classList.remove('mismatch'); tr.querySelector('.status').textContent = '—'; tr._computed = null; } }); // initial calculation on load document.addEventListener('DOMContentLoaded', recalcAll); // Also run once immediately in case script executes after DOMContentLoaded recalcAll(); })(); </script>