Online Smart Payroll Management System

Smart Payroll Management System

Manage timesheets, calculate payroll, and generate payslips efficiently.

Payroll Run for

Total Gross Pay

$0.00

Total Deductions

$0.00

Total Net Pay

$0.00

Employees Paid

0

EmployeeGross PayDeductionsNet PayActions

${emp.payType.charAt(0).toUpperCase() + emp.payType.slice(1)} - ${rateDisplay}

`; }); }; const renderTimesheetLog = () => { const log = document.getElementById('timesheetLog'); const date = document.getElementById('timesheetDate').value; log.innerHTML = ''; if (timesheets[date]) { Object.entries(timesheets[date]).forEach(([empId, hours]) => { const emp = employees.find(e => e.id == empId); log.innerHTML += `
${emp.name}: ${hours} hours
`; }); } }; // --- PAYROLL LOGIC --- app.runPayroll = () => { const period = document.getElementById('payrollPeriod').value; if (!period) { alert('Please select a payroll period.'); return; } const [year, month] = period.split('-').map(Number); const payrollData = employees.map(emp => { let grossPay = 0; if (emp.payType === 'salary') { grossPay = emp.rate / 12; } else { Object.entries(timesheets).forEach(([date, entries]) => { const d = new Date(date); if (d.getFullYear() === year && d.getMonth() + 1 === month && entries[emp.id]) { grossPay += entries[emp.id] * emp.rate; } }); } const deductions = grossPay * 0.15; // Mock 15% tax const netPay = grossPay - deductions; return { ...emp, grossPay, deductions, netPay }; }).filter(p => p.grossPay > 0); renderPayrollDashboard(payrollData); }; const renderPayrollDashboard = (payrollData) => { const totalGross = payrollData.reduce((sum, p) => sum + p.grossPay, 0); const totalDeductions = payrollData.reduce((sum, p) => sum + p.deductions, 0); const totalNet = payrollData.reduce((sum, p) => sum + p.netPay, 0); document.getElementById('totalGrossPay').textContent = `$${totalGross.toFixed(2)}`; document.getElementById('totalDeductions').textContent = `$${totalDeductions.toFixed(2)}`; document.getElementById('totalNetPay').textContent = `$${totalNet.toFixed(2)}`; document.getElementById('employeesPaid').textContent = payrollData.length; const tableBody = document.getElementById('payrollTable'); tableBody.innerHTML = ''; payrollData.forEach(p => { tableBody.innerHTML += `${p.name}$${p.grossPay.toFixed(2)}$${p.deductions.toFixed(2)}$${p.netPay.toFixed(2)}`; }); if (payrollChart) payrollChart.destroy(); const ctx = document.getElementById('payrollChart').getContext('2d'); payrollChart = new Chart(ctx, { type: 'bar', data: { labels: payrollData.map(p => p.name), datasets: [ { label: 'Gross Pay', data: payrollData.map(p => p.grossPay), backgroundColor: '#3B82F6' }, { label: 'Net Pay', data: payrollData.map(p => p.netPay), backgroundColor: '#10B981' } ] } }); }; // --- TIMESHEET LOGIC --- app.logHours = () => { const date = document.getElementById('timesheetDate').value; const employeeId = document.getElementById('timesheetEmployee').value; const hours = parseFloat(document.getElementById('timesheetHours').value); if (!date || !employeeId || !hours) { alert('Please fill all fields.'); return; } if (!timesheets[date]) timesheets[date] = {}; timesheets[date][employeeId] = (timesheets[date][employeeId] || 0) + hours; saveTimesheets(); renderTimesheetLog(); }; app.deleteLogEntry = (date, empId) => { delete timesheets[date][empId]; if (Object.keys(timesheets[date]).length === 0) delete timesheets[date]; saveTimesheets(); renderTimesheetLog(); }; // --- EMPLOYEE MANAGEMENT --- app.showEmployeeModal = (id = null) => { const modal = document.getElementById('employeeModal'); const title = document.getElementById('employeeModalTitle'); const idInput = document.getElementById('employeeIdInput'); const nameInput = document.getElementById('employeeNameInput'); const typeSelect = document.getElementById('payTypeSelect'); const rateInput = document.getElementById('payRateInput'); if (id) { const emp = employees.find(e => e.id === id); title.textContent = 'Edit Employee'; idInput.value = emp.id; nameInput.value = emp.name; typeSelect.value = emp.payType; rateInput.value = emp.rate; } else { title.textContent = 'Add Employee'; idInput.value = ''; nameInput.value = ''; typeSelect.value = 'hourly'; rateInput.value = ''; } modal.classList.remove('hidden'); }; app.saveEmployee = () => { const id = document.getElementById('employeeIdInput').value; const name = document.getElementById('employeeNameInput').value; if (!name.trim()) { alert('Name is required.'); return; } const empData = { name, payType: document.getElementById('payTypeSelect').value, rate: parseFloat(document.getElementById('payRateInput').value) }; if (id) { const emp = employees.find(e => e.id == id); Object.assign(emp, empData); } else { employees.push({ id: Date.now(), ...empData }); } saveEmployees(); renderEmployeeList(); updateTimesheetEmployeeSelect(); app.hideModal('employeeModal'); }; app.deleteEmployee = (id) => { if (confirm('Are you sure? This will delete the employee and their timesheet data.')) { employees = employees.filter(e => e.id !== id); Object.keys(timesheets).forEach(date => { delete timesheets[date][id]; }); saveEmployees(); saveTimesheets(); renderEmployeeList(); updateTimesheetEmployeeSelect(); } }; // --- UTILS & HELPERS --- app.hideModal = (id) => document.getElementById(id).classList.add('hidden'); app.changeTab = (tabIndex) => { document.querySelectorAll('[id^="tabContent-"]').forEach(el => el.classList.add('hidden')); document.querySelectorAll('[id^="tab-"]').forEach(el => el.classList.replace('tab-active', 'tab-inactive')); document.getElementById(`tabContent-${tabIndex}`).classList.remove('hidden'); document.getElementById(`tab-${tabIndex}`).classList.replace('tab-inactive', 'tab-active'); }; const updateTimesheetEmployeeSelect = () => { const select = document.getElementById('timesheetEmployee'); select.innerHTML = ''; employees.filter(e => e.payType === 'hourly').forEach(emp => { select.innerHTML += ``; }); }; app.downloadPayslip = (payroll) => { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const period = document.getElementById('payrollPeriod').value; doc.setFontSize(20); doc.text('Payslip', 105, 20, { align: 'center' }); doc.setFontSize(12); doc.text(`Employee: ${payroll.name}`, 15, 40); doc.text(`Pay Period: ${period}`, 15, 47); doc.autoTable({ startY: 60, head: [['Description', 'Amount']], body: [ ['Gross Pay', `$${payroll.grossPay.toFixed(2)}`], ['Deductions (Tax)', `-$${payroll.deductions.toFixed(2)}`], ['Net Pay', `$${payroll.netPay.toFixed(2)}`], ], foot: [['Total Net Pay', `$${payroll.netPay.toFixed(2)}`]], theme: 'striped', footStyles: { fontStyle: 'bold' } }); doc.save(`Payslip_${payroll.name.replace(' ','_')}_${period}.pdf`); }; // --- INITIALIZATION --- loadData(); renderEmployeeList(); updateTimesheetEmployeeSelect(); const now = new Date(); document.getElementById('timesheetDate').value = now.toISOString().split('T')[0]; document.getElementById('payrollPeriod').value = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`; renderTimesheetLog(); });
Scroll to Top