update holydays

This commit is contained in:
Flatlogic Bot 2026-04-05 04:27:05 +00:00
parent 040f45e79d
commit 2603d90a7f
5 changed files with 320 additions and 18 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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
View 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'; ?>

View File

@ -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'; ?>