setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $conn->exec("SET NAMES utf8mb4"); // التحقق من وجود قاعدة البيانات وإنشائها إذا لم تكن موجودة $conn->exec("CREATE DATABASE IF NOT EXISTS `$dbname` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); $conn->exec("USE `$dbname`"); // إنشاء الجداول إذا لم تكن موجودة createTables($conn); // معالجة الطلب handleRequest($conn); } catch(PDOException $e) { sendResponse(500, ["error" => "فشل الاتصال بقاعدة البيانات: " . $e->getMessage()]); } // دالة إنشاء الجداول function createTables($conn) { try { // جدول الموظفين $conn->exec("CREATE TABLE IF NOT EXISTS `employees` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `position` VARCHAR(255) NOT NULL, `salary` DECIMAL(10,2) NOT NULL, `phone` VARCHAR(20) DEFAULT NULL, `email` VARCHAR(255) DEFAULT NULL, `join_date` DATE DEFAULT NULL, `status` VARCHAR(50) DEFAULT 'active', `balance` DECIMAL(10,2) DEFAULT 0.00, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); // جدول الحضور $conn->exec("CREATE TABLE IF NOT EXISTS `attendance` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `employee_id` INT(11) NOT NULL, `date` DATE NOT NULL, `time_in` TIME DEFAULT NULL, `time_out` TIME DEFAULT NULL, `status` VARCHAR(50) DEFAULT 'present', `notes` TEXT DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); // جدول المصروفات $conn->exec("CREATE TABLE IF NOT EXISTS `expenses` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `date` DATE NOT NULL, `amount` DECIMAL(10,2) NOT NULL, `type` VARCHAR(100) NOT NULL, `reason` TEXT DEFAULT NULL, `employee_id` INT(11) DEFAULT NULL, `payer` VARCHAR(50) DEFAULT 'workshop', `payment_method` VARCHAR(50) DEFAULT 'cash', `recipient` VARCHAR(255) DEFAULT NULL, `payment_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `status` VARCHAR(50) DEFAULT 'pending', `settlement_status` VARCHAR(50) DEFAULT NULL, `settlement_date` DATE DEFAULT NULL, `settlement_amount` DECIMAL(10,2) DEFAULT NULL, `settlement_notes` TEXT DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); // جدول الإعدادات $conn->exec("CREATE TABLE IF NOT EXISTS `settings` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `value` TEXT DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); // إضافة إعدادات افتراضية إذا لم تكن موجودة $stmt = $conn->prepare("SELECT COUNT(*) FROM settings WHERE name = 'salary_day'"); $stmt->execute(); if ($stmt->fetchColumn() == 0) { $stmt = $conn->prepare("INSERT INTO settings (name, value) VALUES ('salary_day', '28')"); $stmt->execute(); } $stmt = $conn->prepare("SELECT COUNT(*) FROM settings WHERE name = 'work_start_time'"); $stmt->execute(); if ($stmt->fetchColumn() == 0) { $stmt = $conn->prepare("INSERT INTO settings (name, value) VALUES ('work_start_time', '08:00')"); $stmt->execute(); } } catch(PDOException $e) { sendResponse(500, ["error" => "فشل إنشاء الجداول: " . $e->getMessage()]); } } // دالة معالجة الطلب function handleRequest($conn) { $method = $_SERVER['REQUEST_METHOD']; // الحصول على اسم الجدول من الطلب $table = isset($_GET['table']) ? $_GET['table'] : ''; switch ($method) { case 'GET': handleGetRequest($conn, $table); break; case 'POST': handlePostRequest($conn, $table); break; case 'PUT': handlePutRequest($conn, $table); break; case 'DELETE': handleDeleteRequest($conn, $table); break; default: sendResponse(405, ["error" => "طريقة الطلب غير مدعومة"]); break; } } // دالة معالجة طلب GET function handleGetRequest($conn, $table) { try { $id = isset($_GET['id']) ? $_GET['id'] : null; switch ($table) { case 'employees': if ($id) { $stmt = $conn->prepare("SELECT * FROM employees WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); $result = $stmt->fetch(PDO::FETCH_ASSOC); if ($result) { // جلب رصيد الموظف من المصروفات التي دفعها $stmt = $conn->prepare(" SELECT COALESCE(SUM(CASE WHEN payer = 'employee' THEN amount ELSE 0 END), 0) as paid_by_employee, COALESCE(SUM(CASE WHEN type = 'سلفة' AND payer = 'workshop' THEN amount ELSE 0 END), 0) as advances, COALESCE(SUM(CASE WHEN type = 'راتب' THEN amount ELSE 0 END), 0) as salary_paid FROM expenses WHERE employee_id = :employee_id "); $stmt->bindParam(':employee_id', $id); $stmt->execute(); $balance_data = $stmt->fetch(PDO::FETCH_ASSOC); // حساب الرصيد: المبالغ التي دفعها الموظف - السلفيات + الرواتب المدفوعة $balance = $balance_data['paid_by_employee'] - $balance_data['advances'] + $balance_data['salary_paid']; // تحديث رصيد الموظف في قاعدة البيانات $stmt = $conn->prepare("UPDATE employees SET balance = :balance WHERE id = :id"); $stmt->bindParam(':balance', $balance); $stmt->bindParam(':id', $id); $stmt->execute(); $result['balance'] = $balance; $result['paid_by_employee'] = $balance_data['paid_by_employee']; $result['advances'] = $balance_data['advances']; $result['salary_paid'] = $balance_data['salary_paid']; sendResponse(200, $result); } else { sendResponse(404, ["error" => "لم يتم العثور على الموظف"]); } } else { $stmt = $conn->prepare("SELECT * FROM employees ORDER BY id DESC"); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); // تحديث رصيد كل موظف foreach ($result as &$employee) { $stmt = $conn->prepare(" SELECT COALESCE(SUM(CASE WHEN payer = 'employee' THEN amount ELSE 0 END), 0) as paid_by_employee, COALESCE(SUM(CASE WHEN type = 'سلفة' AND payer = 'workshop' THEN amount ELSE 0 END), 0) as advances, COALESCE(SUM(CASE WHEN type = 'راتب' THEN amount ELSE 0 END), 0) as salary_paid FROM expenses WHERE employee_id = :employee_id "); $stmt->bindParam(':employee_id', $employee['id']); $stmt->execute(); $balance_data = $stmt->fetch(PDO::FETCH_ASSOC); // حساب الرصيد: المبالغ التي دفعها الموظف - السلفيات + الرواتب المدفوعة $balance = $balance_data['paid_by_employee'] - $balance_data['advances'] + $balance_data['salary_paid']; // تحديث رصيد الموظف في قاعدة البيانات $stmt = $conn->prepare("UPDATE employees SET balance = :balance WHERE id = :id"); $stmt->bindParam(':balance', $balance); $stmt->bindParam(':id', $employee['id']); $stmt->execute(); $employee['balance'] = $balance; $employee['paid_by_employee'] = $balance_data['paid_by_employee']; $employee['advances'] = $balance_data['advances']; $employee['salary_paid'] = $balance_data['salary_paid']; } sendResponse(200, $result); } break; case 'attendance': if ($id) { $stmt = $conn->prepare("SELECT a.*, e.name as employee_name FROM attendance a JOIN employees e ON a.employee_id = e.id WHERE a.id = :id"); $stmt->bindParam(':id', $id); } else { $employee_id = isset($_GET['employee_id']) ? $_GET['employee_id'] : null; $date = isset($_GET['date']) ? $_GET['date'] : null; if ($employee_id && $date) { $stmt = $conn->prepare("SELECT a.*, e.name as employee_name FROM attendance a JOIN employees e ON a.employee_id = e.id WHERE a.employee_id = :employee_id AND a.date = :date"); $stmt->bindParam(':employee_id', $employee_id); $stmt->bindParam(':date', $date); } elseif ($employee_id) { $stmt = $conn->prepare("SELECT a.*, e.name as employee_name FROM attendance a JOIN employees e ON a.employee_id = e.id WHERE a.employee_id = :employee_id ORDER BY a.date DESC"); $stmt->bindParam(':employee_id', $employee_id); } elseif ($date) { $stmt = $conn->prepare("SELECT a.*, e.name as employee_name FROM attendance a JOIN employees e ON a.employee_id = e.id WHERE a.date = :date ORDER BY a.employee_id"); $stmt->bindParam(':date', $date); } else { $stmt = $conn->prepare("SELECT a.*, e.name as employee_name FROM attendance a JOIN employees e ON a.employee_id = e.id ORDER BY a.date DESC, a.employee_id"); } } $stmt->execute(); $result = $id ? $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC); if ($result) { sendResponse(200, $result); } else { sendResponse(200, []); } break; case 'expenses': if ($id) { $stmt = $conn->prepare("SELECT e.*, emp.name as employee_name FROM expenses e LEFT JOIN employees emp ON e.employee_id = emp.id WHERE e.id = :id"); $stmt->bindParam(':id', $id); } else { $employee_id = isset($_GET['employee_id']) ? $_GET['employee_id'] : null; $type = isset($_GET['type']) ? $_GET['type'] : null; $payer = isset($_GET['payer']) ? $_GET['payer'] : null; $period = isset($_GET['period']) ? $_GET['period'] : 'month'; // تحديد نطاق التاريخ بناءً على الفترة $start_date = null; $end_date = date('Y-m-d'); if ($period == 'day') { $start_date = date('Y-m-d'); } elseif ($period == 'week') { $start_date = date('Y-m-d', strtotime('-7 days')); } elseif ($period == 'month') { $start_date = date('Y-m-d', strtotime('-30 days')); } elseif ($period == 'custom') { $start_date = isset($_GET['start']) ? $_GET['start'] : date('Y-m-d', strtotime('-30 days')); $end_date = isset($_GET['end']) ? $_GET['end'] : date('Y-m-d'); } $query = "SELECT e.*, emp.name as employee_name FROM expenses e LEFT JOIN employees emp ON e.employee_id = emp.id WHERE 1=1"; $params = []; if ($employee_id) { $query .= " AND e.employee_id = :employee_id"; $params[':employee_id'] = $employee_id; } if ($type) { $query .= " AND e.type = :type"; $params[':type'] = $type; } if ($payer) { $query .= " AND e.payer = :payer"; $params[':payer'] = $payer; } if ($start_date && $end_date) { $query .= " AND e.date BETWEEN :start_date AND :end_date"; $params[':start_date'] = $start_date; $params[':end_date'] = $end_date; } $query .= " ORDER BY e.date DESC, e.id DESC"; $stmt = $conn->prepare($query); foreach ($params as $key => $value) { $stmt->bindValue($key, $value); } } $stmt->execute(); $result = $id ? $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC); if ($result) { sendResponse(200, $result); } else { sendResponse(200, []); } break; case 'settings': if ($id) { $stmt = $conn->prepare("SELECT * FROM settings WHERE id = :id"); $stmt->bindParam(':id', $id); } else { $name = isset($_GET['name']) ? $_GET['name'] : null; if ($name) { $stmt = $conn->prepare("SELECT * FROM settings WHERE name = :name"); $stmt->bindParam(':name', $name); } else { $stmt = $conn->prepare("SELECT * FROM settings"); } } $stmt->execute(); $result = $id || $name ? $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC); if ($result) { sendResponse(200, $result); } else { sendResponse(200, []); } break; case 'salary_report': // تقرير الرواتب مع حساب الخصومات $month = isset($_GET['month']) ? $_GET['month'] : date('Y-m'); $employee_id = isset($_GET['employee_id']) ? $_GET['employee_id'] : null; // الحصول على إعدادات النظام $stmt = $conn->prepare("SELECT * FROM settings WHERE name IN ('salary_day', 'work_start_time')"); $stmt->execute(); $settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); $salary_day = isset($settings['salary_day']) ? $settings['salary_day'] : 28; $work_start_time = isset($settings['work_start_time']) ? $settings['work_start_time'] : '08:00'; // تحديد بداية ونهاية الشهر $start_date = $month . '-01'; $end_date = date('Y-m-t', strtotime($start_date)); // استعلام الموظفين $query = "SELECT * FROM employees WHERE status = 'active'"; $params = []; if ($employee_id) { $query .= " AND id = :employee_id"; $params[':employee_id'] = $employee_id; } $stmt = $conn->prepare($query); foreach ($params as $key => $value) { $stmt->bindValue($key, $value); } $stmt->execute(); $employees = $stmt->fetchAll(PDO::FETCH_ASSOC); $salary_report = []; foreach ($employees as $employee) { // حساب أيام الغياب $stmt = $conn->prepare(" SELECT COUNT(*) as absent_days FROM attendance WHERE employee_id = :employee_id AND date BETWEEN :start_date AND :end_date AND status = 'غياب' "); $stmt->bindParam(':employee_id', $employee['id']); $stmt->bindParam(':start_date', $start_date); $stmt->bindParam(':end_date', $end_date); $stmt->execute(); $absent_data = $stmt->fetch(PDO::FETCH_ASSOC); $absent_days = $absent_data['absent_days']; // حساب خصم الغياب (الراتب ÷ 30 لكل يوم غياب) $daily_rate = $employee['salary'] / 30; $absent_deduction = $absent_days * $daily_rate; // حساب ساعات التأخير $stmt = $conn->prepare(" SELECT SUM(TIME_TO_SEC(TIMEDIFF(time_in, :work_start_time)) / 3600) as late_hours FROM attendance WHERE employee_id = :employee_id AND date BETWEEN :start_date AND :end_date AND status = 'تأخير' AND time_in > :work_start_time "); $stmt->bindParam(':employee_id', $employee['id']); $stmt->bindParam(':start_date', $start_date); $stmt->bindParam(':end_date', $end_date); $stmt->bindParam(':work_start_time', $work_start_time); $stmt->execute(); $late_data = $stmt->fetch(PDO::FETCH_ASSOC); $late_hours = $late_data['late_hours'] ? $late_data['late_hours'] : 0; // حساب خصم التأخير ((الراتب ÷ 30) ÷ 12 لكل ساعة تأخير) $hourly_rate = $daily_rate / 12; $late_deduction = $late_hours * $hourly_rate; // حساب السلفيات $stmt = $conn->prepare(" SELECT COALESCE(SUM(amount), 0) as advances FROM expenses WHERE employee_id = :employee_id AND type = 'سلفة' AND date BETWEEN :start_date AND :end_date "); $stmt->bindParam(':employee_id', $employee['id']); $stmt->bindParam(':start_date', $start_date); $stmt->bindParam(':end_date', $end_date); $stmt->execute(); $advances_data = $stmt->fetch(PDO::FETCH_ASSOC); $advances = $advances_data['advances']; // حساب المبالغ التي دفعها الموظف $stmt = $conn->prepare(" SELECT COALESCE(SUM(amount), 0) as paid_by_employee FROM expenses WHERE employee_id = :employee_id AND payer = 'employee' AND date BETWEEN :start_date AND :end_date "); $stmt->bindParam(':employee_id', $employee['id']); $stmt->bindParam(':start_date', $start_date); $stmt->bindParam(':end_date', $end_date); $stmt->execute(); $paid_data = $stmt->fetch(PDO::FETCH_ASSOC); $paid_by_employee = $paid_data['paid_by_employee']; // حساب الراتب النهائي $net_salary = $employee['salary'] - $absent_deduction - $late_deduction - $advances + $paid_by_employee; $salary_report[] = [ 'employee_id' => $employee['id'], 'employee_name' => $employee['name'], 'position' => $employee['position'], 'base_salary' => $employee['salary'], 'absent_days' => $absent_days, 'absent_deduction' => $absent_deduction, 'late_hours' => $late_hours, 'late_deduction' => $late_deduction, 'advances' => $advances, 'paid_by_employee' => $paid_by_employee, 'net_salary' => $net_salary, 'payment_date' => date('Y-m-' . $salary_day, strtotime($end_date)), 'status' => date('Y-m-d') >= date('Y-m-' . $salary_day, strtotime($end_date)) ? 'due' : 'pending' ]; } sendResponse(200, $salary_report); break; default: sendResponse(400, ["error" => "جدول غير معروف: $table"]); break; } } catch(PDOException $e) { sendResponse(500, ["error" => "فشل في تنفيذ الاستعلام: " . $e->getMessage()]); } } // دالة معالجة طلب POST function handlePostRequest($conn, $table) { try { // الحصول على البيانات المرسلة $data = json_decode(file_get_contents("php://input"), true); if (!$data) { sendResponse(400, ["error" => "لم يتم إرسال بيانات صالحة"]); return; } switch ($table) { case 'employees': // التحقق من وجود البيانات المطلوبة if (!isset($data['name']) || !isset($data['position']) || !isset($data['salary'])) { sendResponse(400, ["error" => "البيانات المطلوبة غير مكتملة"]); return; } // إضافة موظف جديد $stmt = $conn->prepare(" INSERT INTO employees (name, position, salary, phone, email, join_date, status) VALUES (:name, :position, :salary, :phone, :email, :join_date, :status) "); $stmt->bindParam(':name', $data['name']); $stmt->bindParam(':position', $data['position']); $stmt->bindParam(':salary', $data['salary']); $stmt->bindParam(':phone', $data['phone'] ?? null); $stmt->bindParam(':email', $data['email'] ?? null); $stmt->bindParam(':join_date', $data['join_date'] ?? date('Y-m-d')); $stmt->bindParam(':status', $data['status'] ?? 'active'); $stmt->execute(); $employee_id = $conn->lastInsertId(); sendResponse(201, ["id" => $employee_id, "message" => "تم إضافة الموظف بنجاح"]); break; case 'attendance': // التحقق من وجود البيانات المطلوبة if (!isset($data['employee_id']) || !isset($data['date'])) { sendResponse(400, ["error" => "البيانات المطلوبة غير مكتملة"]); return; } // التحقق من عدم وجود سجل حضور للموظف في نفس اليوم $stmt = $conn->prepare("SELECT COUNT(*) FROM attendance WHERE employee_id = :employee_id AND date = :date"); $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->bindParam(':date', $data['date']); $stmt->execute(); if ($stmt->fetchColumn() > 0) { // تحديث سجل الحضور الموجود $stmt = $conn->prepare(" UPDATE attendance SET time_in = :time_in, time_out = :time_out, status = :status, notes = :notes WHERE employee_id = :employee_id AND date = :date "); } else { // إضافة سجل حضور جديد $stmt = $conn->prepare(" INSERT INTO attendance (employee_id, date, time_in, time_out, status, notes) VALUES (:employee_id, :date, :time_in, :time_out, :status, :notes) "); } $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->bindParam(':date', $data['date']); $stmt->bindParam(':time_in', $data['time_in'] ?? null); $stmt->bindParam(':time_out', $data['time_out'] ?? null); $stmt->bindParam(':status', $data['status'] ?? 'present'); $stmt->bindParam(':notes', $data['notes'] ?? null); $stmt->execute(); $attendance_id = $conn->lastInsertId(); sendResponse(201, ["id" => $attendance_id, "message" => "تم تسجيل الحضور بنجاح"]); break; case 'expenses': // التحقق من وجود البيانات المطلوبة if (!isset($data['date']) || !isset($data['amount']) || !isset($data['type'])) { sendResponse(400, ["error" => "البيانات المطلوبة غير مكتملة"]); return; } // التحقق من عدم تكرار نفس المصروف (خلال 5 دقائق) if (isset($data['employee_id'])) { $stmt = $conn->prepare(" SELECT COUNT(*) FROM expenses WHERE date = :date AND amount = :amount AND type = :type AND employee_id = :employee_id AND ABS(TIMESTAMPDIFF(MINUTE, payment_time, NOW())) < 5 "); $stmt->bindParam(':date', $data['date']); $stmt->bindParam(':amount', $data['amount']); $stmt->bindParam(':type', $data['type']); $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->execute(); if ($stmt->fetchColumn() > 0) { sendResponse(409, ["error" => "هذا المصروف تم إضافته بالفعل خلال الدقائق القليلة الماضية"]); return; } } // إضافة مصروف جديد $stmt = $conn->prepare(" INSERT INTO expenses (date, amount, type, reason, employee_id, payer, payment_method, recipient, payment_time, status) VALUES (:date, :amount, :type, :reason, :employee_id, :payer, :payment_method, :recipient, :payment_time, :status) "); $payment_time = isset($data['payment_time']) ? $data['payment_time'] : date('Y-m-d H:i:s'); $stmt->bindParam(':date', $data['date']); $stmt->bindParam(':amount', $data['amount']); $stmt->bindParam(':type', $data['type']); $stmt->bindParam(':reason', $data['reason'] ?? null); $stmt->bindParam(':employee_id', $data['employee_id'] ?? null); $stmt->bindParam(':payer', $data['payer'] ?? 'workshop'); $stmt->bindParam(':payment_method', $data['payment_method'] ?? 'cash'); $stmt->bindParam(':recipient', $data['recipient'] ?? null); $stmt->bindParam(':payment_time', $payment_time); $stmt->bindParam(':status', $data['status'] ?? 'pending'); $stmt->execute(); $expense_id = $conn->lastInsertId(); // إذا كان نوع المصروف هو راتب، تحديث حالة الراتب if ($data['type'] == 'راتب' && isset($data['employee_id'])) { // تحديث رصيد الموظف updateEmployeeBalance($conn, $data['employee_id']); } // إذا كان الدافع هو موظف، تحديث رصيد الموظف if (isset($data['payer']) && $data['payer'] == 'employee' && isset($data['employee_id'])) { // تحديث رصيد الموظف updateEmployeeBalance($conn, $data['employee_id']); } sendResponse(201, ["id" => $expense_id, "message" => "تم إضافة المصروف بنجاح"]); break; case 'settings': // التحقق من وجود البيانات المطلوبة if (!isset($data['name']) || !isset($data['value'])) { sendResponse(400, ["error" => "البيانات المطلوبة غير مكتملة"]); return; } // التحقق من وجود الإعداد $stmt = $conn->prepare("SELECT COUNT(*) FROM settings WHERE name = :name"); $stmt->bindParam(':name', $data['name']); $stmt->execute(); if ($stmt->fetchColumn() > 0) { // تحديث الإعداد الموجود $stmt = $conn->prepare("UPDATE settings SET value = :value WHERE name = :name"); } else { // إضافة إعداد جديد $stmt = $conn->prepare("INSERT INTO settings (name, value) VALUES (:name, :value)"); } $stmt->bindParam(':name', $data['name']); $stmt->bindParam(':value', $data['value']); $stmt->execute(); sendResponse(200, ["message" => "تم حفظ الإعداد بنجاح"]); break; case 'settle_expenses': // التحقق من وجود البيانات المطلوبة if (!isset($data['employee_id']) || !isset($data['amount'])) { sendResponse(400, ["error" => "البيانات المطلوبة غير مكتملة"]); return; } // تحديث حالة المصروفات المدفوعة من قبل الموظف $stmt = $conn->prepare(" UPDATE expenses SET settlement_status = 'settled', settlement_date = :settlement_date, settlement_amount = :settlement_amount, settlement_notes = :settlement_notes WHERE employee_id = :employee_id AND payer = 'employee' AND (settlement_status IS NULL OR settlement_status != 'settled') "); $settlement_date = isset($data['settlement_date']) ? $data['settlement_date'] : date('Y-m-d'); $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->bindParam(':settlement_date', $settlement_date); $stmt->bindParam(':settlement_amount', $data['amount']); $stmt->bindParam(':settlement_notes', $data['notes'] ?? null); $stmt->execute(); // إضافة مصروف جديد لتسجيل التسوية $stmt = $conn->prepare(" INSERT INTO expenses (date, amount, type, reason, employee_id, payer, payment_method, recipient, payment_time, status) VALUES (:date, :amount, :type, :reason, :employee_id, :payer, :payment_method, :recipient, :payment_time, :status) "); $reason = "تسوية مصروفات الموظف " . $data['employee_name']; $stmt->bindParam(':date', $settlement_date); $stmt->bindParam(':amount', $data['amount']); $stmt->bindValue(':type', 'تسوية'); $stmt->bindParam(':reason', $reason); $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->bindValue(':payer', 'workshop'); $stmt->bindParam(':payment_method', $data['payment_method'] ?? 'cash'); $stmt->bindParam(':recipient', $data['employee_name'] ?? null); $stmt->bindValue(':payment_time', date('Y-m-d H:i:s')); $stmt->bindValue(':status', 'completed'); $stmt->execute(); // تحديث رصيد الموظف updateEmployeeBalance($conn, $data['employee_id']); sendResponse(200, ["message" => "تم تسوية مصروفات الموظف بنجاح"]); break; default: sendResponse(400, ["error" => "جدول غير معروف: $table"]); break; } } catch(PDOException $e) { sendResponse(500, ["error" => "فشل في تنفيذ الاستعلام: " . $e->getMessage()]); } } // دالة معالجة طلب PUT function handlePutRequest($conn, $table) { try { // الحصول على البيانات المرسلة $data = json_decode(file_get_contents("php://input"), true); if (!$data || !isset($data['id'])) { sendResponse(400, ["error" => "لم يتم إرسال بيانات صالحة"]); return; } $id = $data['id']; switch ($table) { case 'employees': // التحقق من وجود الموظف $stmt = $conn->prepare("SELECT COUNT(*) FROM employees WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على الموظف"]); return; } // تحديث بيانات الموظف $stmt = $conn->prepare(" UPDATE employees SET name = :name, position = :position, salary = :salary, phone = :phone, email = :email, join_date = :join_date, status = :status WHERE id = :id "); $stmt->bindParam(':id', $id); $stmt->bindParam(':name', $data['name']); $stmt->bindParam(':position', $data['position']); $stmt->bindParam(':salary', $data['salary']); $stmt->bindParam(':phone', $data['phone'] ?? null); $stmt->bindParam(':email', $data['email'] ?? null); $stmt->bindParam(':join_date', $data['join_date'] ?? null); $stmt->bindParam(':status', $data['status'] ?? 'active'); $stmt->execute(); sendResponse(200, ["message" => "تم تحديث بيانات الموظف بنجاح"]); break; case 'attendance': // التحقق من وجود سجل الحضور $stmt = $conn->prepare("SELECT COUNT(*) FROM attendance WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على سجل الحضور"]); return; } // تحديث سجل الحضور $stmt = $conn->prepare(" UPDATE attendance SET employee_id = :employee_id, date = :date, time_in = :time_in, time_out = :time_out, status = :status, notes = :notes WHERE id = :id "); $stmt->bindParam(':id', $id); $stmt->bindParam(':employee_id', $data['employee_id']); $stmt->bindParam(':date', $data['date']); $stmt->bindParam(':time_in', $data['time_in'] ?? null); $stmt->bindParam(':time_out', $data['time_out'] ?? null); $stmt->bindParam(':status', $data['status'] ?? 'present'); $stmt->bindParam(':notes', $data['notes'] ?? null); $stmt->execute(); sendResponse(200, ["message" => "تم تحديث سجل الحضور بنجاح"]); break; case 'expenses': // التحقق من وجود المصروف $stmt = $conn->prepare("SELECT COUNT(*) FROM expenses WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على المصروف"]); return; } // تحديث المصروف $stmt = $conn->prepare(" UPDATE expenses SET date = :date, amount = :amount, type = :type, reason = :reason, employee_id = :employee_id, payer = :payer, payment_method = :payment_method, recipient = :recipient, status = :status WHERE id = :id "); $stmt->bindParam(':id', $id); $stmt->bindParam(':date', $data['date']); $stmt->bindParam(':amount', $data['amount']); $stmt->bindParam(':type', $data['type']); $stmt->bindParam(':reason', $data['reason'] ?? null); $stmt->bindParam(':employee_id', $data['employee_id'] ?? null); $stmt->bindParam(':payer', $data['payer'] ?? 'workshop'); $stmt->bindParam(':payment_method', $data['payment_method'] ?? 'cash'); $stmt->bindParam(':recipient', $data['recipient'] ?? null); $stmt->bindParam(':status', $data['status'] ?? 'pending'); $stmt->execute(); // إذا كان المصروف مرتبط بموظف، تحديث رصيد الموظف if (isset($data['employee_id']) && $data['employee_id']) { updateEmployeeBalance($conn, $data['employee_id']); } sendResponse(200, ["message" => "تم تحديث المصروف بنجاح"]); break; case 'settings': // التحقق من وجود الإعداد $stmt = $conn->prepare("SELECT COUNT(*) FROM settings WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على الإعداد"]); return; } // تحديث الإعداد $stmt = $conn->prepare("UPDATE settings SET name = :name, value = :value WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->bindParam(':name', $data['name']); $stmt->bindParam(':value', $data['value']); $stmt->execute(); sendResponse(200, ["message" => "تم تحديث الإعداد بنجاح"]); break; default: sendResponse(400, ["error" => "جدول غير معروف: $table"]); break; } } catch(PDOException $e) { sendResponse(500, ["error" => "فشل في تنفيذ الاستعلام: " . $e->getMessage()]); } } // دالة معالجة طلب DELETE function handleDeleteRequest($conn, $table) { try { $id = isset($_GET['id']) ? $_GET['id'] : null; if (!$id) { sendResponse(400, ["error" => "لم يتم تحديد المعرف"]); return; } switch ($table) { case 'employees': // التحقق من وجود الموظف $stmt = $conn->prepare("SELECT COUNT(*) FROM employees WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على الموظف"]); return; } // حذف الموظف $stmt = $conn->prepare("DELETE FROM employees WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); sendResponse(200, ["message" => "تم حذف الموظف بنجاح"]); break; case 'attendance': // التحقق من وجود سجل الحضور $stmt = $conn->prepare("SELECT COUNT(*) FROM attendance WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على سجل الحضور"]); return; } // حذف سجل الحضور $stmt = $conn->prepare("DELETE FROM attendance WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); sendResponse(200, ["message" => "تم حذف سجل الحضور بنجاح"]); break; case 'expenses': // التحقق من وجود المصروف $stmt = $conn->prepare("SELECT employee_id FROM expenses WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); $expense = $stmt->fetch(PDO::FETCH_ASSOC); if (!$expense) { sendResponse(404, ["error" => "لم يتم العثور على المصروف"]); return; } // حذف المصروف $stmt = $conn->prepare("DELETE FROM expenses WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); // إذا كان المصروف مرتبط بموظف، تحديث رصيد الموظف if ($expense['employee_id']) { updateEmployeeBalance($conn, $expense['employee_id']); } sendResponse(200, ["message" => "تم حذف المصروف بنجاح"]); break; case 'settings': // التحقق من وجود الإعداد $stmt = $conn->prepare("SELECT COUNT(*) FROM settings WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); if ($stmt->fetchColumn() == 0) { sendResponse(404, ["error" => "لم يتم العثور على الإعداد"]); return; } // حذف الإعداد $stmt = $conn->prepare("DELETE FROM settings WHERE id = :id"); $stmt->bindParam(':id', $id); $stmt->execute(); sendResponse(200, ["message" => "تم حذف الإعداد بنجاح"]); break; default: sendResponse(400, ["error" => "جدول غير معروف: $table"]); break; } } catch(PDOException $e) { sendResponse(500, ["error" => "فشل في تنفيذ الاستعلام: " . $e->getMessage()]); } } // دالة تحديث رصيد الموظف function updateEmployeeBalance($conn, $employee_id) { try { // حساب رصيد الموظف $stmt = $conn->prepare(" SELECT COALESCE(SUM(CASE WHEN payer = 'employee' THEN amount ELSE 0 END), 0) as paid_by_employee, COALESCE(SUM(CASE WHEN type = 'سلفة' AND payer = 'workshop' THEN amount ELSE 0 END), 0) as advances, COALESCE(SUM(CASE WHEN type = 'راتب' THEN amount ELSE 0 END), 0) as salary_paid, COALESCE(SUM(CASE WHEN type = 'تسوية' THEN amount ELSE 0 END), 0) as settlements FROM expenses WHERE employee_id = :employee_id "); $stmt->bindParam(':employee_id', $employee_id); $stmt->execute(); $balance_data = $stmt->fetch(PDO::FETCH_ASSOC); // حساب الرصيد: المبالغ التي دفعها الموظف - السلفيات + الرواتب المدفوعة + التسويات $balance = $balance_data['paid_by_employee'] - $balance_data['advances'] + $balance_data['salary_paid'] + $balance_data['settlements']; // تحديث رصيد الموظف في قاعدة البيانات $stmt = $conn->prepare("UPDATE employees SET balance = :balance WHERE id = :id"); $stmt->bindParam(':balance', $balance); $stmt->bindParam(':id', $employee_id); $stmt->execute(); return $balance; } catch(PDOException $e) { return 0; } } // دالة إرسال الاستجابة function sendResponse($status, $data) { http_response_code($status); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit; } ?>