update charity all

This commit is contained in:
Flatlogic Bot 2026-04-13 05:29:49 +00:00
parent cbc388177e
commit f1fb1b1949
28 changed files with 346 additions and 75 deletions

View File

@ -237,10 +237,12 @@ $ledger = get_ledger_paginated($search, $date_from, $date_to, $limit, $offset);
<h3 class="text-right">دفتر الأستاذ (General Ledger)</h3>
<div class="table-responsive">
<table class="table table-hover table-bordered text-right align-middle table-sm">
<thead class="table-light"><tr><th>التاريخ</th><th>الوصف</th><th>المرجع</th><th>الحساب</th><th>مدين</th><th>دائن</th><th>الإجراءات</th></tr></thead>
<thead class="table-light"><tr><th>التاريخ</th><th>الوصف</th><th>المرجع</th><th>الحساب</th><th>مدين</th><th>دائن</th><th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>الإجراءات</th></tr></thead>
<tbody>
<?php if(empty($ledger)): ?>
<tr><td colspan="7" class="text-center">لا توجد قيود.</td></tr>
<tr><td colspan="9" class="text-center">لا توجد قيود.</td></tr>
<?php endif; ?>
<?php foreach ($ledger as $row): ?>
<tr>
@ -250,6 +252,8 @@ $ledger = get_ledger_paginated($search, $date_from, $date_to, $limit, $offset);
<td><?= htmlspecialchars($row['account_name']) ?></td>
<td><?= number_format($row['debit'], 2) ?></td>
<td><?= number_format($row['credit'], 2) ?></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['updated_by'] ?? null)) ?></small></td>
<td>
<button type="button" class="btn btn-sm btn-link text-warning p-0 me-2" title="تعديل" onclick="openEditModal(<?= $row['id'] ?>)"><i class="fas fa-edit"></i></button>

View File

