From 4d100ba658092a69ff1cece25e6c0a33503204a4 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 5 Mar 2026 17:14:54 +0000 Subject: [PATCH] Autosave: 20260305-171454 --- .../20260305_z_alter_drugs_name_length.sql | 4 + includes/SimpleXLSX.php | 2 +- includes/actions.php | 279 ++++++++++++------ includes/common_data.php | 2 +- includes/layout/header.php | 6 + includes/pages/drugs_groups.php | 2 +- includes/pages/visits.php | 2 +- update_actions.py | 110 +++++++ 8 files changed, 306 insertions(+), 101 deletions(-) create mode 100644 db/migrations/20260305_z_alter_drugs_name_length.sql create mode 100644 update_actions.py diff --git a/db/migrations/20260305_z_alter_drugs_name_length.sql b/db/migrations/20260305_z_alter_drugs_name_length.sql new file mode 100644 index 0000000..c59d64b --- /dev/null +++ b/db/migrations/20260305_z_alter_drugs_name_length.sql @@ -0,0 +1,4 @@ +ALTER TABLE drugs MODIFY name_en TEXT; +ALTER TABLE drugs MODIFY name_ar TEXT; +ALTER TABLE drugs_groups MODIFY name_en TEXT; +ALTER TABLE drugs_groups MODIFY name_ar TEXT; diff --git a/includes/SimpleXLSX.php b/includes/SimpleXLSX.php index c6f9643..2f1faf9 100644 --- a/includes/SimpleXLSX.php +++ b/includes/SimpleXLSX.php @@ -479,7 +479,7 @@ class SimpleXLSX $entry_xml .= ' '; $entry_xml = preg_replace('/<[a-zA-Z0-9]+:([^>]+)>/', '<$1>', $entry_xml); // fix namespaced openned tags $entry_xml .= ' '; - $entry_xml = preg_replace('/<\[a-zA-Z0-9]+:([^>]+)>/', '', $entry_xml); // fix namespaced closed tags + $entry_xml = preg_replace('/<\/[a-zA-Z0-9]+:([^>]+)>/', '', $entry_xml); // fix namespaced closed tags $entry_xml .= ' '; if (strpos($name, '/sheet')) { // dirty skip empty rows diff --git a/includes/actions.php b/includes/actions.php index 5747813..8a3383e 100644 --- a/includes/actions.php +++ b/includes/actions.php @@ -4,8 +4,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { require_once __DIR__ . '/../helpers.php'; $db = db(); + // Check for post_max_size overflow + if (empty($_POST) && empty($_FILES) && isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) { + $_SESSION['flash_message'] = 'Error: File too large (exceeds post_max_size).'; + header("Location: " . $_SERVER['REQUEST_URI']); + exit; + } + function parse_import_file($file_input) { if (!isset($file_input['error']) || $file_input['error'] !== UPLOAD_ERR_OK) { + $_SESSION['import_error'] = 'Upload error code: ' . ($file_input['error'] ?? 'unknown'); return false; } $ext = strtolower(pathinfo($file_input['name'], PATHINFO_EXTENSION)); @@ -13,7 +21,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($ext === 'csv') { $handle = fopen($file_input['tmp_name'], 'r'); - // Skip header + if ($handle === false) { + $_SESSION['import_error'] = 'Failed to open CSV file.'; + return false; + } + # Skip header fgetcsv($handle); while (($row = fgetcsv($handle)) !== false) { if (array_filter($row)) { @@ -21,16 +33,29 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } fclose($handle); + if (empty($rows)) { + $_SESSION['import_error'] = 'CSV file is empty or could not be parsed.'; + } } elseif ($ext === 'xlsx' || $ext === 'xls') { require_once __DIR__ . '/SimpleXLSX.php'; - if ($xlsx = Shuchkin\SimpleXLSX::parse($file_input['tmp_name'])) { + if ($xlsx = \Shuchkin\SimpleXLSX::parse($file_input['tmp_name'])) { $rows = $xlsx->rows(); - array_shift($rows); // Skip header + array_shift($rows); # Skip header + if (empty($rows)) { + $_SESSION['import_error'] = 'Excel file is empty.'; + } + } else { + $_SESSION['import_error'] = 'SimpleXLSX Error: ' . \Shuchkin\SimpleXLSX::parseError(); + return false; } + } else { + $_SESSION['import_error'] = "Unsupported file extension: $ext. Please upload .csv or .xlsx"; + return false; } return $rows; } + function upload_file($file_array, $index, $target_dir = "assets/uploads/") { if (!isset($file_array["name"][$index]) || $file_array["error"][$index] !== UPLOAD_ERR_OK) { return null; @@ -765,131 +790,191 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } elseif ($_POST['action'] === 'import_drugs_groups') { if (isset($_FILES['csv_file'])) { - $rows = parse_import_file($_FILES['csv_file']); - - if ($rows) { - $stmt = $db->prepare("INSERT INTO drugs_groups (name_en, name_ar) VALUES (?, ?)"); - $checkStmt = $db->prepare("SELECT id FROM drugs_groups WHERE name_en = ?"); + try { + $rows = parse_import_file($_FILES['csv_file']); - foreach ($rows as $row) { - $name_en = $row[0] ?? ''; - $name_ar = $row[1] ?? ''; + if ($rows) { + $db->beginTransaction(); + $stmt = $db->prepare("INSERT INTO drugs_groups (name_en, name_ar) VALUES (?, ?)"); + $checkStmt = $db->prepare("SELECT id FROM drugs_groups WHERE name_en = ?"); - if ($name_en) { - $checkStmt->execute([$name_en]); - if (!$checkStmt->fetch()) { - $stmt->execute([$name_en, $name_ar]); + foreach ($rows as $row) { + $name_en = $row[0] ?? ''; + $name_ar = $row[1] ?? ''; + + if ($name_en) { + $checkStmt->execute([$name_en]); + if (!$checkStmt->fetch()) { + $stmt->execute([$name_en, $name_ar]); + } } } + $db->commit(); + $_SESSION['flash_message'] = __('import_successfully'); + $redirect = true; + } else { + $_SESSION['flash_message'] = $_SESSION['import_error'] ?? 'Failed to parse file or empty.'; unset($_SESSION['import_error']); + $redirect = true; } - $_SESSION['flash_message'] = __('import_successfully'); + } catch (Throwable $e) { + if ($db->inTransaction()) { + $db->rollBack(); + } + error_log("Import Error: " . $e->getMessage()); + $_SESSION['flash_message'] = 'Error: ' . $e->getMessage(); $redirect = true; } } } elseif ($_POST['action'] === 'import_drugs') { if (isset($_FILES['csv_file'])) { - $rows = parse_import_file($_FILES['csv_file']); - - if ($rows) { - $stmt = $db->prepare("INSERT INTO drugs (name_en, name_ar, group_id, price, expiry_date, supplier_id) VALUES (?, ?, ?, ?, ?, ?)"); + try { + $rows = parse_import_file($_FILES['csv_file']); - $groupMap = []; - $supplierMap = []; - - foreach ($rows as $row) { - $name_en = $row[0] ?? ''; - $name_ar = $row[1] ?? ''; - $group_name = $row[2] ?? ''; - $price = $row[3] ?? 0; - $expiry = $row[4] ?? null; - $supplier_name = $row[5] ?? ''; + if ($rows) { + $db->beginTransaction(); + $stmt = $db->prepare("INSERT INTO drugs (name_en, name_ar, group_id, price, expiry_date, supplier_id) VALUES (?, ?, ?, ?, ?, ?)"); - if ($name_en) { - $group_id = null; - if ($group_name) { - if (isset($groupMap[$group_name])) { - $group_id = $groupMap[$group_name]; - } else { - $gStmt = $db->prepare("SELECT id FROM drugs_groups WHERE name_en = ? OR name_ar = ?"); - $gStmt->execute([$group_name, $group_name]); - $gRes = $gStmt->fetch(); - if ($gRes) { - $group_id = $gRes['id']; - } else { - $cgStmt = $db->prepare("INSERT INTO drugs_groups (name_en, name_ar) VALUES (?, ?)"); - $cgStmt->execute([$group_name, $group_name]); - $group_id = $db->lastInsertId(); - } - $groupMap[$group_name] = $group_id; - } - } + $groupMap = []; + $supplierMap = []; + + foreach ($rows as $row) { + $name_en = $row[0] ?? ''; + $name_ar = $row[1] ?? ''; + $group_name = $row[2] ?? ''; + $price = $row[3] ?? 0; + // $expiry = $row[4] ?? null; + // Force expiry to null as requested to bypass parsing issues + $expiry = null; + $supplier_name = $row[5] ?? ''; - $supplier_id = null; - if ($supplier_name) { - if (isset($supplierMap[$supplier_name])) { - $supplier_id = $supplierMap[$supplier_name]; - } else { - $sStmt = $db->prepare("SELECT id FROM suppliers WHERE name_en = ? OR name_ar = ?"); - $sStmt->execute([$supplier_name, $supplier_name]); - $sRes = $sStmt->fetch(); - if ($sRes) { - $supplier_id = $sRes['id']; + if ($name_en) { + $group_id = null; + if ($group_name) { + if (isset($groupMap[$group_name])) { + $group_id = $groupMap[$group_name]; } else { - $csStmt = $db->prepare("INSERT INTO suppliers (name_en, name_ar) VALUES (?, ?)"); - $csStmt->execute([$supplier_name, $supplier_name]); - $supplier_id = $db->lastInsertId(); + $gStmt = $db->prepare("SELECT id FROM drugs_groups WHERE name_en = ? OR name_ar = ?"); + $gStmt->execute([$group_name, $group_name]); + $gRes = $gStmt->fetch(); + if ($gRes) { + $group_id = $gRes['id']; + } else { + $cgStmt = $db->prepare("INSERT INTO drugs_groups (name_en, name_ar) VALUES (?, ?)"); + $cgStmt->execute([$group_name, $group_name]); + $group_id = $db->lastInsertId(); + } + $groupMap[$group_name] = $group_id; } - $supplierMap[$supplier_name] = $supplier_id; } - } - - if ($expiry && !strtotime($expiry)) $expiry = null; + + $supplier_id = null; + if ($supplier_name) { + if (isset($supplierMap[$supplier_name])) { + $supplier_id = $supplierMap[$supplier_name]; + } else { + $sStmt = $db->prepare("SELECT id FROM suppliers WHERE name_en = ? OR name_ar = ?"); + $sStmt->execute([$supplier_name, $supplier_name]); + $sRes = $sStmt->fetch(); + if ($sRes) { + $supplier_id = $sRes['id']; + } else { + $csStmt = $db->prepare("INSERT INTO suppliers (name_en, name_ar) VALUES (?, ?)"); + $csStmt->execute([$supplier_name, $supplier_name]); + $supplier_id = $db->lastInsertId(); + } + $supplierMap[$supplier_name] = $supplier_id; + } + } + + /* + if ($expiry) { + if (is_numeric($expiry)) { + $ts = strtotime($expiry); + } else { + $ts = strtotime($expiry); + } - $stmt->execute([$name_en, $name_ar, $group_id, $price, $expiry, $supplier_id]); + if ($ts) { + $expiry = date('Y-m-d', $ts); + } else { + $expiry = null; + } + } else { + $expiry = null; + } + */ + + $stmt->execute([$name_en, $name_ar, $group_id, $price, $expiry, $supplier_id]); + } } + $db->commit(); + $_SESSION['flash_message'] = __('import_successfully'); + $redirect = true; + } else { + $_SESSION['flash_message'] = $_SESSION['import_error'] ?? 'Failed to parse file or empty.'; unset($_SESSION['import_error']); + $redirect = true; } - $_SESSION['flash_message'] = __('import_successfully'); + } catch (Throwable $e) { + if ($db->inTransaction()) { + $db->rollBack(); + } + error_log("Import Error: " . $e->getMessage()); + $_SESSION['flash_message'] = 'Error: ' . $e->getMessage(); $redirect = true; } } } elseif ($_POST['action'] === 'import_tests') { if (isset($_FILES['csv_file'])) { - $rows = parse_import_file($_FILES['csv_file']); - - if ($rows) { - $stmt = $db->prepare("INSERT INTO laboratory_tests (name_en, name_ar, group_id, price, normal_range) VALUES (?, ?, ?, ?, ?)"); - $groupMap = []; + try { + $rows = parse_import_file($_FILES['csv_file']); + + if ($rows) { + $db->beginTransaction(); + $stmt = $db->prepare("INSERT INTO laboratory_tests (name_en, name_ar, group_id, price, normal_range) VALUES (?, ?, ?, ?, ?)"); + $groupMap = []; - foreach ($rows as $row) { - $name_en = $row[0] ?? ''; - $name_ar = $row[1] ?? ''; - $group_name = $row[2] ?? ''; - $price = $row[3] ?? 0; - $range = $row[4] ?? ''; - - if ($name_en) { - $group_id = null; - if ($group_name) { - if (isset($groupMap[$group_name])) { - $group_id = $groupMap[$group_name]; - } else { - $gStmt = $db->prepare("SELECT id FROM test_groups WHERE name_en = ? OR name_ar = ?"); - $gStmt->execute([$group_name, $group_name]); - $gRes = $gStmt->fetch(); - if ($gRes) { - $group_id = $gRes['id']; + foreach ($rows as $row) { + $name_en = $row[0] ?? ''; + $name_ar = $row[1] ?? ''; + $group_name = $row[2] ?? ''; + $price = $row[3] ?? 0; + $range = $row[4] ?? ''; + + if ($name_en) { + $group_id = null; + if ($group_name) { + if (isset($groupMap[$group_name])) { + $group_id = $groupMap[$group_name]; } else { - $cgStmt = $db->prepare("INSERT INTO test_groups (name_en, name_ar) VALUES (?, ?)"); - $cgStmt->execute([$group_name, $group_name]); - $group_id = $db->lastInsertId(); + $gStmt = $db->prepare("SELECT id FROM test_groups WHERE name_en = ? OR name_ar = ?"); + $gStmt->execute([$group_name, $group_name]); + $gRes = $gStmt->fetch(); + if ($gRes) { + $group_id = $gRes['id']; + } else { + $cgStmt = $db->prepare("INSERT INTO test_groups (name_en, name_ar) VALUES (?, ?)"); + $cgStmt->execute([$group_name, $group_name]); + $group_id = $db->lastInsertId(); + } + $groupMap[$group_name] = $group_id; } - $groupMap[$group_name] = $group_id; } + $stmt->execute([$name_en, $name_ar, $group_id, $price, $range]); } - $stmt->execute([$name_en, $name_ar, $group_id, $price, $range]); } + $db->commit(); + $_SESSION['flash_message'] = __('import_successfully'); + $redirect = true; + } else { + $_SESSION['flash_message'] = $_SESSION['import_error'] ?? 'Failed to parse file or empty.'; unset($_SESSION['import_error']); + $redirect = true; } - $_SESSION['flash_message'] = __('import_successfully'); + } catch (Throwable $e) { + if ($db->inTransaction()) { + $db->rollBack(); + } + error_log("Import Error: " . $e->getMessage()); + $_SESSION['flash_message'] = 'Error: ' . $e->getMessage(); $redirect = true; } } diff --git a/includes/common_data.php b/includes/common_data.php index 6cc20d5..68011b5 100644 --- a/includes/common_data.php +++ b/includes/common_data.php @@ -1,7 +1,7 @@ query("SELECT id, name_$lang as name FROM doctors")->fetchAll(); -$all_patients = $db->query("SELECT id, name FROM patients")->fetchAll(); +$all_patients = $db->query("SELECT id, name, dob, gender FROM patients")->fetchAll(); $all_nurses = $db->query("SELECT id, name_$lang as name FROM nurses")->fetchAll(); $all_departments = $db->query("SELECT id, name_$lang as name FROM departments")->fetchAll(); $all_employees = $db->query("SELECT id, name_$lang as name FROM employees")->fetchAll(); diff --git a/includes/layout/header.php b/includes/layout/header.php index 96f3754..7e5d003 100644 --- a/includes/layout/header.php +++ b/includes/layout/header.php @@ -7,6 +7,12 @@ $lang = $_SESSION['lang']; $section = $section ?? 'dashboard'; $message = $message ?? ''; +// Check for flash message in session +if (isset($_SESSION['flash_message'])) { + $message = $_SESSION['flash_message']; + unset($_SESSION['flash_message']); +} + // Fetch company settings for dynamic branding $stmt = $db->query("SELECT setting_key, setting_value FROM settings WHERE setting_key IN ('company_name', 'company_logo', 'company_favicon')"); $site_settings = []; diff --git a/includes/pages/drugs_groups.php b/includes/pages/drugs_groups.php index d1319c1..1add878 100644 --- a/includes/pages/drugs_groups.php +++ b/includes/pages/drugs_groups.php @@ -108,7 +108,7 @@ $groups = $stmt->fetchAll();