add HR
This commit is contained in:
parent
dbea931b59
commit
990505d301
47
db/migrations/20260217_hr_module.sql
Normal file
47
db/migrations/20260217_hr_module.sql
Normal file
@ -0,0 +1,47 @@
|
||||
-- HR Module Migration
|
||||
CREATE TABLE IF NOT EXISTS hr_departments (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hr_employees (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
department_id INT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255),
|
||||
phone VARCHAR(20),
|
||||
position VARCHAR(100),
|
||||
salary DECIMAL(15, 3) DEFAULT 0.000,
|
||||
joining_date DATE,
|
||||
status ENUM('active', 'inactive') DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (department_id) REFERENCES hr_departments(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hr_attendance (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
employee_id INT NOT NULL,
|
||||
attendance_date DATE NOT NULL,
|
||||
clock_in TIME,
|
||||
clock_out TIME,
|
||||
status ENUM('present', 'absent', 'on_leave') DEFAULT 'present',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (employee_id) REFERENCES hr_employees(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY (employee_id, attendance_date)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS hr_payroll (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
employee_id INT NOT NULL,
|
||||
payroll_month INT NOT NULL,
|
||||
payroll_year INT NOT NULL,
|
||||
basic_salary DECIMAL(15, 3) DEFAULT 0.000,
|
||||
bonus DECIMAL(15, 3) DEFAULT 0.000,
|
||||
deductions DECIMAL(15, 3) DEFAULT 0.000,
|
||||
net_salary DECIMAL(15, 3) DEFAULT 0.000,
|
||||
payment_date DATE,
|
||||
status ENUM('pending', 'paid') DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (employee_id) REFERENCES hr_employees(id) ON DELETE CASCADE
|
||||
);
|
||||
2
db/migrations/20260217_hr_payroll_unique.sql
Normal file
2
db/migrations/20260217_hr_payroll_unique.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- Add unique constraint to payroll to prevent duplicates
|
||||
ALTER TABLE hr_payroll ADD UNIQUE KEY employee_month_year (employee_id, payroll_month, payroll_year);
|
||||
616
index.php
616
index.php
@ -1219,6 +1219,126 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
}
|
||||
|
||||
// --- HR Handlers ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['add_hr_department'])) {
|
||||
$name = $_POST['name'] ?? '';
|
||||
if ($name) {
|
||||
$stmt = db()->prepare("INSERT INTO hr_departments (name) VALUES (?)");
|
||||
$stmt->execute([$name]);
|
||||
$message = "Department added successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['edit_hr_department'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
$name = $_POST['name'] ?? '';
|
||||
if ($id && $name) {
|
||||
$stmt = db()->prepare("UPDATE hr_departments SET name = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $id]);
|
||||
$message = "Department updated successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['delete_hr_department'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
if ($id) {
|
||||
$stmt = db()->prepare("DELETE FROM hr_departments WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$message = "Department deleted successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['add_hr_employee'])) {
|
||||
$dept_id = (int)$_POST['department_id'] ?: null;
|
||||
$name = $_POST['name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
$pos = $_POST['position'] ?? '';
|
||||
$salary = (float)($_POST['salary'] ?? 0);
|
||||
$j_date = $_POST['joining_date'] ?: null;
|
||||
if ($name) {
|
||||
$stmt = db()->prepare("INSERT INTO hr_employees (department_id, name, email, phone, position, salary, joining_date) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$dept_id, $name, $email, $phone, $pos, $salary, $j_date]);
|
||||
$message = "Employee added successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['edit_hr_employee'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
$dept_id = (int)$_POST['department_id'] ?: null;
|
||||
$name = $_POST['name'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
$pos = $_POST['position'] ?? '';
|
||||
$salary = (float)($_POST['salary'] ?? 0);
|
||||
$j_date = $_POST['joining_date'] ?: null;
|
||||
$status = $_POST['status'] ?? 'active';
|
||||
if ($id && $name) {
|
||||
$stmt = db()->prepare("UPDATE hr_employees SET department_id = ?, name = ?, email = ?, phone = ?, position = ?, salary = ?, joining_date = ?, status = ? WHERE id = ?");
|
||||
$stmt->execute([$dept_id, $name, $email, $phone, $pos, $salary, $j_date, $status, $id]);
|
||||
$message = "Employee updated successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['delete_hr_employee'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
if ($id) {
|
||||
$stmt = db()->prepare("DELETE FROM hr_employees WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$message = "Employee deleted successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['mark_attendance'])) {
|
||||
$emp_id = (int)$_POST['employee_id'];
|
||||
$date = $_POST['attendance_date'] ?: date('Y-m-d');
|
||||
$status = $_POST['status'] ?? 'present';
|
||||
$in = $_POST['clock_in'] ?: null;
|
||||
$out = $_POST['clock_out'] ?: null;
|
||||
if ($emp_id) {
|
||||
$stmt = db()->prepare("INSERT INTO hr_attendance (employee_id, attendance_date, status, clock_in, clock_out) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE status = ?, clock_in = ?, clock_out = ?");
|
||||
$stmt->execute([$emp_id, $date, $status, $in, $out, $status, $in, $out]);
|
||||
$message = "Attendance marked successfully!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['generate_payroll'])) {
|
||||
$emp_id = (int)$_POST['employee_id'];
|
||||
$month = (int)$_POST['month'];
|
||||
$year = (int)$_POST['year'];
|
||||
$bonus = (float)($_POST['bonus'] ?? 0);
|
||||
$deductions = (float)($_POST['deductions'] ?? 0);
|
||||
|
||||
$emp = db()->prepare("SELECT salary FROM hr_employees WHERE id = ?");
|
||||
$emp->execute([$emp_id]);
|
||||
$salary = (float)$emp->fetchColumn();
|
||||
|
||||
$net = $salary + $bonus - $deductions;
|
||||
|
||||
try {
|
||||
$stmt = db()->prepare("INSERT INTO hr_payroll (employee_id, payroll_month, payroll_year, basic_salary, bonus, deductions, net_salary, status) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')");
|
||||
$stmt->execute([$emp_id, $month, $year, $salary, $bonus, $deductions, $net]);
|
||||
$message = "Payroll generated successfully!";
|
||||
} catch (PDOException $e) {
|
||||
if ($e->getCode() == 23000) { // Integrity constraint violation
|
||||
$message = "Error: Payroll already exists for this employee in the selected period.";
|
||||
} else {
|
||||
$message = "Error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($_POST['pay_payroll'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
if ($id) {
|
||||
$stmt = db()->prepare("UPDATE hr_payroll SET status = 'paid', payment_date = CURDATE() WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$message = "Payroll marked as paid!";
|
||||
}
|
||||
}
|
||||
if (isset($_POST['delete_payroll'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
if ($id) {
|
||||
$stmt = db()->prepare("DELETE FROM hr_payroll WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$message = "Payroll record deleted successfully!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Routing & Data Fetching
|
||||
$page = $_GET['page'] ?? 'dashboard';
|
||||
@ -1567,6 +1687,30 @@ switch ($page) {
|
||||
$stmt->execute($params);
|
||||
$data['expiry_items'] = $stmt->fetchAll();
|
||||
break;
|
||||
case 'hr_departments':
|
||||
$data['departments'] = db()->query("SELECT * FROM hr_departments ORDER BY id DESC")->fetchAll();
|
||||
break;
|
||||
case 'hr_employees':
|
||||
$data['employees'] = db()->query("SELECT e.*, d.name as dept_name FROM hr_employees e LEFT JOIN hr_departments d ON e.department_id = d.id ORDER BY e.id DESC")->fetchAll();
|
||||
$data['departments'] = db()->query("SELECT * FROM hr_departments ORDER BY name ASC")->fetchAll();
|
||||
break;
|
||||
case 'hr_attendance':
|
||||
$date = $_GET['date'] ?? date('Y-m-d');
|
||||
$data['attendance_date'] = $date;
|
||||
$data['employees'] = db()->query("SELECT e.id, e.name, d.name as dept_name, a.status, a.clock_in, a.clock_out
|
||||
FROM hr_employees e
|
||||
LEFT JOIN hr_departments d ON e.department_id = d.id
|
||||
LEFT JOIN hr_attendance a ON e.id = a.employee_id AND a.attendance_date = '$date'
|
||||
WHERE e.status = 'active' ORDER BY e.name ASC")->fetchAll();
|
||||
break;
|
||||
case 'hr_payroll':
|
||||
$month = (int)($_GET['month'] ?? date('m'));
|
||||
$year = (int)($_GET['year'] ?? date('Y'));
|
||||
$data['month'] = $month;
|
||||
$data['year'] = $year;
|
||||
$data['payroll'] = db()->query("SELECT p.*, e.name as emp_name FROM hr_payroll p JOIN hr_employees e ON p.employee_id = e.id WHERE p.payroll_month = $month AND p.payroll_year = $year ORDER BY p.id DESC")->fetchAll();
|
||||
$data['employees'] = db()->query("SELECT id, name, salary FROM hr_employees WHERE status = 'active' ORDER BY name ASC")->fetchAll();
|
||||
break;
|
||||
default:
|
||||
$data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll();
|
||||
// Dashboard stats
|
||||
@ -1733,8 +1877,25 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<a href="index.php?page=settings" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'settings' ? 'active' : '' ?>">
|
||||
<i class="bi bi-building"></i> <span data-en="Company Profile" data-ar="ملف الشركة">Company Profile</span>
|
||||
</a>
|
||||
<a href="#" class="nav-link">
|
||||
<i class="bi bi-person-badge"></i> <span data-en="HR" data-ar="الموارد البشرية">HR</span>
|
||||
</div>
|
||||
|
||||
<!-- HR Section -->
|
||||
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['hr_employees', 'hr_departments', 'hr_attendance', 'hr_payroll']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#hr-collapse">
|
||||
<span data-en="HR" data-ar="الموارد البشرية">HR</span>
|
||||
<i class="bi bi-chevron-down"></i>
|
||||
</div>
|
||||
<div class="collapse <?= in_array($page, ['hr_employees', 'hr_departments', 'hr_attendance', 'hr_payroll']) ? 'show' : '' ?>" id="hr-collapse">
|
||||
<a href="index.php?page=hr_departments" class="nav-link <?= $page === 'hr_departments' ? 'active' : '' ?>">
|
||||
<i class="bi bi-building"></i> <span data-en="Departments" data-ar="الأقسام">Departments</span>
|
||||
</a>
|
||||
<a href="index.php?page=hr_employees" class="nav-link <?= $page === 'hr_employees' ? 'active' : '' ?>">
|
||||
<i class="bi bi-person-badge"></i> <span data-en="Employees" data-ar="الموظفون">Employees</span>
|
||||
</a>
|
||||
<a href="index.php?page=hr_attendance" class="nav-link <?= $page === 'hr_attendance' ? 'active' : '' ?>">
|
||||
<i class="bi bi-calendar-check"></i> <span data-en="Attendance" data-ar="الحضور">Attendance</span>
|
||||
</a>
|
||||
<a href="index.php?page=hr_payroll" class="nav-link <?= $page === 'hr_payroll' ? 'active' : '' ?>">
|
||||
<i class="bi bi-cash-coin"></i> <span data-en="Payroll" data-ar="الرواتب">Payroll</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
@ -1761,6 +1922,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
'supplier_statement' => ['en' => 'Supplier Statement', 'ar' => 'كشف حساب مورد'],
|
||||
'expiry_report' => ['en' => 'Expiry Report', 'ar' => 'تقرير انتهاء الصلاحية'],
|
||||
'settings' => ['en' => 'Company Profile', 'ar' => 'ملف الشركة'],
|
||||
'hr_departments' => ['en' => 'HR Departments', 'ar' => 'أقسام الموارد البشرية'],
|
||||
'hr_employees' => ['en' => 'HR Employees', 'ar' => 'موظفي الموارد البشرية'],
|
||||
'hr_attendance' => ['en' => 'HR Attendance', 'ar' => 'حضور الموارد البشرية'],
|
||||
'hr_payroll' => ['en' => 'HR Payroll', 'ar' => 'رواتب الموارد البشرية'],
|
||||
];
|
||||
$currTitle = $titles[$page] ?? $titles['dashboard'];
|
||||
?>
|
||||
@ -4064,6 +4229,374 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'hr_departments'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="m-0" data-en="HR Departments" data-ar="أقسام الموارد البشرية">HR Departments</h5>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addHrDepartmentModal">
|
||||
<i class="bi bi-plus-lg"></i> <span data-en="Add Department" data-ar="إضافة قسم">Add Department</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-en="ID" data-ar="المعرف">ID</th>
|
||||
<th data-en="Department Name" data-ar="اسم القسم">Department Name</th>
|
||||
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($data['departments'] as $d): ?>
|
||||
<tr>
|
||||
<td><?= $d['id'] ?></td>
|
||||
<td><?= htmlspecialchars($d['name']) ?></td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editHrDepartmentModal<?= $d['id'] ?>"><i class="bi bi-pencil"></i></button>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
|
||||
<input type="hidden" name="id" value="<?= $d['id'] ?>">
|
||||
<button type="submit" name="delete_hr_department" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Edit Dept Modal -->
|
||||
<div class="modal fade" id="editHrDepartmentModal<?= $d['id'] ?>" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Edit Department" data-ar="تعديل القسم">Edit Department</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="id" value="<?= $d['id'] ?>">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Department Name" data-ar="اسم القسم">Department Name</label>
|
||||
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($d['name']) ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="edit_hr_department" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'hr_employees'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="m-0" data-en="HR Employees" data-ar="موظفي الموارد البشرية">HR Employees</h5>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addHrEmployeeModal">
|
||||
<i class="bi bi-plus-lg"></i> <span data-en="Add Employee" data-ar="إضافة موظف">Add Employee</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-en="Name" data-ar="الاسم">Name</th>
|
||||
<th data-en="Department" data-ar="القسم">Department</th>
|
||||
<th data-en="Position" data-ar="المنصب">Position</th>
|
||||
<th data-en="Salary" data-ar="الراتب">Salary</th>
|
||||
<th data-en="Status" data-ar="الحالة">Status</th>
|
||||
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($data['employees'] as $e): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-bold"><?= htmlspecialchars($e['name']) ?></div>
|
||||
<div class="small text-muted"><?= htmlspecialchars($e['email']) ?></div>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($e['dept_name'] ?? '---') ?></td>
|
||||
<td><?= htmlspecialchars($e['position']) ?></td>
|
||||
<td>OMR <?= number_format($e['salary'], 3) ?></td>
|
||||
<td>
|
||||
<span class="badge <?= $e['status'] === 'active' ? 'bg-success' : 'bg-danger' ?> text-uppercase">
|
||||
<?= $e['status'] ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editHrEmployeeModal<?= $e['id'] ?>"><i class="bi bi-pencil"></i></button>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
|
||||
<input type="hidden" name="id" value="<?= $e['id'] ?>">
|
||||
<button type="submit" name="delete_hr_employee" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Edit Employee Modal -->
|
||||
<div class="modal fade" id="editHrEmployeeModal<?= $e['id'] ?>" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Edit Employee" data-ar="تعديل الموظف">Edit Employee</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="id" value="<?= $e['id'] ?>">
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Full Name" data-ar="الاسم الكامل">Full Name</label>
|
||||
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($e['name']) ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Department" data-ar="القسم">Department</label>
|
||||
<select name="department_id" class="form-select">
|
||||
<option value="">--- Select ---</option>
|
||||
<?php foreach ($data['departments'] as $d): ?>
|
||||
<option value="<?= $d['id'] ?>" <?= $e['department_id'] == $d['id'] ? 'selected' : '' ?>><?= htmlspecialchars($d['name']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Email" data-ar="البريد">Email</label>
|
||||
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars($e['email']) ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
|
||||
<input type="text" name="phone" class="form-control" value="<?= htmlspecialchars($e['phone']) ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Position" data-ar="المنصب">Position</label>
|
||||
<input type="text" name="position" class="form-control" value="<?= htmlspecialchars($e['position']) ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Basic Salary" data-ar="الراتب الأساسي">Basic Salary</label>
|
||||
<input type="number" step="0.001" name="salary" class="form-control" value="<?= $e['salary'] ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Joining Date" data-ar="تاريخ الانضمام">Joining Date</label>
|
||||
<input type="date" name="joining_date" class="form-control" value="<?= $e['joining_date'] ?>">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Status" data-ar="الحالة">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="active" <?= $e['status'] === 'active' ? 'selected' : '' ?>>Active</option>
|
||||
<option value="inactive" <?= $e['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="edit_hr_employee" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'hr_attendance'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="m-0" data-en="HR Attendance" data-ar="حضور الموارد البشرية">HR Attendance</h5>
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<input type="hidden" name="page" value="hr_attendance">
|
||||
<input type="date" name="date" class="form-control form-control-sm" value="<?= $data['attendance_date'] ?>" onchange="this.form.submit()">
|
||||
</form>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-en="Employee" data-ar="الموظف">Employee</th>
|
||||
<th data-en="Department" data-ar="القسم">Department</th>
|
||||
<th data-en="Status" data-ar="الحالة">Status</th>
|
||||
<th data-en="Clock In" data-ar="وقت الدخول">Clock In</th>
|
||||
<th data-en="Clock Out" data-ar="وقت الخروج">Clock Out</th>
|
||||
<th data-en="Action" data-ar="إجراء" class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($data['employees'] as $e): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($e['name']) ?></td>
|
||||
<td><?= htmlspecialchars($e['dept_name'] ?? '---') ?></td>
|
||||
<td>
|
||||
<?php if ($e['status']): ?>
|
||||
<span class="badge <?= $e['status'] === 'present' ? 'bg-success' : ($e['status'] === 'absent' ? 'bg-danger' : 'bg-warning') ?> text-uppercase">
|
||||
<?= $e['status'] ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-secondary text-uppercase">Not Marked</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= $e['clock_in'] ?? '---' ?></td>
|
||||
<td><?= $e['clock_out'] ?? '---' ?></td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#markAttendanceModal<?= $e['id'] ?>">
|
||||
<i class="bi bi-calendar-check"></i> <span data-en="Mark" data-ar="تسجيل">Mark</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Attendance Modal -->
|
||||
<div class="modal fade" id="markAttendanceModal<?= $e['id'] ?>" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Mark Attendance" data-ar="تسجيل الحضور">Mark Attendance - <?= htmlspecialchars($e['name']) ?></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="employee_id" value="<?= $e['id'] ?>">
|
||||
<input type="hidden" name="attendance_date" value="<?= $data['attendance_date'] ?>">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Status" data-ar="الحالة">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="present" <?= $e['status'] === 'present' ? 'selected' : '' ?>>Present</option>
|
||||
<option value="absent" <?= $e['status'] === 'absent' ? 'selected' : '' ?>>Absent</option>
|
||||
<option value="on_leave" <?= $e['status'] === 'on_leave' ? 'selected' : '' ?>>On Leave</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Clock In" data-ar="وقت الدخول">Clock In</label>
|
||||
<input type="time" name="clock_in" class="form-control" value="<?= $e['clock_in'] ?>">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Clock Out" data-ar="وقت الخروج">Clock Out</label>
|
||||
<input type="time" name="clock_out" class="form-control" value="<?= $e['clock_out'] ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="mark_attendance" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'hr_payroll'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="m-0" data-en="HR Payroll" data-ar="رواتب الموارد البشرية">HR Payroll</h5>
|
||||
<div class="d-flex gap-2">
|
||||
<form method="GET" class="d-flex gap-2">
|
||||
<input type="hidden" name="page" value="hr_payroll">
|
||||
<select name="month" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||
<?php for($m=1; $m<=12; $m++): ?>
|
||||
<option value="<?= $m ?>" <?= $data['month'] == $m ? 'selected' : '' ?>><?= date('F', mktime(0, 0, 0, $m, 1)) ?></option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
<select name="year" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||
<?php for($y=date('Y'); $y>=date('Y')-2; $y--): ?>
|
||||
<option value="<?= $y ?>" <?= $data['year'] == $y ? 'selected' : '' ?>><?= $y ?></option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</form>
|
||||
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#generatePayrollModal">
|
||||
<i class="bi bi-gear"></i> <span data-en="Generate" data-ar="توليد">Generate</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-en="Employee" data-ar="الموظف">Employee</th>
|
||||
<th data-en="Basic" data-ar="الأساسي">Basic</th>
|
||||
<th data-en="Bonus" data-ar="مكافأة">Bonus</th>
|
||||
<th data-en="Deductions" data-ar="استقطاعات">Deductions</th>
|
||||
<th data-en="Net Salary" data-ar="صافي الراتب">Net Salary</th>
|
||||
<th data-en="Status" data-ar="الحالة">Status</th>
|
||||
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($data['payroll'] as $p): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($p['emp_name']) ?></td>
|
||||
<td>OMR <?= number_format($p['basic_salary'], 3) ?></td>
|
||||
<td class="text-success">+ OMR <?= number_format($p['bonus'], 3) ?></td>
|
||||
<td class="text-danger">- OMR <?= number_format($p['deductions'], 3) ?></td>
|
||||
<td class="fw-bold">OMR <?= number_format($p['net_salary'], 3) ?></td>
|
||||
<td>
|
||||
<span class="badge <?= $p['status'] === 'paid' ? 'bg-success' : 'bg-warning' ?> text-uppercase">
|
||||
<?= $p['status'] ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php if ($p['status'] === 'pending'): ?>
|
||||
<form method="POST" class="d-inline">
|
||||
<input type="hidden" name="id" value="<?= $p['id'] ?>">
|
||||
<button type="submit" name="pay_payroll" class="btn btn-sm btn-success" title="Mark Paid"><i class="bi bi-check-circle"></i></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
|
||||
<input type="hidden" name="id" value="<?= $p['id'] ?>">
|
||||
<button type="submit" name="delete_payroll" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generate Payroll Modal -->
|
||||
<div class="modal fade" id="generatePayrollModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Generate Payroll" data-ar="توليد الرواتب">Generate Payroll</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="month" value="<?= $data['month'] ?>">
|
||||
<input type="hidden" name="year" value="<?= $data['year'] ?>">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Employee" data-ar="الموظف">Employee</label>
|
||||
<select name="employee_id" class="form-select select2" required>
|
||||
<option value="">--- Select ---</option>
|
||||
<?php foreach ($data['employees'] as $e): ?>
|
||||
<option value="<?= $e['id'] ?>"><?= htmlspecialchars($e['name']) ?> (Basic: <?= number_format($e['salary'], 3) ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Bonus" data-ar="مكافأة">Bonus</label>
|
||||
<input type="number" step="0.001" name="bonus" class="form-control" value="0.000">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Deductions" data-ar="استقطاعات">Deductions</label>
|
||||
<input type="number" step="0.001" name="deductions" class="form-control" value="0.000">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="generate_payroll" class="btn btn-primary" data-en="Generate" data-ar="توليد">Generate</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php elseif ($page === 'settings'): ?>
|
||||
<div class="card p-4">
|
||||
<h5 class="mb-4" data-en="Company Profile" data-ar="ملف الشركة">Company Profile</h5>
|
||||
@ -4128,6 +4661,85 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Add HR Department Modal -->
|
||||
<div class="modal fade" id="addHrDepartmentModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Add HR Department" data-ar="إضافة قسم">Add HR Department</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" data-en="Department Name" data-ar="اسم القسم">Department Name</label>
|
||||
<input type="text" name="name" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="add_hr_department" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add HR Employee Modal -->
|
||||
<div class="modal fade" id="addHrEmployeeModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" data-en="Add HR Employee" data-ar="إضافة موظف">Add HR Employee</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Full Name" data-ar="الاسم الكامل">Full Name</label>
|
||||
<input type="text" name="name" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Department" data-ar="القسم">Department</label>
|
||||
<select name="department_id" class="form-select">
|
||||
<option value="">--- Select ---</option>
|
||||
<?php foreach ($data['departments'] ?? [] as $d): ?>
|
||||
<option value="<?= $d['id'] ?>"><?= htmlspecialchars($d['name']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Email" data-ar="البريد">Email</label>
|
||||
<input type="email" name="email" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
|
||||
<input type="text" name="phone" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Position" data-ar="المنصب">Position</label>
|
||||
<input type="text" name="position" class="form-control">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Basic Salary" data-ar="الراتب الأساسي">Basic Salary</label>
|
||||
<input type="number" step="0.001" name="salary" class="form-control" value="0.000">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" data-en="Joining Date" data-ar="تاريخ الانضمام">Joining Date</label>
|
||||
<input type="date" name="joining_date" class="form-control" value="<?= date('Y-m-d') ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
|
||||
<button type="submit" name="add_hr_employee" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Customer Modal -->
|
||||
<div class="modal fade" id="addCustomerModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user