@ -129,7 +129,9 @@ $typeMap = [
<tr>
<th>الاسم</th>
<th>النوع</th>
<th style="width: 120px; text-align: center;">إجراءات</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th style="width: 120px; text-align: center;">إجراءات</th>
</tr>
</thead>
<tbody>
@ -141,6 +143,8 @@ $typeMap = [
<?= htmlspecialchars($typeMap[$account['type']] ?? $account['type']) ?>
</span>
</td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($account['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($account['updated_by'] ?? null)) ?></small></td>
<td class="text-center">
<button class="btn btn-warning text-white btn-sm shadow-sm mx-1" onclick="editAccount(<?= $account['id'] ?>, '<?= htmlspecialchars($account['name'], ENT_QUOTES) ?>', '<?= htmlspecialchars($account['type'], ENT_QUOTES) ?>')" title="تعديل">
<i class="fas fa-pencil-alt"></i>

View File

@ -1,7 +1,7 @@
<?php
require_once 'includes/header.php';
if (!isAdmin() && !canView('committees')) {
if (!isAdmin() && !canView('charity_members')) {
echo "<div class='alert alert-danger'>غير مصرح لك بالوصول لهذه الصفحة.</div>";
require_once 'includes/footer.php';
exit;
@ -10,7 +10,7 @@ if (!isAdmin() && !canView('committees')) {
$action = $_GET['action'] ?? 'list';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['add_member']) && (isAdmin() || canAdd('committees'))) {
if (isset($_POST['add_member']) && (isAdmin() || canAdd('charity_members'))) {
$name = $_POST['name'] ?? '';
$role = $_POST['role'] ?? '';
$phone = $_POST['phone'] ?? '';
@ -23,7 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$_SESSION['success'] = "تمت إضافة العضو بنجاح.";
redirect('charity_members.php');
} elseif (isset($_POST['edit_member']) && (isAdmin() || canEdit('committees'))) {
} elseif (isset($_POST['edit_member']) && (isAdmin() || canEdit('charity_members'))) {
$id = $_POST['id'];
$name = $_POST['name'] ?? '';
$role = $_POST['role'] ?? '';
@ -37,7 +37,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$_SESSION['success'] = "تم تحديث العضو بنجاح.";
redirect('charity_members.php');
} elseif (isset($_POST['delete_member']) && (isAdmin() || canDelete('committees'))) {
} elseif (isset($_POST['delete_member']) && (isAdmin() || canDelete('charity_members'))) {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM charity_members WHERE id = ?");
$stmt->execute([$id]);
@ -58,7 +58,7 @@ $members = $stmt->fetchAll();
<a href="print_charity_report.php" target="_blank" class="btn btn-secondary me-2">
<i class="fas fa-print me-2"></i> طباعة تقرير الجمعية
</a>
<?php if (isAdmin() || canAdd('committees')): ?>
<?php if (isAdmin() || canAdd('charity_members')): ?>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addMemberModal">
<i class="fas fa-plus me-2"></i> إضافة عضو جديد
</button>
@ -86,6 +86,8 @@ $members = $stmt->fetchAll();
<th>البريد الإلكتروني</th>
<th>تاريخ الانضمام</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-end">الإجراءات</th>
</tr>
</thead>
@ -113,13 +115,15 @@ $members = $stmt->fetchAll();
<span class="badge bg-secondary bg-opacity-10 text-secondary px-3 py-2 rounded-pill">غير نشط</span>
<?php endif; ?>
</td>
<td class="text-end">
<?php if (isAdmin() || canEdit('committees')): ?>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($member['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($member['updated_by'] ?? null)) ?></small></td>
<td class="text-end">
<?php if (isAdmin() || canEdit('charity_members')): ?>
<button class="btn btn-sm btn-outline-primary me-2" data-bs-toggle="modal" data-bs-target="#editMemberModal<?= $member['id'] ?>">
<i class="fas fa-edit"></i>
</button>
<?php endif; ?>
<?php if (isAdmin() || canDelete('committees')): ?>
<?php if (isAdmin() || canDelete('charity_members')): ?>
<button class="btn btn-sm btn-outline-danger" data-bs-toggle="modal" data-bs-target="#deleteMemberModal<?= $member['id'] ?>">
<i class="fas fa-trash"></i>
</button>
@ -204,7 +208,7 @@ $members = $stmt->fetchAll();
<?php endforeach; ?>
<?php if (empty($members)): ?>
<tr>
<td colspan="7" class="text-center text-muted py-4">لا يوجد أعضاء مضافين حتى الآن</td>
<td colspan="9" class="text-center text-muted py-4">لا يوجد أعضاء مضافين حتى الآن</td>
</tr>
<?php endif; ?>
</tbody>

View File

@ -1,14 +1,14 @@
<?php
require_once 'includes/header.php';
if (!isAdmin() && !canView('committees')) {
if (!isAdmin() && !canView('charity_plans')) {
echo "<div class='alert alert-danger'>غير مصرح لك بالوصول لهذه الصفحة.</div>";
require_once 'includes/footer.php';
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['add_plan']) && (isAdmin() || canAdd('committees'))) {
if (isset($_POST['add_plan']) && (isAdmin() || canAdd('charity_plans'))) {
$title = $_POST['title'];
$description = $_POST['description'] ?? '';
$start_date = $_POST['start_date'] ?? date('Y-m-d');
@ -21,7 +21,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$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'))) {
} elseif (isset($_POST['edit_plan']) && (isAdmin() || canEdit('charity_plans'))) {
$id = $_POST['id'];
$title = $_POST['title'];
$description = $_POST['description'] ?? '';
@ -35,7 +35,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$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'))) {
} elseif (isset($_POST['delete_plan']) && (isAdmin() || canDelete('charity_plans'))) {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM charity_plans WHERE id = ?");
$stmt->execute([$id]);
@ -84,7 +84,7 @@ $status_labels = [
<a href="print_charity_report.php" target="_blank" class="btn btn-secondary me-2">
<i class="fas fa-print me-2"></i> طباعة تقرير الجمعية
</a>
<?php if (isAdmin() || canAdd('committees')): ?>
<?php if (isAdmin() || canAdd('charity_plans')): ?>
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addPlanModal">
<i class="fas fa-plus me-2"></i> إضافة خطة/هدف جديد
</button>
@ -161,6 +161,8 @@ $status_labels = [
<th>المحقق</th>
<th>النسبة</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-end">الإجراءات</th>
</tr>
</thead>
@ -190,13 +192,15 @@ $status_labels = [
<?= $status_labels[$plan['status']] ?>
</span>
</td>
<td class="text-end">
<?php if (isAdmin() || canEdit('committees')): ?>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($plan['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($plan['updated_by'] ?? null)) ?></small></td>
<td class="text-end">
<?php if (isAdmin() || canEdit('charity_plans')): ?>
<button class="btn btn-sm btn-outline-primary me-2" data-bs-toggle="modal" data-bs-target="#editPlanModal<?= $plan['id'] ?>">
<i class="fas fa-edit"></i>
</button>
<?php endif; ?>
<?php if (isAdmin() || canDelete('committees')): ?>
<?php if (isAdmin() || canDelete('charity_plans')): ?>
<button class="btn btn-sm btn-outline-danger" data-bs-toggle="modal" data-bs-target="#deletePlanModal<?= $plan['id'] ?>">
<i class="fas fa-trash"></i>
</button>
@ -290,7 +294,7 @@ $status_labels = [
<?php endforeach; ?>
<?php if (empty($plans)): ?>
<tr>
<td colspan="7" class="text-center text-muted py-4">لا توجد خطط مضافة حتى الآن</td>
<td colspan="9" class="text-center text-muted py-4">لا توجد خطط مضافة حتى الآن</td>
</tr>
<?php endif; ?>
</tbody>

View File

@ -8,17 +8,37 @@ if (!canView('committees')) {
}
// 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);
if (isAdmin()) {
$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);
} else {
$stmt = db()->prepare("
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
JOIN committee_members m ON c.id = m.committee_id
JOIN charity_members cm ON m.charity_member_id = cm.id
JOIN users u ON (u.id = cm.user_id) OR (cm.email != '' AND cm.email = u.email) OR (cm.name = u.full_name) OR (cm.name = u.username)
WHERE u.id = ?
GROUP BY c.id
ORDER BY c.name ASC
");
$stmt->execute([$_SESSION['user_id']]);
$committees = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// Overall stats
$total_committees = count($committees);

View File

@ -99,6 +99,8 @@ if (isset($_SESSION['error'])) {
<th class="ps-4" style="width: 80px;">الرقم</th>
<th>اسم اللجنة</th>
<th>الوصف</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center">الإجراءات</th>
</tr>
</thead>
@ -109,7 +111,9 @@ if (isset($_SESSION['error'])) {
<td class="ps-4"><?= htmlspecialchars($committee['id']) ?></td>
<td class="fw-bold"><?= htmlspecialchars($committee['name']) ?></td>
<td><?= htmlspecialchars($committee['description'] ?? '') ?></td>
<td class="text-center">
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($committee['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($committee['updated_by'] ?? null)) ?></small></td>
<td class="text-center">
<a href="view_committee.php?id=<?= $committee['id'] ?>" class="btn btn-sm btn-outline-info me-1" title="إدارة اللجنة"><i class="fas fa-cog"></i> إدارة</a>
<?php if (canEdit('committees')): ?>
<button class="btn btn-sm btn-outline-primary me-1" onclick='openModal("edit", <?= json_encode($committee, JSON_HEX_APOS | JSON_HEX_QUOT) ?>)'>
@ -126,7 +130,7 @@ if (isset($_SESSION['error'])) {
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="4" class="text-center py-4 text-muted">لا توجد لجان مضافة حتى الآن.</td>
<td colspan="6" class="text-center py-4 text-muted">لا توجد لجان مضافة حتى الآن.</td>
</tr>
<?php endif; ?>
</tbody>

View File

@ -12,6 +12,13 @@ function db() {
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
if (session_status() === PHP_SESSION_NONE) {
@session_start();
}
if (isset($_SESSION['user_id'])) {
$pdo->exec("SET @app_user_id = " . (int)$_SESSION['user_id']);
}
}
return $pdo;
}
@ -48,4 +55,4 @@ function generateRefNo($type) {
}
return $prefix . '-' . $year . '-' . str_pad($serial, 3, '0', STR_PAD_LEFT);
}
}

View File

@ -0,0 +1,17 @@
<?php
require_once __DIR__ . '/../config.php';
$db = db();
try {
$db->exec("ALTER TABLE charity_members ADD COLUMN user_id INT NULL");
$db->exec("ALTER TABLE charity_members ADD CONSTRAINT fk_charity_members_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL");
echo "Migration 033 completed successfully.\n";
} catch (PDOException $e) {
if (strpos($e->getMessage(), 'Duplicate column name') !== false) {
echo "Column user_id already exists.\n";
} else {
echo "Error: " . $e->getMessage() . "\n";
}
}

View File

@ -0,0 +1,82 @@
ALTER TABLE `committees` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `committees` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `committee_plans` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `committee_plans` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `committee_plans` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `committee_plans` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `charity_members` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `charity_members` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `charity_members` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `charity_members` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `charity_plans` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `charity_plans` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `charity_plans` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `charity_plans` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `expenses` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `expenses` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `expenses` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `expenses` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `expense_categories` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `expense_categories` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `expense_categories` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `expense_categories` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `accounting_accounts` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `accounting_accounts` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `accounting_accounts` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `accounting_accounts` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `accounting_journal` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `accounting_journal` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `accounting_journal` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `accounting_journal` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_employees` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `hr_employees` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_employees` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `hr_employees` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_attendance` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `hr_attendance` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_attendance` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `hr_attendance` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_holidays` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `hr_holidays` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_holidays` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `hr_holidays` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_leaves` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `hr_leaves` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_leaves` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `hr_leaves` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_payroll` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `hr_payroll` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `hr_payroll` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `hr_payroll` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_items` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `stock_items` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_items` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `stock_items` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_categories` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `stock_categories` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_categories` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `stock_categories` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_stores` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `stock_stores` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_stores` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `stock_stores` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_transactions` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `stock_transactions` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_transactions` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `stock_transactions` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_lending` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `stock_lending` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `stock_lending` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `stock_lending` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `users` ADD COLUMN `created_by` INT DEFAULT NULL;
ALTER TABLE `users` ADD FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `users` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `users` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `inbound_mail` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `inbound_mail` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `outbound_mail` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `outbound_mail` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `internal_mail` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `internal_mail` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;
ALTER TABLE `meetings` ADD COLUMN `updated_by` INT DEFAULT NULL;
ALTER TABLE `meetings` ADD FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE SET NULL;

View File

@ -101,6 +101,8 @@ if (isset($_SESSION['error'])) {
<th class="ps-4">اسم التصنيف</th>
<th>الحساب المحاسبي المرتبط</th>
<th>الوصف</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center">الإجراءات</th>
</tr>
</thead>
@ -116,6 +118,8 @@ if (isset($_SESSION['error'])) {
<?php endif; ?>
</td>
<td><?= htmlspecialchars($cat['description']) ?></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($cat['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($cat['updated_by'] ?? null)) ?></small></td>
<td class="text-center">
<?php if (canEdit('expense_settings')): ?>
<button class="btn btn-sm btn-outline-primary" onclick='openModal("edit", <?= json_encode($cat, JSON_HEX_APOS | JSON_HEX_QUOT) ?>)'>

View File

@ -283,13 +283,15 @@ if (isset($_SESSION['success'])) {
<th>المبلغ</th>
<th>طريقة الدفع</th>
<th>الإيصال</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center">الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($expenses)): ?>
<tr>
<td colspan="8" class="text-center py-5 text-muted">لا توجد سجلات مطابقة</td>
<td colspan="10" class="text-center py-5 text-muted">لا توجد سجلات مطابقة</td>
</tr>
<?php else: ?>
<?php foreach ($expenses as $exp): ?>
@ -305,7 +307,9 @@ if (isset($_SESSION['success'])) {
<td><?= htmlspecialchars($exp['vendor'] ?: '-') ?></td>
<td class="fw-bold text-danger"><?= number_format($exp['amount'], 2) ?></td>
<td><?= htmlspecialchars($exp['payment_method']) ?></td>
<td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($exp['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($exp['updated_by'] ?? null)) ?></small></td>
<td>
<?php if ($exp['receipt_file']): ?>
<a href="<?= htmlspecialchars($exp['receipt_file']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-paperclip"></i>
@ -330,13 +334,13 @@ if (isset($_SESSION['success'])) {
<?php endforeach; ?>
<!-- Page Total -->
<tr class="bg-light">
<td colspan="4" class="text-end fw-bold">إجمالي الصفحة:</td>
<td colspan="6" class="text-end fw-bold">إجمالي الصفحة:</td>
<td class="text-danger fw-bold"><?= number_format(array_sum(array_column($expenses, 'amount')), 2) ?></td>
<td colspan="3"></td>
</tr>
<!-- Grand Total -->
<tr class="bg-light border-top-0">
<td colspan="4" class="text-end fw-bold">الإجمالي الكلي (للبحث الحالي):</td>
<td colspan="6" class="text-end fw-bold">الإجمالي الكلي (للبحث الحالي):</td>
<td class="text-danger fw-bold"><?= number_format($grandTotalAmount, 2) ?></td>
<td colspan="3"></td>
</tr>

View File

@ -99,13 +99,15 @@ $records = $stmt->fetchAll();
<th>وقت الحضور</th>
<th>وقت الانصراف</th>
<th>ملاحظات</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>إجراء</th>
</tr>
</thead>
<tbody>
<?php if (empty($records)): ?>
<tr>
<td colspan="7" class="text-center py-4 text-muted">لا يوجد موظفين نشطين.</td>
<td colspan="9" class="text-center py-4 text-muted">لا يوجد موظفين نشطين.</td>
</tr>
<?php endif; ?>
<?php foreach ($records as $row): ?>
@ -140,7 +142,9 @@ $records = $stmt->fetchAll();
<td><?= $row['check_in'] ? date('h:i A', strtotime($row['check_in'])) : '-' ?></td>
<td><?= $row['check_out'] ? date('h:i A', strtotime($row['check_out'])) : '-' ?></td>
<td class="text-truncate" style="max-width: 150px;"><?= htmlspecialchars($row['notes'] ?? '') ?></td>
<td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['updated_by'] ?? null)) ?></small></td>
<td>
<?php if (canEdit('hr_attendance')): ?>
<?php if ($row['att_id']): ?>
<button class="btn btn-sm btn-outline-primary"

View File

@ -258,6 +258,8 @@ $pagination = getPagination($page, $totalEmployees, $perPage);
<th>تاريخ التعيين</th>
<th>الحالة</th>
<th>بصمة (UID)</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>الإجراءات</th>
</tr>
</thead>
@ -303,7 +305,9 @@ $pagination = getPagination($page, $totalEmployees, $perPage);
<span class="badge bg-<?= $status_cls ?>"><?= htmlspecialchars($row['status']) ?></span>
</td>
<td><span class="badge bg-light text-dark border"><?= htmlspecialchars($row['zkteco_uid'] ?: '-') ?></span></td>
<td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($emp['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($emp['updated_by'] ?? null)) ?></small></td>
<td>
<div class="btn-group">
<?php if (canEdit('hr_employees')): ?>
<button type="button" class="btn btn-sm btn-outline-primary"

View File

@ -75,12 +75,14 @@ $holidays = db()->query("SELECT * FROM hr_holidays ORDER BY date_from DESC")->fe
<th>من تاريخ</th>
<th>إلى تاريخ</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>إجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($holidays)): ?>
<tr><td colspan="5" class="text-center py-4 text-muted">لا توجد عطلات مسجلة.</td></tr>
<tr><td colspan="7" class="text-center py-4 text-muted">لا توجد عطلات مسجلة.</td></tr>
<?php else: ?>
<?php foreach ($holidays as $row):
$today = date('Y-m-d');
@ -100,6 +102,8 @@ $holidays = db()->query("SELECT * FROM hr_holidays ORDER BY date_from DESC")->fe
<td><?= $row['date_from'] ?></td>
<td><?= $row['date_to'] ?></td>
<td><span class="badge bg-<?= $status_cls ?>"><?= $status_txt ?></span></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['updated_by'] ?? null)) ?></small></td>
<td>
<?php if (canEdit('hr_attendance')): ?>
<button class="btn btn-sm btn-outline-primary"

View File

@ -205,12 +205,14 @@ $requests = $stmt->fetchAll();
<th>السبب</th>
<th>الحالة</th>
<?php if ($tab === 'all'): ?><th>المعتمد</th><?php endif; ?>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>إجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($requests)): ?>
<tr><td colspan="8" class="text-center py-4 text-muted">لا توجد طلبات.</td></tr>
<tr><td colspan="10" class="text-center py-4 text-muted">لا توجد طلبات.</td></tr>
<?php else: ?>
<?php foreach ($requests as $req): ?>
<tr>
@ -251,6 +253,8 @@ $requests = $stmt->fetchAll();
<?php if ($tab === 'all'): ?>
<td class="small"><?= htmlspecialchars($req['approver_name'] ?? '-') ?></td>
<?php endif; ?>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($req['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($req['updated_by'] ?? null)) ?></small></td>
<td>
<?php if ($req['status'] === 'pending' && canEdit('hr_leaves')): ?>
<button class="btn btn-sm btn-outline-primary"

View File

@ -204,12 +204,14 @@ $total_salaries = $sumStmt->fetchColumn() ?: 0;
<th>خصومات</th>
<th>الصافي</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>إجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($payrolls)): ?>
<tr><td colspan="7" class="text-center py-4 text-muted">لا توجد بيانات لهذا الشهر. اضغط على "توليد الرواتب" للبدء.</td></tr>
<tr><td colspan="9" class="text-center py-4 text-muted">لا توجد بيانات لهذا الشهر. اضغط على "توليد الرواتب" للبدء.</td></tr>
<?php else: ?>
<?php foreach ($payrolls as $row): ?>
<tr>
@ -229,6 +231,8 @@ $total_salaries = $sumStmt->fetchColumn() ?: 0;
<span class="badge bg-info text-dark" title="مرحل للمحاسبة"><i class="fas fa-check-circle"></i></span>
<?php endif; ?>
</td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($row['updated_by'] ?? null)) ?></small></td>
<td>
<?php if (canEdit('hr_payroll')): ?>
<button class="btn btn-sm btn-outline-primary"

View File

@ -237,13 +237,15 @@ if (isset($_GET['id'])) {
<th>الجهة المرسلة</th>
<th>الحالة</th>
<th>المسؤول</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center pe-4">الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($mails)): ?>
<tr>
<td colspan="7" class="text-center py-5 text-muted">
<td colspan="9" class="text-center py-5 text-muted">
<i class="fas fa-inbox fa-3x mb-3 opacity-20"></i>
<p>لا يوجد بريد وارد حالياً.</p>
</td>
@ -275,6 +277,8 @@ if (isset($_GET['id'])) {
<span class="small"><?= htmlspecialchars($mail['assigned_to_name'] ?: 'غير محدد') ?></span>
</div>
</td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($mail['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($mail['updated_by'] ?? null)) ?></small></td>
<td class="text-center pe-4">
<div class="btn-group shadow-sm rounded">
<a href="view_mail.php?id=<?= $mail['id'] ?>&type=inbound" class="btn btn-sm btn-white text-primary border" title="عرض">

View File

@ -62,3 +62,19 @@ function canDelete($page = null) {
function canViewInternal() {
return canView('internal');
}
// Added for auditing display
function getAuditUserName($user_id) {
if (!$user_id) return '-';
static $userCache = null;
if ($userCache === null) {
$userCache = [];
try {
$stmt = db()->query("SELECT id, username, full_name FROM users");
while ($u = $stmt->fetch()) {
$userCache[$u['id']] = $u['full_name'] ?: $u['username'];
}
} catch(Exception $e) {}
}
return $userCache[$user_id] ?? '-';
}

View File

@ -104,6 +104,8 @@ function getStatusBadgeInternal($mail) {
<th>المرفقات</th>
<th>التاريخ</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="pe-4 text-center">الإجراء</th>
</tr>
</thead>
@ -140,14 +142,16 @@ function getStatusBadgeInternal($mail) {
<small class="text-muted"><?= date('Y-m-d H:i', strtotime($msg['created_at'])) ?></small>
</td>
<td><?= getStatusBadgeInternal($msg) ?></td>
<td class="pe-4 text-center">
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($msg['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($msg['updated_by'] ?? null)) ?></small></td>
<td class="pe-4 text-center">
<a href="view_mail.php?id=<?= $msg['id'] ?>&type=internal" class="btn btn-sm btn-light rounded-pill px-3">عرض</a>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6" class="text-center py-5 text-muted">
<td colspan="8" class="text-center py-5 text-muted">
<i class="fas fa-envelope-open fa-3x mb-3 opacity-25"></i>
<p>لا توجد رسائل واردة حالياً</p>
</td>

View File

@ -206,6 +206,8 @@ function getStatusBadgeInternal($mail) {
<th>المرفقات</th>
<th>التاريخ</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="pe-4 text-center">الإجراء</th>
</tr>
</thead>
@ -242,14 +244,16 @@ function getStatusBadgeInternal($mail) {
<small class="text-muted"><?= date('Y-m-d H:i', strtotime($msg['created_at'])) ?></small>
</td>
<td><?= getStatusBadgeInternal($msg) ?></td>
<td class="pe-4 text-center">
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($msg['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($msg['updated_by'] ?? null)) ?></small></td>
<td class="pe-4 text-center">
<a href="view_mail.php?id=<?= $msg['id'] ?>&type=internal" class="btn btn-sm btn-light rounded-pill px-3">عرض</a>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6" class="text-center py-5 text-muted">
<td colspan="8" class="text-center py-5 text-muted">
<i class="fas fa-paper-plane fa-3x mb-3 opacity-25"></i>
<p>لم يتم إرسال أي رسائل حالياً</p>
</td>

View File

@ -210,13 +210,15 @@ if (isset($_SESSION['success'])) {
<th>المكان</th>
<th>المنظم</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center">الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($meetings)): ?>
<tr>
<td colspan="6" class="text-center py-5 text-muted">لا توجد اجتماعات مطابقة</td>
<td colspan="8" class="text-center py-5 text-muted">لا توجد اجتماعات مطابقة</td>
</tr>
<?php else: ?>
<?php foreach ($meetings as $meeting): ?>
@ -256,7 +258,9 @@ if (isset($_SESSION['success'])) {
</td>
<td><?= htmlspecialchars($meeting['created_by_name']) ?></td>
<td><span class="badge <?= $status_class ?>"><?= $status_text ?></span></td>
<td class="text-center">
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($meeting['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($meeting['updated_by'] ?? null)) ?></small></td>
<td class="text-center">
<?php if (canEdit('meetings')): ?>
<button class="btn btn-sm btn-outline-primary" onclick='openModal("edit", <?= json_encode($meeting, JSON_HEX_APOS | JSON_HEX_QUOT) ?>)'>
<i class="fas fa-edit"></i>

View File

@ -226,13 +226,15 @@ if (isset($_GET['id'])) {
<th>الموضوع</th>
<th>الجهة المستلمة</th>
<th>الحالة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center pe-4">الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($mails)): ?>
<tr>
<td colspan="6" class="text-center py-5 text-muted">
<td colspan="8" class="text-center py-5 text-muted">
<i class="fas fa-paper-plane fa-3x mb-3 opacity-20"></i>
<p>لا يوجد بريد صادر حالياً.</p>
</td>
@ -256,6 +258,8 @@ if (isset($_GET['id'])) {
<i class="fas fa-circle me-1 small"></i> <?= htmlspecialchars($mail['status_name']) ?>
</span>
</td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($mail['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($mail['updated_by'] ?? null)) ?></small></td>
<td class="text-center pe-4">
<div class="btn-group shadow-sm rounded">
<a href="view_mail.php?id=<?= $mail['id'] ?>&type=outbound" class="btn btn-sm btn-white text-primary border" title="عرض">

View File

@ -4,7 +4,7 @@ require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/includes/permissions.php';
require_once __DIR__ . '/includes/settings.php';
if (!isLoggedIn() || !canView('committees')) {
if (!isLoggedIn() || (!canView('charity_members') && !canView('charity_plans'))) {
exit("لا توجد صلاحية للوصول لهذه الصفحة.");
}
@ -61,10 +61,25 @@ $status_labels = [
th, td { border: 1px solid #dee2e6; padding: 8px; text-align: right; }
th { background-color: #f1f3f5; }
@media print {
body { margin: 0; padding: 0; }
body { margin: 0; padding: 0; font-size: 10pt; }
.btn-print { display: none !important; }
@page { margin: 1cm; }
.page-break { page-break-before: always; }
@page { margin: 1cm; size: A4; }
.container { width: 100% !important; max-width: none !important; padding: 0 !important; }
.print-header { padding-bottom: 10px; margin-bottom: 15px; }
.print-logo { max-height: 60px; }
h2.fw-bold { font-size: 16pt; }
p.fs-5 { font-size: 12pt !important; }
h3.text-decoration-underline { font-size: 14pt; margin-bottom: 15px !important; }
.section-title { margin-top: 15px; margin-bottom: 10px; padding: 5px 10px; font-size: 11pt; }
.kpi-box { padding: 10px; }
.kpi-box h2 { font-size: 14pt; margin: 0; }
.kpi-box h5 { font-size: 10pt; margin-bottom: 2px; }
table { margin-top: 10px; margin-bottom: 10px; }
th, td { padding: 4px 6px; font-size: 9pt; }
.page-break { page-break-before: auto; } /* Removed forced page break */
.mb-5 { margin-bottom: 15px !important; }
.py-4 { padding-top: 10px !important; padding-bottom: 10px !important; }
.mt-5 { margin-top: 20px !important; }
}
</style>
</head>
@ -157,11 +172,8 @@ $status_labels = [
</table>
<?php endif; ?>
<!-- Page Break before Members -->
<div class="page-break"></div>
<!-- Members Table -->
<div class="section-title mt-0">2. أعضاء الجمعية</div>
<div class="section-title">2. أعضاء الجمعية</div>
<?php if (empty($members)): ?>
<div class="text-muted text-center fst-italic py-3 border">لا يوجد أعضاء مسجلين.</div>
<?php else: ?>

View File

@ -12,16 +12,35 @@ $settings = get_settings();
$db = db();
// Fetch committees and members
$committees_query = $db->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);
if (isAdmin()) {
$committees_query = $db->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);
} else {
$committees_query = $db->prepare("
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
JOIN committee_members m ON c.id = m.committee_id
JOIN charity_members cm ON m.charity_member_id = cm.id
JOIN users u ON (u.id = cm.user_id) OR (cm.email != '' AND cm.email = u.email) OR (cm.name = u.full_name) OR (cm.name = u.username)
WHERE u.id = ?
GROUP BY c.id
ORDER BY c.name ASC
");
$committees_query->execute([$_SESSION['user_id']]);
$committees = $committees_query->fetchAll(PDO::FETCH_ASSOC);
}
foreach ($committees as &$c) {
// Calculate performance score

View File

@ -157,13 +157,15 @@ $categories = db()->query("SELECT * FROM stock_categories ORDER BY name ASC")->f
<th>الكمية الحالية</th>
<th>الحد الأدنى</th>
<th>الوحدة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="text-center">الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($items)): ?>
<tr>
<td colspan="7" class="text-center py-5 text-muted">
<td colspan="9" class="text-center py-5 text-muted">
<i class="fas fa-boxes fa-3x mb-3 opacity-20"></i>
<p>لا يوجد أصناف مطابقة.</p>
</td>
@ -183,6 +185,8 @@ $categories = db()->query("SELECT * FROM stock_categories ORDER BY name ASC")->f
</td>
<td><?= number_format($item['min_quantity']) ?></td>
<td><?= htmlspecialchars($item['unit']) ?></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($item['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($item['updated_by'] ?? null)) ?></small></td>
<td class="text-center">
<?php if (canEdit('stock_items')): ?>
<button class="btn btn-sm btn-outline-primary" onclick='openItemModal("edit", <?= json_encode($item) ?>)'>

View File

@ -144,13 +144,15 @@ $items = db()->query("SELECT * FROM stock_items ORDER BY name ASC")->fetchAll();
<th>تاريخ الإعارة</th>
<th>تاريخ الإرجاع المتوقع</th>
<th>الحالة</th>
<th>الإجراءات</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th>الإجراءات</th>
</tr>
</thead>
<tbody>
<?php if (empty($loans)): ?>
<tr>
<td colspan="7" class="text-center py-4 text-muted">لا توجد إعارات نشطة حالياً</td>
<td colspan="9" class="text-center py-4 text-muted">لا توجد إعارات نشطة حالياً</td>
</tr>
<?php else: ?>
<?php foreach ($loans as $loan): ?>
@ -170,6 +172,8 @@ $items = db()->query("SELECT * FROM stock_items ORDER BY name ASC")->fetchAll();
<span class="<?= $cls ?>"><?= date('Y-m-d', $due) ?></span>
</td>
<td><span class="badge bg-warning text-dark">نشط</span></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($loan['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($loan['updated_by'] ?? null)) ?></small></td>
<td>
<form method="POST" onsubmit="return confirm('هل استلمت المواد المرجعة؟ سيتم إضافتها للمخزون.')">
<input type="hidden" name="action" value="return">

View File

@ -33,7 +33,9 @@ $modules = [
'expenses' => 'المصروفات',
'expense_settings' => 'المصروفات - الإعدادات',
'meetings' => 'الاجتماعات',
'committees' => 'اللجان'
'committees' => 'اللجان',
'charity_members' => 'أعضاء الجمعية',
'charity_plans' => 'الخطط والأهداف'
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@ -242,6 +244,8 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
<th>البريد الإلكتروني</th>
<th>الدور</th>
<th>تاريخ الإنشاء</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-plus me-1"></i>أضيف بواسطة</th>
<th class="text-secondary text-nowrap" style="font-size: 0.85rem;"><i class="fas fa-user-edit me-1"></i>عُدل بواسطة</th>
<th class="pe-4 text-center">الإجراءات</th>
</tr>
</thead>
@ -270,6 +274,8 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
<?php endif; ?>
</td>
<td><?= $user['created_at'] ?></td>
<td><small class="text-muted"><i class="fas fa-user text-primary opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($user['created_by'] ?? null)) ?></small></td>
<td><small class="text-muted"><i class="fas fa-user-edit text-warning opacity-50 me-1"></i><?= htmlspecialchars(getAuditUserName($user['updated_by'] ?? null)) ?></small></td>
<td class="pe-4 text-center">
<?php if (canEdit('users')): ?>
<button type="button" class="btn btn-sm btn-outline-primary"

View File

@ -19,6 +19,22 @@ if (!$committee) {
redirect('committees.php');
}
// Check membership for non-admins
if (!isAdmin()) {
$check_stmt = $db->prepare("
SELECT 1
FROM committee_members m
JOIN charity_members cm ON m.charity_member_id = cm.id
JOIN users u ON (u.id = cm.user_id) OR (cm.email != '' AND cm.email = u.email) OR (cm.name = u.full_name) OR (cm.name = u.username)
WHERE m.committee_id = ? AND u.id = ?
");
$check_stmt->execute([$id, $_SESSION['user_id']]);
if (!$check_stmt->fetchColumn()) {
$_SESSION['error'] = 'غير مصرح لك بعرض هذه اللجنة';
redirect('committees.php');
}
}
$tab = $_GET['tab'] ?? 'members';
$allowed_tabs = ['members', 'plans', 'activities'];
if (!in_array($tab, $allowed_tabs)) {