update holydays
This commit is contained in:
parent
040f45e79d
commit
2603d90a7f
@ -21,6 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$id = !empty($_POST['id']) ? $_POST['id'] : null;
|
||||
$first_name = trim($_POST["first_name"]);
|
||||
$zkteco_uid = !empty($_POST["zkteco_uid"]) ? trim($_POST["zkteco_uid"]) : null;
|
||||
$user_id = !empty($_POST["user_id"]) ? $_POST["user_id"] : null;
|
||||
$last_name = trim($_POST['last_name']);
|
||||
$email = trim($_POST['email']);
|
||||
$phone = trim($_POST['phone']);
|
||||
@ -38,13 +39,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
try {
|
||||
if ($id) {
|
||||
// Update
|
||||
$stmt = db()->prepare("UPDATE hr_employees SET first_name=?, last_name=?, email=?, phone=?, department_id=?, job_title=?, basic_salary=?, join_date=?, status=?, gender=?, birth_date=?, zkteco_uid=? WHERE id=?");
|
||||
$stmt->execute([$first_name, $last_name, $email, $phone, $department_id, $job_title, $basic_salary, $join_date, $status, $gender, $birth_date, $zkteco_uid, $id]);
|
||||
$stmt = db()->prepare("UPDATE hr_employees SET first_name=?, last_name=?, email=?, phone=?, department_id=?, job_title=?, basic_salary=?, join_date=?, status=?, gender=?, birth_date=?, zkteco_uid=?, user_id=? WHERE id=?");
|
||||
$stmt->execute([$first_name, $last_name, $email, $phone, $department_id, $job_title, $basic_salary, $join_date, $status, $gender, $birth_date, $zkteco_uid, $user_id, $id]);
|
||||
$success = "تم تحديث بيانات الموظف بنجاح.";
|
||||
} else {
|
||||
// Insert
|
||||
$stmt = db()->prepare("INSERT INTO hr_employees (first_name, last_name, email, phone, department_id, job_title, basic_salary, join_date, status, gender, birth_date, zkteco_uid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$first_name, $last_name, $email, $phone, $department_id, $job_title, $basic_salary, $join_date, $status, $gender, $birth_date, $zkteco_uid]);
|
||||
$stmt = db()->prepare("INSERT INTO hr_employees (first_name, last_name, email, phone, department_id, job_title, basic_salary, join_date, status, gender, birth_date, zkteco_uid, user_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$first_name, $last_name, $email, $phone, $department_id, $job_title, $basic_salary, $join_date, $status, $gender, $birth_date, $zkteco_uid, $user_id]);
|
||||
$success = "تم إضافة الموظف بنجاح.";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
@ -86,6 +87,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Fetch Departments for Dropdown
|
||||
$departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchAll();
|
||||
$users = db()->query("SELECT id, full_name, email FROM users ORDER BY full_name")->fetchAll();
|
||||
|
||||
// Pagination
|
||||
$page = $_GET['page'] ?? 1;
|
||||
@ -188,6 +190,15 @@ $pagination = getPagination($page, $totalEmployees, $perPage);
|
||||
<input type="date" name="birth_date" id="empBirthDate" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">ربط بمستخدم النظام (اختياري)</label>
|
||||
<select name="user_id" id="empUser" class="form-select">
|
||||
<option value="">-- بدون حساب مستخدم --</option>
|
||||
<?php foreach ($users as $u): ?>
|
||||
<option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['full_name'] . ' (' . $u['email'] . ')') ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">القسم</label>
|
||||
<select name="department_id" id="empDept" class="form-select">
|
||||
@ -309,7 +320,7 @@ $pagination = getPagination($page, $totalEmployees, $perPage);
|
||||
data-job="<?= htmlspecialchars($row['job_title']) ?>"
|
||||
data-join="<?= $row['join_date'] ?>"
|
||||
data-salary="<?= $row['basic_salary'] ?>"
|
||||
data-status="<?= $row['status'] ?>"
|
||||
data-status="<?= $row['status'] ?>" data-user="<?= $row['user_id'] ?>"
|
||||
onclick="editEmployee(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
@ -355,6 +366,7 @@ $pagination = getPagination($page, $totalEmployees, $perPage);
|
||||
document.getElementById("empSalary").value = btn.dataset.salary;
|
||||
document.getElementById("empZktecoUid").value = btn.dataset.zkteco;
|
||||
document.getElementById('empStatus').value = btn.dataset.status;
|
||||
document.getElementById('empUser').value = btn.dataset.user || '';
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -65,20 +65,50 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Fetch Employees for Dropdown
|
||||
$employees = db()->query("SELECT id, first_name, last_name FROM hr_employees WHERE status = 'active' ORDER BY first_name")->fetchAll();
|
||||
|
||||
// Pagination
|
||||
// Pagination Setup
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
if ($page < 1) $page = 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
// Fetch Leaves based on Tab
|
||||
$where_clause = $tab === 'pending' ? "WHERE l.status = 'pending'" : "WHERE 1=1";
|
||||
// Filters & Search
|
||||
$search = $_GET['search'] ?? '';
|
||||
$filter_type = $_GET['filter_type'] ?? '';
|
||||
$filter_status = $_GET['filter_status'] ?? '';
|
||||
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
|
||||
if ($tab === 'pending') {
|
||||
$conditions[] = "l.status = 'pending'";
|
||||
} else {
|
||||
if ($filter_status) {
|
||||
$conditions[] = "l.status = ?";
|
||||
$params[] = $filter_status;
|
||||
}
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
$conditions[] = "(e.first_name LIKE ? OR e.last_name LIKE ? OR l.reason LIKE ?)";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
$params[] = "%$search%";
|
||||
}
|
||||
|
||||
if ($filter_type) {
|
||||
$conditions[] = "l.leave_type = ?";
|
||||
$params[] = $filter_type;
|
||||
}
|
||||
|
||||
$where_clause = count($conditions) > 0 ? "WHERE " . implode(' AND ', $conditions) : "WHERE 1=1";
|
||||
|
||||
// Count Total
|
||||
$countSql = "SELECT COUNT(*) FROM hr_leaves l $where_clause";
|
||||
$countStmt = db()->query($countSql);
|
||||
$countSql = "SELECT COUNT(*) FROM hr_leaves l JOIN hr_employees e ON l.employee_id = e.id $where_clause";
|
||||
$countStmt = db()->prepare($countSql);
|
||||
$countStmt->execute($params);
|
||||
$totalFiltered = $countStmt->fetchColumn();
|
||||
|
||||
// Fetch Records
|
||||
$sql = "SELECT l.*, e.first_name, e.last_name, u.full_name as approver_name
|
||||
FROM hr_leaves l
|
||||
JOIN hr_employees e ON l.employee_id = e.id
|
||||
@ -86,7 +116,9 @@ $sql = "SELECT l.*, e.first_name, e.last_name, u.full_name as approver_name
|
||||
$where_clause
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
$requests = db()->query($sql)->fetchAll();
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$requests = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
@ -117,6 +149,49 @@ $requests = db()->query($sql)->fetchAll();
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Filter & Search Form -->
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="row g-3 align-items-center">
|
||||
<input type="hidden" name="tab" value="<?= htmlspecialchars($tab) ?>">
|
||||
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="search" class="form-control" placeholder="بحث باسم الموظف أو السبب..." value="<?= htmlspecialchars($search) ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<select name="filter_type" class="form-select">
|
||||
<option value="">-- كل الأنواع --</option>
|
||||
<option value="annual" <?= $filter_type === 'annual' ? 'selected' : '' ?>>سنوية</option>
|
||||
<option value="sick" <?= $filter_type === 'sick' ? 'selected' : '' ?>>مرضية</option>
|
||||
<option value="unpaid" <?= $filter_type === 'unpaid' ? 'selected' : '' ?>>بدون راتب</option>
|
||||
<option value="maternity" <?= $filter_type === 'maternity' ? 'selected' : '' ?>>أمومة</option>
|
||||
<option value="emergency" <?= $filter_type === 'emergency' ? 'selected' : '' ?>>طارئة</option>
|
||||
<option value="other" <?= $filter_type === 'other' ? 'selected' : '' ?>>أخرى</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<?php if ($tab === 'all'): ?>
|
||||
<div class="col-md-3">
|
||||
<select name="filter_status" class="form-select">
|
||||
<option value="">-- كل الحالات --</option>
|
||||
<option value="pending" <?= $filter_status === 'pending' ? 'selected' : '' ?>>معلقة</option>
|
||||
<option value="approved" <?= $filter_status === 'approved' ? 'selected' : '' ?>>مقبولة</option>
|
||||
<option value="rejected" <?= $filter_status === 'rejected' ? 'selected' : '' ?>>مرفوضة</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="col-md-2 d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary flex-grow-1"><i class="fas fa-search"></i> بحث</button>
|
||||
<?php if ($search || $filter_type || $filter_status): ?>
|
||||
<a href="?tab=<?= htmlspecialchars($tab) ?>" class="btn btn-outline-secondary">إلغاء</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@ -212,7 +287,10 @@ $requests = db()->query($sql)->fetchAll();
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<?php renderPagination($page, $totalFiltered, $limit); ?>
|
||||
<?php
|
||||
$totalPages = ceil($totalFiltered / $limit);
|
||||
echo renderPagination($page, $totalPages);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -578,6 +578,7 @@ $is_admin_open = in_array($cp, $admin_pages);
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="userMenu">
|
||||
<li><a class="dropdown-item" href="profile.php"><i class="fas fa-user-circle me-2 text-muted"></i> ملفي الشخصي</a></li>
|
||||
<li><a class="dropdown-item" href="my_leaves.php"><i class="fas fa-calendar-day me-2 text-muted"></i> إجازاتي</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item text-danger" href="logout.php"><i class="fas fa-sign-out-alt me-2"></i> تسجيل الخروج</a></li>
|
||||
</ul>
|
||||
|
||||
215
my_leaves.php
Normal file
215
my_leaves.php
Normal file
@ -0,0 +1,215 @@
|
||||
<?php
|
||||
require_once 'includes/header.php';
|
||||
require_once 'includes/pagination.php';
|
||||
|
||||
// Only logged in users can access this page
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo "<div class='alert alert-danger'>يرجى تسجيل الدخول.</div>";
|
||||
require_once 'includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$error = '';
|
||||
$success = '';
|
||||
if (isset($_SESSION["success"])) {
|
||||
$success = $_SESSION["success"];
|
||||
unset($_SESSION["success"]);
|
||||
}
|
||||
|
||||
// Check if current user is linked to an employee
|
||||
$stmt = db()->prepare("SELECT id, first_name, last_name, department_id FROM hr_employees WHERE user_id = ? AND status = 'active'");
|
||||
$stmt->execute([$user_id]);
|
||||
$employee = $stmt->fetch();
|
||||
|
||||
if (!$employee) {
|
||||
echo "<div class='container mt-5'><div class='alert alert-warning text-center'>";
|
||||
echo "<i class='fas fa-exclamation-triangle fa-3x mb-3 text-warning'></i><br>";
|
||||
echo "<h4>لم يتم العثور على ملف موظف مرتبط بحسابك</h4>";
|
||||
echo "<p>يرجى التواصل مع قسم الموارد البشرية لربط حسابك بملف الموظف الخاص بك لتتمكن من تقديم طلبات الإجازات.</p>";
|
||||
echo "</div></div>";
|
||||
require_once 'includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
$emp_id = $employee['id'];
|
||||
|
||||
// Handle Form Submissions
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['request_leave'])) {
|
||||
$type = $_POST['leave_type'];
|
||||
$start = $_POST['start_date'];
|
||||
$end = $_POST['end_date'];
|
||||
$reason = trim($_POST['reason']);
|
||||
|
||||
$start_dt = new DateTime($start);
|
||||
$end_dt = new DateTime($end);
|
||||
$days = $end_dt->diff($start_dt)->days + 1;
|
||||
|
||||
if ($days <= 0) {
|
||||
$error = "تاريخ النهاية يجب أن يكون بعد أو نفس تاريخ البداية.";
|
||||
} else {
|
||||
try {
|
||||
$stmt = db()->prepare("INSERT INTO hr_leaves (employee_id, leave_type, start_date, end_date, days_count, reason, status) VALUES (?, ?, ?, ?, ?, ?, 'pending')");
|
||||
$stmt->execute([$emp_id, $type, $start, $end, $days, $reason]);
|
||||
$_SESSION["success"] = "تم تقديم طلب الإجازة بنجاح، بانتظار الاعتماد."; header("Location: my_leaves.php"); exit;
|
||||
} catch (PDOException $e) {
|
||||
$error = "حدث خطأ أثناء تقديم الطلب: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pagination
|
||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
if ($page < 1) $page = 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
// Fetch My Leaves
|
||||
$countStmt = db()->prepare("SELECT COUNT(*) FROM hr_leaves WHERE employee_id = ?");
|
||||
$countStmt->execute([$emp_id]);
|
||||
$totalFiltered = $countStmt->fetchColumn();
|
||||
|
||||
$sql = "SELECT l.*, u.full_name as approver_name
|
||||
FROM hr_leaves l
|
||||
LEFT JOIN users u ON l.approved_by = u.id
|
||||
WHERE l.employee_id = ?
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute([$emp_id]);
|
||||
$requests = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2"><i class="fas fa-calendar-day text-primary me-2"></i> إجازاتي</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#leaveModal">
|
||||
<i class="fas fa-plus"></i> تقديم طلب إجازة
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success"><?= htmlspecialchars($success) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>نوع الإجازة</th>
|
||||
<th>الفترة</th>
|
||||
<th>المدة</th>
|
||||
<th>السبب</th>
|
||||
<th>تاريخ التقديم</th>
|
||||
<th>الحالة</th>
|
||||
<th>المعتمد</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($requests)): ?>
|
||||
<tr><td colspan="7" class="text-center py-4 text-muted">لا توجد طلبات إجازات سابقة.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($requests as $req): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$type_map = [
|
||||
'annual' => 'سنوية',
|
||||
'sick' => 'مرضية',
|
||||
'unpaid' => 'بدون راتب',
|
||||
'maternity' => 'أمومة',
|
||||
'emergency' => 'طارئة',
|
||||
'other' => 'أخرى'
|
||||
];
|
||||
echo $type_map[$req['leave_type']] ?? $req['leave_type'];
|
||||
?>
|
||||
</td>
|
||||
<td class="small">
|
||||
من <?= $req['start_date'] ?><br>إلى <?= $req['end_date'] ?>
|
||||
</td>
|
||||
<td><?= $req['days_count'] ?> يوم</td>
|
||||
<td class="text-truncate" style="max-width: 150px;"><?= htmlspecialchars($req['reason']) ?></td>
|
||||
<td class="small"><?= date('Y-m-d', strtotime($req['created_at'])) ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$status_cls = match($req['status']) {
|
||||
'approved' => 'success',
|
||||
'rejected' => 'danger',
|
||||
default => 'warning'
|
||||
};
|
||||
$status_txt = match($req['status']) {
|
||||
'approved' => 'مقبولة',
|
||||
'rejected' => 'مرفوضة',
|
||||
default => 'معلقة'
|
||||
};
|
||||
?>
|
||||
<span class="badge bg-<?= $status_cls ?>"><?= $status_txt ?></span>
|
||||
</td>
|
||||
<td class="small"><?= $req['status'] === 'pending' ? '-' : htmlspecialchars($req['approver_name'] ?? 'مدير النظام') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<?php echo renderPagination($page, ceil($totalFiltered / $limit)); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Leave Request Modal -->
|
||||
<div class="modal fade" id="leaveModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">تقديم طلب إجازة جديد</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="post">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">نوع الإجازة</label>
|
||||
<select name="leave_type" class="form-select" required>
|
||||
<option value="annual">سنوية</option>
|
||||
<option value="sick">مرضية</option>
|
||||
<option value="emergency">طارئة</option>
|
||||
<option value="unpaid">بدون راتب</option>
|
||||
<option value="maternity">أمومة</option>
|
||||
<option value="other">أخرى</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col">
|
||||
<label class="form-label">من تاريخ</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">إلى تاريخ</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">السبب</label>
|
||||
<textarea name="reason" class="form-control" rows="3" placeholder="سبب الإجازة... (اختياري)"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||
<button type="submit" name="request_leave" class="btn btn-primary">تقديم الطلب</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once 'includes/footer.php'; ?>
|
||||
@ -311,11 +311,7 @@ if ($type == 'internal') {
|
||||
<label class="text-muted small">الرسالة / الوصف</label>
|
||||
<div class="bg-light p-3 rounded border">
|
||||
<?php
|
||||
if ($type == 'outbound' || $type == 'internal') {
|
||||
echo $mail['description'] ?: '<span class="text-muted">لا يوجد محتوى إضافي</span>';
|
||||
} else {
|
||||
echo nl2br(htmlspecialchars($mail['description'] ?: 'لا يوجد محتوى إضافي'));
|
||||
}
|
||||
echo $mail['description'] ?: '<span class="text-muted">لا يوجد محتوى إضافي</span>';
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
@ -512,4 +508,4 @@ if ($type == 'internal') {
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user