diff --git a/assets/css/custom.css b/assets/css/custom.css
index e4322e1..06fb23e 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -522,3 +522,4 @@ body {
color: #fff;
}
.group-meetings { color: #20c997 !important; } /* Teal */
+.group-committees { color: #8e24aa !important; } /* Purple */
diff --git a/charity_members.php b/charity_members.php
new file mode 100644
index 0000000..44f93f1
--- /dev/null
+++ b/charity_members.php
@@ -0,0 +1,260 @@
+غير مصرح لك بالوصول لهذه الصفحة.";
+ require_once 'includes/footer.php';
+ exit;
+}
+
+$action = $_GET['action'] ?? 'list';
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ if (isset($_POST['add_member']) && (isAdmin() || canAdd('committees'))) {
+ $name = $_POST['name'] ?? '';
+ $role = $_POST['role'] ?? '';
+ $phone = $_POST['phone'] ?? '';
+ $email = $_POST['email'] ?? '';
+ $join_date = $_POST['join_date'] ?? date('Y-m-d');
+ $status = $_POST['status'] ?? 'active';
+
+ $stmt = db()->prepare("INSERT INTO charity_members (name, role, phone, email, join_date, status) VALUES (?, ?, ?, ?, ?, ?)");
+ $stmt->execute([$name, $role, $phone, $email, $join_date, $status]);
+
+ $_SESSION['success'] = "تمت إضافة العضو بنجاح.";
+ redirect('charity_members.php');
+ } elseif (isset($_POST['edit_member']) && (isAdmin() || canEdit('committees'))) {
+ $id = $_POST['id'];
+ $name = $_POST['name'] ?? '';
+ $role = $_POST['role'] ?? '';
+ $phone = $_POST['phone'] ?? '';
+ $email = $_POST['email'] ?? '';
+ $join_date = $_POST['join_date'] ?? date('Y-m-d');
+ $status = $_POST['status'] ?? 'active';
+
+ $stmt = db()->prepare("UPDATE charity_members SET name = ?, role = ?, phone = ?, email = ?, join_date = ?, status = ? WHERE id = ?");
+ $stmt->execute([$name, $role, $phone, $email, $join_date, $status, $id]);
+
+ $_SESSION['success'] = "تم تحديث العضو بنجاح.";
+ redirect('charity_members.php');
+ } elseif (isset($_POST['delete_member']) && (isAdmin() || canDelete('committees'))) {
+ $id = $_POST['id'];
+ $stmt = db()->prepare("DELETE FROM charity_members WHERE id = ?");
+ $stmt->execute([$id]);
+
+ $_SESSION['success'] = "تم حذف العضو بنجاح.";
+ redirect('charity_members.php');
+ }
+}
+
+// Fetch members
+$stmt = db()->query("SELECT * FROM charity_members ORDER BY name ASC");
+$members = $stmt->fetchAll();
+?>
+
+
+
أعضاء الجمعية
+
+
+ إضافة عضو جديد
+
+
+
+
+
+
+ = htmlspecialchars($_SESSION['success']) ?>
+
+
+
+
+
+
+
+
+
+
+
+ الاسم
+ الدور/الصفة
+ رقم الجوال
+ البريد الإلكتروني
+ تاريخ الانضمام
+ الحالة
+ الإجراءات
+
+
+
+
+
+
+
+
+
+
+
+
= htmlspecialchars($member['name']) ?>
+
+
+
+ = htmlspecialchars($member['role']) ?>
+ = htmlspecialchars($member['phone']) ?>
+ = htmlspecialchars($member['email']) ?>
+ = htmlspecialchars($member['join_date']) ?>
+
+
+ نشط
+
+ غير نشط
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
هل أنت متأكد؟
+
هل تريد حقاً حذف العضو "= htmlspecialchars($member['name']) ?>"؟ لا يمكن التراجع عن هذا الإجراء وسيتم حذفه من أي لجان مرتبط بها.
+
+
+
+
+
+
+
+
+ لا يوجد أعضاء مضافين حتى الآن
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/charity_plans.php b/charity_plans.php
new file mode 100644
index 0000000..1bf18f9
--- /dev/null
+++ b/charity_plans.php
@@ -0,0 +1,357 @@
+غير مصرح لك بالوصول لهذه الصفحة.";
+ require_once 'includes/footer.php';
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ if (isset($_POST['add_plan']) && (isAdmin() || canAdd('committees'))) {
+ $title = $_POST['title'];
+ $description = $_POST['description'] ?? '';
+ $start_date = $_POST['start_date'] ?? date('Y-m-d');
+ $end_date = $_POST['end_date'] ?? date('Y-m-d', strtotime('+1 month'));
+ $target_value = (int)$_POST['target_value'];
+ $achieved_value = (int)($_POST['achieved_value'] ?? 0);
+ $status = $_POST['status'] ?? 'pending';
+
+ $stmt = db()->prepare("INSERT INTO charity_plans (title, description, start_date, end_date, target_value, achieved_value, status) VALUES (?, ?, ?, ?, ?, ?, ?)");
+ $stmt->execute([$title, $description, $start_date, $end_date, $target_value, $achieved_value, $status]);
+ $_SESSION['success'] = "تمت إضافة الخطة بنجاح.";
+ redirect('charity_plans.php');
+ } elseif (isset($_POST['edit_plan']) && (isAdmin() || canEdit('committees'))) {
+ $id = $_POST['id'];
+ $title = $_POST['title'];
+ $description = $_POST['description'] ?? '';
+ $start_date = $_POST['start_date'] ?? date('Y-m-d');
+ $end_date = $_POST['end_date'] ?? date('Y-m-d');
+ $target_value = (int)$_POST['target_value'];
+ $achieved_value = (int)($_POST['achieved_value'] ?? 0);
+ $status = $_POST['status'] ?? 'pending';
+
+ $stmt = db()->prepare("UPDATE charity_plans SET title = ?, description = ?, start_date = ?, end_date = ?, target_value = ?, achieved_value = ?, status = ? WHERE id = ?");
+ $stmt->execute([$title, $description, $start_date, $end_date, $target_value, $achieved_value, $status, $id]);
+ $_SESSION['success'] = "تم تحديث الخطة بنجاح.";
+ redirect('charity_plans.php');
+ } elseif (isset($_POST['delete_plan']) && (isAdmin() || canDelete('committees'))) {
+ $id = $_POST['id'];
+ $stmt = db()->prepare("DELETE FROM charity_plans WHERE id = ?");
+ $stmt->execute([$id]);
+ $_SESSION['success'] = "تم حذف الخطة بنجاح.";
+ redirect('charity_plans.php');
+ }
+}
+
+$stmt = db()->query("SELECT * FROM charity_plans ORDER BY created_at DESC");
+$plans = $stmt->fetchAll();
+
+$total_plans = count($plans);
+$completed_plans = 0;
+$total_target = 0;
+$total_achieved = 0;
+
+foreach ($plans as $plan) {
+ if ($plan['status'] === 'completed') {
+ $completed_plans++;
+ }
+ $total_target += $plan['target_value'];
+ $total_achieved += $plan['achieved_value'];
+}
+
+$completion_rate = $total_plans > 0 ? round(($completed_plans / $total_plans) * 100) : 0;
+$kpi_score = $total_target > 0 ? min(100, round(($total_achieved / $total_target) * 100)) : 0;
+$overall_score = round(($completion_rate * 0.4) + ($kpi_score * 0.6));
+
+$status_colors = [
+ 'pending' => 'secondary',
+ 'in_progress' => 'warning',
+ 'completed' => 'success',
+ 'cancelled' => 'danger'
+];
+$status_labels = [
+ 'pending' => 'قيد الانتظار',
+ 'in_progress' => 'قيد التنفيذ',
+ 'completed' => 'مكتمل',
+ 'cancelled' => 'ملغي'
+];
+?>
+
+
+
خطط وتقييم الجمعية (KPI)
+
+
+ إضافة خطة/هدف جديد
+
+
+
+
+
+
+ = htmlspecialchars($_SESSION['success']) ?>
+
+
+
+
+
+
+
+
+
+
التقييم العام للجمعية
+
= $overall_score ?>%
+
+ = 85): ?>
+ أداء متميز
+ = 60): ?>
+ أداء جيد
+
+ بحاجة لتحسين
+
+
+
+
+
+
+
معدل الإنجاز (المستهدف)
+
+
+
+
+ = $kpi_score ?>%
+
+
+
إجمالي المحقق: = $total_achieved ?> من = $total_target ?>
+
+
+
+
+
إنجاز الخطط (الحالة)
+
+
+
+
+ = $completion_rate ?>%
+
+
+
خطط مكتملة: = $completed_plans ?> من = $total_plans ?>
+
+
+
+
+
+
+
+
+
+
+
+
+ عنوان الخطة / الهدف
+ الفترة
+ المستهدف
+ المحقق
+ النسبة
+ الحالة
+ الإجراءات
+
+
+
+ 0 ? min(100, round(($plan['achieved_value'] / $plan['target_value']) * 100)) : 0;
+ ?>
+
+
+ = htmlspecialchars($plan['title']) ?>
+ = htmlspecialchars($plan['description']) ?>
+
+
+ من: = $plan['start_date'] ?>
+ إلى: = $plan['end_date'] ?>
+
+ = number_format($plan['target_value']) ?>
+ = number_format($plan['achieved_value']) ?>
+
+
+ = $plan_rate ?>%
+
+
+
+ = $status_labels[$plan['status']] ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
هل أنت متأكد؟
+
لن تتمكن من استعادة هذه الخطة بعد حذفها.
+
+
+
+
+
+
+
+
+ لا توجد خطط مضافة حتى الآن
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ العنوان
+
+
+
+ الوصف
+
+
+
+
+
+
الرقم المستهدف (KPI)
+
+
مثال: 100 (للتعبير عن 100 يتيم أو 100%)
+
+
+ الرقم المحقق الفعلي
+
+
+
+
+ الحالة
+
+ قيد الانتظار
+ قيد التنفيذ
+ مكتمل
+ ملغي
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/committee_reports.php b/committee_reports.php
new file mode 100644
index 0000000..595c745
--- /dev/null
+++ b/committee_reports.php
@@ -0,0 +1,211 @@
+لا توجد صلاحية للوصول لهذه الصفحة.";
+ require_once 'includes/footer.php';
+ exit;
+}
+
+// Fetch all committees and calculate stats
+$stmt = db()->query("
+ SELECT
+ c.id, c.name,
+ (SELECT COUNT(*) FROM committee_members WHERE committee_id = c.id) as members_count,
+ (SELECT COUNT(*) FROM committee_plans WHERE committee_id = c.id) as total_plans,
+ (SELECT COUNT(*) FROM committee_plans WHERE committee_id = c.id AND status = 'completed') as completed_plans,
+ (SELECT COUNT(*) FROM committee_activities WHERE committee_id = c.id) as activities_count
+ FROM committees c
+ ORDER BY c.name ASC
+");
+$committees = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+// Overall stats
+$total_committees = count($committees);
+$total_members = 0;
+$total_plans = 0;
+$total_completed = 0;
+$total_activities = 0;
+
+foreach ($committees as &$c) {
+ $total_members += $c['members_count'];
+ $total_plans += $c['total_plans'];
+ $total_completed += $c['completed_plans'];
+ $total_activities += $c['activities_count'];
+
+ // Calculate performance score (smart assessment)
+ // Score based on: Completed plans (weight 60%) + Activities done (weight 40%)
+ // Let's make a simple normalized score out of 100 for visual assessment
+ $plan_completion_rate = $c['total_plans'] > 0 ? ($c['completed_plans'] / $c['total_plans']) * 100 : 0;
+
+ // Assume an "active" committee should have at least 1 activity per month (say 5 is a good baseline for 100% activity score)
+ $activity_score = min(100, $c['activities_count'] * 20);
+
+ // Final composite score
+ $score = ($plan_completion_rate * 0.6) + ($activity_score * 0.4);
+ $c['score'] = $score;
+
+ // Determine badge
+ if ($score >= 80) {
+ $c['badge'] = 'ممتاز ';
+ $c['color'] = 'success';
+ } elseif ($score >= 50) {
+ $c['badge'] = 'جيد ';
+ $c['color'] = 'primary';
+ } elseif ($score > 0) {
+ $c['badge'] = 'يحتاج تحسين ';
+ $c['color'] = 'warning';
+ } else {
+ $c['badge'] = 'غير نشط ';
+ $c['color'] = 'danger';
+ }
+}
+unset($c);
+
+// Sort by score descending to rank them
+usort($committees, function($a, $b) {
+ return $b['score'] <=> $a['score'];
+});
+
+?>
+
+
+
+
تقييم وتقارير اللجان
+
+
+
+
+
+
+
+
+
+
+
+
+
إجمالي اللجان
+ = $total_committees ?>
+
+
+
+
+
+
+
+
إنجاز الخطط
+
+ = $total_plans > 0 ? round(($total_completed / $total_plans) * 100) : 0 ?>%
+
+ = $total_completed ?> من = $total_plans ?> خطة مكتملة
+
+
+
+
+
+
+
+
إجمالي الأنشطة
+ = $total_activities ?>
+
+
+
+
+
+
+
+
إجمالي الأعضاء
+ = $total_members ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ الترتيب
+ اللجنة
+ الأعضاء
+ إنجاز الخطط
+ الأنشطة المنجزة
+ مؤشر الأداء (KPI)
+ التقييم
+
+
+
+
+
+ لا توجد لجان مضافة حتى الآن.
+
+ $c): ?>
+
+
+ 0): ?>
+
+ 0): ?>
+
+ 0): ?>
+
+
+ #= $index + 1 ?>
+
+
+ = htmlspecialchars($c['name']) ?>
+
+ = $c['members_count'] ?>
+
+
+
+
= $c['completed_plans'] ?> / = $c['total_plans'] ?>
+
+ 0 ? ($c['completed_plans'] / $c['total_plans']) * 100 : 0; ?>
+
+
+
+
+
+ = $c['activities_count'] ?>
+
+
+
+ نسبة الإنجاز:
+ = round($c['score']) ?>%
+
+
+
+
+ = $c['badge'] ?>
+
+
+
+ تقرير مفصل
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/committees.php b/committees.php
new file mode 100644
index 0000000..a8a8db1
--- /dev/null
+++ b/committees.php
@@ -0,0 +1,203 @@
+prepare("INSERT INTO committees (name, description) VALUES (?, ?)");
+ $stmt->execute([$name, $description]);
+ $_SESSION['success'] = 'تم إضافة اللجنة بنجاح';
+ }
+ } elseif ($action === 'edit' && $id && canEdit('committees')) {
+ if (empty($name)) {
+ $_SESSION['error'] = 'اسم اللجنة مطلوب';
+ } else {
+ $stmt = $db->prepare("UPDATE committees SET name = ?, description = ? WHERE id = ?");
+ $stmt->execute([$name, $description, $id]);
+ $_SESSION['success'] = 'تم تحديث اللجنة بنجاح';
+ }
+ }
+ } catch (PDOException $e) {
+ $_SESSION['error'] = 'حدث خطأ: ' . $e->getMessage();
+ }
+ redirect('committees.php');
+ }
+}
+
+if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
+ if (!canDelete('committees')) redirect('committees.php');
+ $id = $_GET['id'];
+ try {
+ $db = db();
+ $stmt = $db->prepare("DELETE FROM committees WHERE id = ?");
+ $stmt->execute([$id]);
+ $_SESSION['success'] = 'تم حذف اللجنة بنجاح';
+ } catch (PDOException $e) {
+ $_SESSION['error'] = 'حدث خطأ: ' . $e->getMessage();
+ }
+ redirect('committees.php');
+}
+
+$committees = db()->query("SELECT * FROM committees ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC);
+
+if (isset($_SESSION['success'])) {
+ $success = $_SESSION['success'];
+ unset($_SESSION['success']);
+}
+if (isset($_SESSION['error'])) {
+ $error = $_SESSION['error'];
+ unset($_SESSION['error']);
+}
+?>
+
+
+
اللجان
+
+
+ إضافة لجنة جديدة
+
+
+
+
+
+
+ = $success ?>
+
+
+
+
+
+
+ = $error ?>
+
+
+
+
+
+
+
+
+
+
+ الرقم
+ اسم اللجنة
+ الوصف
+ الإجراءات
+
+
+
+ 0): ?>
+
+
+ = htmlspecialchars($committee['id']) ?>
+ = htmlspecialchars($committee['name']) ?>
+ = htmlspecialchars($committee['description'] ?? '') ?>
+
+ إدارة
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ لا توجد لجان مضافة حتى الآن.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ اسم اللجنة *
+
+
+
+
+ الوصف
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/db/migrations/030_add_committees_module.sql b/db/migrations/030_add_committees_module.sql
new file mode 100644
index 0000000..f094c4d
--- /dev/null
+++ b/db/migrations/030_add_committees_module.sql
@@ -0,0 +1,7 @@
+CREATE TABLE IF NOT EXISTS `committees` (
+ `id` INT AUTO_INCREMENT PRIMARY KEY,
+ `name` VARCHAR(255) NOT NULL,
+ `description` TEXT,
+ `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
\ No newline at end of file
diff --git a/db/migrations/031_add_committee_details.sql b/db/migrations/031_add_committee_details.sql
new file mode 100644
index 0000000..3261f15
--- /dev/null
+++ b/db/migrations/031_add_committee_details.sql
@@ -0,0 +1,35 @@
+CREATE TABLE IF NOT EXISTS committee_members (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ committee_id INT NOT NULL,
+ user_id INT NOT NULL,
+ role VARCHAR(100) DEFAULT 'عضو',
+ joined_at DATE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (committee_id) REFERENCES committees(id) ON DELETE CASCADE,
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
+ UNIQUE KEY unique_member (committee_id, user_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS committee_plans (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ committee_id INT NOT NULL,
+ title VARCHAR(255) NOT NULL,
+ description TEXT,
+ start_date DATE,
+ end_date DATE,
+ status ENUM('pending', 'in_progress', 'completed', 'cancelled') DEFAULT 'pending',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ FOREIGN KEY (committee_id) REFERENCES committees(id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS committee_activities (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ committee_id INT NOT NULL,
+ title VARCHAR(255) NOT NULL,
+ description TEXT,
+ activity_date DATE,
+ location VARCHAR(255),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (committee_id) REFERENCES committees(id) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
\ No newline at end of file
diff --git a/db/migrations/032_add_charity_members_plans.sql b/db/migrations/032_add_charity_members_plans.sql
new file mode 100644
index 0000000..94c23cc
--- /dev/null
+++ b/db/migrations/032_add_charity_members_plans.sql
@@ -0,0 +1,38 @@
+CREATE TABLE IF NOT EXISTS charity_members (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ role VARCHAR(100),
+ phone VARCHAR(50),
+ email VARCHAR(100),
+ join_date DATE,
+ status ENUM('active', 'inactive') DEFAULT 'active',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS charity_plans (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(255) NOT NULL,
+ description TEXT,
+ start_date DATE,
+ end_date DATE,
+ target_value INT DEFAULT 100,
+ achieved_value INT DEFAULT 0,
+ status ENUM('pending', 'in_progress', 'completed', 'cancelled') DEFAULT 'pending',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+DROP TABLE IF EXISTS committee_members;
+
+CREATE TABLE IF NOT EXISTS committee_members (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ committee_id INT NOT NULL,
+ charity_member_id INT NOT NULL,
+ role VARCHAR(100) DEFAULT 'عضو',
+ joined_at DATE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (committee_id) REFERENCES committees(id) ON DELETE CASCADE,
+ FOREIGN KEY (charity_member_id) REFERENCES charity_members(id) ON DELETE CASCADE,
+ UNIQUE KEY unique_member (committee_id, charity_member_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
\ No newline at end of file
diff --git a/hr_zkteco.php b/hr_zkteco.php
index 135e5a4..4b9480b 100644
--- a/hr_zkteco.php
+++ b/hr_zkteco.php
@@ -1,6 +1,12 @@
خطأ: مجلد vendor غير موجود على الاستضافة. يرجى التأكد من رفع مجلد المكتبات (vendor) مع باقي ملفات النظام، أو تنفيذ أمر composer install إذا كنت تستخدم سطر الأوامر.
";
+ require_once 'includes/footer.php';
+ exit;
+}
+require $autoloadPath;
use Rats\Zkteco\Lib\ZKTeco;
diff --git a/includes/header.php b/includes/header.php
index 5cb6107..331e3e8 100644
--- a/includes/header.php
+++ b/includes/header.php
@@ -73,6 +73,13 @@ $is_stock_open = in_array($cp, $stock_pages);
$expenses_pages = ['expenses.php', 'expense_categories.php', 'expense_reports.php'];
$is_expenses_open = in_array($cp, $expenses_pages);
+$charity_pages = ['charity_members.php', 'charity_plans.php'];
+$is_charity_open = in_array($cp, $charity_pages);
+
+$committees_pages = ["committees.php", "view_committee.php", "committee_reports.php", "print_committees_report.php"];
+$is_committees_open = in_array($cp, $committees_pages);
+
+
$meetings_pages = ['meetings.php'];
$is_meetings_open = in_array($cp, $meetings_pages);
@@ -470,6 +477,59 @@ $is_admin_open = in_array($cp, $admin_pages);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/print_committees_report.php b/print_committees_report.php
new file mode 100644
index 0000000..73f5231
--- /dev/null
+++ b/print_committees_report.php
@@ -0,0 +1,165 @@
+query("
+ SELECT
+ c.id, c.name, c.description,
+ (SELECT COUNT(*) FROM committee_plans WHERE committee_id = c.id) as total_plans,
+ (SELECT COUNT(*) FROM committee_plans WHERE committee_id = c.id AND status = 'completed') as completed_plans,
+ (SELECT COUNT(*) FROM committee_activities WHERE committee_id = c.id) as activities_count
+ FROM committees c
+ ORDER BY c.name ASC
+");
+$committees = $committees_query->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($committees as &$c) {
+ // Calculate performance score
+ $plan_completion_rate = $c['total_plans'] > 0 ? ($c['completed_plans'] / $c['total_plans']) * 100 : 0;
+ $activity_score = min(100, $c['activities_count'] * 20);
+ $c['score'] = ($plan_completion_rate * 0.6) + ($activity_score * 0.4);
+
+ // Fetch members for this committee
+ $members_stmt = $db->prepare("
+ SELECT cm.role, u.name as full_name, u.phone
+ FROM committee_members cm
+ JOIN charity_members u ON cm.charity_member_id = u.id
+ WHERE cm.committee_id = ?
+ ORDER BY cm.id DESC
+ ");
+ $members_stmt->execute([$c['id']]);
+ $c['members'] = $members_stmt->fetchAll(PDO::FETCH_ASSOC);
+}
+unset($c);
+
+// Sort by score descending
+usort($committees, function($a, $b) {
+ return $b['score'] <=> $a['score'];
+});
+
+?>
+
+
+
+
+
+ تقرير اللجان والأعضاء
+
+
+
+
+
+
+
+ طباعة التقرير
+ إغلاق
+
+
+
+
+
+
تقرير تفصيلي بأسماء اللجان وأعضائها
+
+
+
لا توجد لجان مسجلة في النظام.
+
+ $c): ?>
+
+
+
+ = $index + 1 ?>. = htmlspecialchars($c['name']) ?>
+
+
+ مؤشر الأداء (KPI): = round($c['score']) ?>%
+
+
+
+
+ = htmlspecialchars($c['description']) ?: 'لا يوجد وصف' ?>
+
+
+
+ إجمالي الخطط: = $c['total_plans'] ?>
+ الخطط المكتملة: = $c['completed_plans'] ?>
+ إجمالي الأنشطة: = $c['activities_count'] ?>
+
+
+ 0): ?>
+
+
+
+ م
+ اسم العضو
+ الدور في اللجنة
+ رقم الهاتف
+
+
+
+ $m): ?>
+
+ = $m_index + 1 ?>
+ = htmlspecialchars($m['full_name']) ?>
+ = htmlspecialchars($m['role']) ?>
+ = htmlspecialchars($m['phone'] ?? '-') ?>
+
+
+
+
+
+
لا يوجد أعضاء مسجلين في هذه اللجنة حالياً.
+
+
+
+
+
+
+
+ هذا التقرير معتمد ومستخرج آلياً من نظام إدارة اللجان - = htmlspecialchars($settings['site_name']) ?>
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/users.php b/users.php
index 621b3d6..90677fd 100644
--- a/users.php
+++ b/users.php
@@ -32,7 +32,8 @@ $modules = [
'stock_settings' => 'المخزون - الإعدادات',
'expenses' => 'المصروفات',
'expense_settings' => 'المصروفات - الإعدادات',
- 'meetings' => 'الاجتماعات'
+ 'meetings' => 'الاجتماعات',
+ 'committees' => 'اللجان'
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
diff --git a/view_committee.php b/view_committee.php
new file mode 100644
index 0000000..9373daf
--- /dev/null
+++ b/view_committee.php
@@ -0,0 +1,600 @@
+prepare("SELECT * FROM committees WHERE id = ?");
+$stmt->execute([$id]);
+$committee = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$committee) {
+ redirect('committees.php');
+}
+
+$tab = $_GET['tab'] ?? 'members';
+$allowed_tabs = ['members', 'plans', 'activities'];
+if (!in_array($tab, $allowed_tabs)) {
+ $tab = 'members';
+}
+
+$error = '';
+$success = '';
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $action = $_POST['action'] ?? '';
+
+ try {
+ if ($action === 'add_member' && canAdd('committees')) {
+ $charity_member_id = $_POST['charity_member_id'] ?? 0;
+ $role = trim($_POST['role'] ?? 'عضو');
+ if ($charity_member_id) {
+ $stmt = $db->prepare("INSERT INTO committee_members (committee_id, charity_member_id, role, joined_at) VALUES (?, ?, ?, CURDATE())");
+ $stmt->execute([$id, $charity_member_id, $role]);
+ $_SESSION['success'] = 'تم إضافة العضو بنجاح';
+ }
+ } elseif ($action === 'edit_member' && canEdit('committees')) {
+ $member_id = $_POST['member_id'] ?? 0;
+ $role = trim($_POST['role'] ?? 'عضو');
+ if ($member_id) {
+ $stmt = $db->prepare("UPDATE committee_members SET role = ? WHERE id = ?");
+ $stmt->execute([$role, $member_id]);
+ $_SESSION['success'] = 'تم تحديث دور العضو بنجاح';
+ }
+ } elseif ($action === 'delete_member' && canDelete('committees')) {
+ $member_id = $_POST['member_id'] ?? 0;
+ if ($member_id) {
+ $stmt = $db->prepare("DELETE FROM committee_members WHERE id = ?");
+ $stmt->execute([$member_id]);
+ $_SESSION['success'] = 'تم حذف العضو بنجاح';
+ }
+ } elseif ($action === 'add_plan' && canAdd('committees')) {
+ $title = trim($_POST['title'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+ $start_date = $_POST['start_date'] ?: null;
+ $end_date = $_POST['end_date'] ?: null;
+ if ($title) {
+ $stmt = $db->prepare("INSERT INTO committee_plans (committee_id, title, description, start_date, end_date) VALUES (?, ?, ?, ?, ?)");
+ $stmt->execute([$id, $title, $description, $start_date, $end_date]);
+ $_SESSION['success'] = 'تم إضافة الخطة بنجاح';
+ }
+ } elseif ($action === 'edit_plan' && canEdit('committees')) {
+ $plan_id = $_POST['plan_id'] ?? 0;
+ $title = trim($_POST['title'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+ $start_date = $_POST['start_date'] ?: null;
+ $end_date = $_POST['end_date'] ?: null;
+ $status = $_POST['status'] ?? 'pending';
+ if ($plan_id && $title) {
+ $stmt = $db->prepare("UPDATE committee_plans SET title = ?, description = ?, start_date = ?, end_date = ?, status = ? WHERE id = ?");
+ $stmt->execute([$title, $description, $start_date, $end_date, $status, $plan_id]);
+ $_SESSION['success'] = 'تم تحديث الخطة بنجاح';
+ }
+ } elseif ($action === 'delete_plan' && canDelete('committees')) {
+ $plan_id = $_POST['plan_id'] ?? 0;
+ if ($plan_id) {
+ $stmt = $db->prepare("DELETE FROM committee_plans WHERE id = ?");
+ $stmt->execute([$plan_id]);
+ $_SESSION['success'] = 'تم حذف الخطة بنجاح';
+ }
+ } elseif ($action === 'add_activity' && canAdd('committees')) {
+ $title = trim($_POST['title'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+ $activity_date = $_POST['activity_date'] ?: null;
+ $location = trim($_POST['location'] ?? '');
+ if ($title) {
+ $stmt = $db->prepare("INSERT INTO committee_activities (committee_id, title, description, activity_date, location) VALUES (?, ?, ?, ?, ?)");
+ $stmt->execute([$id, $title, $description, $activity_date, $location]);
+ $_SESSION['success'] = 'تم إضافة النشاط بنجاح';
+ }
+ } elseif ($action === 'edit_activity' && canEdit('committees')) {
+ $activity_id = $_POST['activity_id'] ?? 0;
+ $title = trim($_POST['title'] ?? '');
+ $description = trim($_POST['description'] ?? '');
+ $activity_date = $_POST['activity_date'] ?: null;
+ $location = trim($_POST['location'] ?? '');
+ if ($activity_id && $title) {
+ $stmt = $db->prepare("UPDATE committee_activities SET title = ?, description = ?, activity_date = ?, location = ? WHERE id = ?");
+ $stmt->execute([$title, $description, $activity_date, $location, $activity_id]);
+ $_SESSION['success'] = 'تم تحديث النشاط بنجاح';
+ }
+ } elseif ($action === 'delete_activity' && canDelete('committees')) {
+ $activity_id = $_POST['activity_id'] ?? 0;
+ if ($activity_id) {
+ $stmt = $db->prepare("DELETE FROM committee_activities WHERE id = ?");
+ $stmt->execute([$activity_id]);
+ $_SESSION['success'] = 'تم حذف النشاط بنجاح';
+ }
+ }
+ } catch (PDOException $e) {
+ $_SESSION['error'] = 'حدث خطأ: ' . $e->getMessage();
+ }
+ redirect("view_committee.php?id=$id&tab=$tab");
+}
+
+if (isset($_SESSION['success'])) {
+ $success = $_SESSION['success'];
+ unset($_SESSION['success']);
+}
+if (isset($_SESSION['error'])) {
+ $error = $_SESSION['error'];
+ unset($_SESSION['error']);
+}
+
+// Fetch tab data
+$members = [];
+$plans = [];
+$activities = [];
+
+if ($tab === 'members') {
+ $stmt = $db->prepare("SELECT cm.*, u.name as full_name, u.email, u.phone FROM committee_members cm JOIN charity_members u ON cm.charity_member_id = u.id WHERE cm.committee_id = ? ORDER BY cm.id DESC");
+ $stmt->execute([$id]);
+ $members = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ // Get available users to add
+ $member_ids = array_column($members, 'charity_member_id');
+ $not_in = count($member_ids) > 0 ? implode(',', array_map('intval', $member_ids)) : '0';
+ $available_users = $db->query("SELECT id, name as full_name, email FROM charity_members WHERE status = 'active' AND id NOT IN ($not_in) ORDER BY full_name ASC")->fetchAll(PDO::FETCH_ASSOC);
+} elseif ($tab === 'plans') {
+ $stmt = $db->prepare("SELECT * FROM committee_plans WHERE committee_id = ? ORDER BY id DESC");
+ $stmt->execute([$id]);
+ $plans = $stmt->fetchAll(PDO::FETCH_ASSOC);
+} elseif ($tab === 'activities') {
+ $stmt = $db->prepare("SELECT * FROM committee_activities WHERE committee_id = ? ORDER BY activity_date DESC, id DESC");
+ $stmt->execute([$id]);
+ $activities = $stmt->fetchAll(PDO::FETCH_ASSOC);
+}
+?>
+
+
+
إدارة اللجنة: = htmlspecialchars($committee['name']) ?>
+
+ عودة للجان
+
+
+
+
+
+ = $success ?>
+
+
+
+
+
+
+ = $error ?>
+
+
+
+
+= nl2br(htmlspecialchars($committee['description'])) ?>
+
+
+
+
+
+
+
+
+
+
+
+ الاسم
+ البريد الإلكتروني
+ الهاتف
+ الدور
+ تاريخ الانضمام
+ الإجراءات
+
+
+
+ 0): ?>
+
+
+ = htmlspecialchars($m['full_name']) ?>
+ = htmlspecialchars($m['email']) ?>
+ = htmlspecialchars($m['phone'] ?? '-' ) ?>
+ = htmlspecialchars($m['role']) ?>
+ = $m['joined_at'] ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ لا يوجد أعضاء في هذه اللجنة حالياً.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ المستخدم *
+
+ -- اختر مستخدم --
+
+ = htmlspecialchars($u['full_name']) ?> (= htmlspecialchars($u['email']) ?>)
+
+
+
+
+ الدور في اللجنة
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ الدور في اللجنة
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ عنوان الخطة
+ تاريخ البداية
+ تاريخ النهاية
+ الحالة
+ الإجراءات
+
+
+
+ 'secondary',
+ 'in_progress' => 'primary',
+ 'completed' => 'success',
+ 'cancelled' => 'danger'
+ ];
+ $status_labels = [
+ 'pending' => 'قيد الانتظار',
+ 'in_progress' => 'قيد التنفيذ',
+ 'completed' => 'مكتملة',
+ 'cancelled' => 'ملغاة'
+ ];
+ if (count($plans) > 0): ?>
+
+
+
+ = htmlspecialchars($p['title']) ?>
+ = htmlspecialchars($p['description'] ?? '') ?>
+
+ = $p['start_date'] ?: '-' ?>
+ = $p['end_date'] ?: '-' ?>
+ = $status_labels[$p['status']] ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ لا توجد خطط مضافة حالياً.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ عنوان الخطة *
+
+
+
+ الوصف
+
+
+
+
+ الحالة
+
+ قيد الانتظار
+ قيد التنفيذ
+ مكتملة
+ ملغاة
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ النشاط
+ التاريخ
+ الموقع
+ الإجراءات
+
+
+
+ 0): ?>
+
+
+
+ = htmlspecialchars($a['title']) ?>
+ = htmlspecialchars($a['description'] ?? '') ?>
+
+ = $a['activity_date'] ?: '-' ?>
+ = htmlspecialchars($a['location'] ?? '-') ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ لا توجد أنشطة مضافة حالياً.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ عنوان النشاط *
+
+
+
+ الوصف
+
+
+
+
+
+
+
+
+
+
+
+
+
+