From b5ea341aa58e4f24b33eac602e24c36b6d9c007d Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 21 Mar 2026 14:06:06 +0000 Subject: [PATCH] Autosave: 20260321-140606 --- .gemini/GEMINI_LAST_MESSAGE.txt | 26 +- check_patients_table.php | 9 - .../20260321_create_insurance_payments.sql | 10 + ...d_payment_method_to_insurance_payments.sql | 1 + helpers.php | 21 +- includes/actions.php | 74 +- includes/layout/header.php | 12 +- includes/pages/billing.php | 6 +- includes/pages/dashboard.php | 18 +- includes/pages/drugs.php | 9 +- includes/pages/insurance.php | 989 +++++++++++++++--- includes/pages/laboratory_tests.php | 11 +- includes/pages/pharmacy_pos.php | 13 +- includes/pages/pharmacy_purchase_returns.php | 8 +- includes/pages/pharmacy_purchases.php | 8 +- includes/pages/pharmacy_sales.php | 8 +- includes/pages/services.php | 5 +- includes/pages/settings.php | 23 +- includes/pages/xray_tests.php | 9 +- insurance.php | 6 + lang.php | 55 +- print_bill.php | 8 +- print_insurance_statement.php | 191 ++++ print_pharmacy_receipt.php | 13 +- print_pharmacy_report.php | 20 +- settings.php | 13 +- 26 files changed, 1311 insertions(+), 255 deletions(-) delete mode 100644 check_patients_table.php create mode 100644 db/migrations/20260321_create_insurance_payments.sql create mode 100644 db/migrations/20260321_z_add_payment_method_to_insurance_payments.sql create mode 100644 print_insurance_statement.php diff --git a/.gemini/GEMINI_LAST_MESSAGE.txt b/.gemini/GEMINI_LAST_MESSAGE.txt index 4f250e6..e4047b0 100644 --- a/.gemini/GEMINI_LAST_MESSAGE.txt +++ b/.gemini/GEMINI_LAST_MESSAGE.txt @@ -1,19 +1,13 @@ Plan: -1. **Fix 500 Error:** I identified and fixed a critical syntax error in `includes/actions.php` (a missing quote in the SQL query) that was crashing the application. -2. **Restore Token Logic:** I carefully re-implemented the token generation code in `includes/actions.php` to ensure it works correctly without breaking the visit recording process. -3. **Add Missing UI:** I added the **"Issue Token"** checkbox to the "Details" tab of the "Add Visit" modal in `includes/layout/footer.php`, which was missing from the previous attempt. -4. **Verify Integrity:** I confirmed that the `patient_queue` database table exists and that all new files (`queue.php`, `api/queue.php`, `queue_display.php`) have valid syntax. +1. **Investigate:** Checked Apache error logs and `includes/actions.php`. +2. **Identify Issue:** Found a mismatch between the database schema for `insurance_payments` (missing `payment_method` column) and the PHP code trying to insert into it. +3. **Fix:** Created and applied a migration to add the `payment_method` column to the `insurance_payments` table. +4. **Verify:** Confirmed the column now exists in the database. -Changed: -* `includes/actions.php`: Fixed a syntax error and correctly implemented the token generation logic. -* `includes/layout/footer.php`: Added the "Issue Token" checkbox to the "Details" tab of the `recordVisitModal`. +Changed Files: +* `db/migrations/20260321_z_add_payment_method_to_insurance_payments.sql`: Added migration to fix the schema. -Notes: -* The application should now load correctly without the 500 error. -* To use the token system: - 1. **Receptionist:** When adding a new visit, check the **"Issue Token"** box in the "Details" tab. - 2. **Queue Management:** Go to **"Queue Management"** in the sidebar to manage the queue (Call, Finish). - 3. **Display:** Click **"Open TV Display"** to open the public waiting list on a separate screen. -* Reminder: click Save in the editor to sync changes. - -Next: Please refresh your browser and try adding a visit with the "Issue Token" checkbox checked. Let me know if everything works as expected! \ No newline at end of file +Next Steps: +* Go to **Insurance > Transactions**. +* Try adding a transaction again. It should work now. +* **Reminder:** Click Save in the editor to sync changes. \ No newline at end of file diff --git a/check_patients_table.php b/check_patients_table.php deleted file mode 100644 index 469ea02..0000000 --- a/check_patients_table.php +++ /dev/null @@ -1,9 +0,0 @@ -query("DESCRIBE patients"); -$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); -foreach ($rows as $row) { - echo $row['Field'] . "\n"; -} - diff --git a/db/migrations/20260321_create_insurance_payments.sql b/db/migrations/20260321_create_insurance_payments.sql new file mode 100644 index 0000000..e044d07 --- /dev/null +++ b/db/migrations/20260321_create_insurance_payments.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS insurance_payments ( + id INT AUTO_INCREMENT PRIMARY KEY, + insurance_company_id INT NOT NULL, + amount DECIMAL(10, 2) NOT NULL, + payment_date DATE NOT NULL, + reference_number VARCHAR(100) DEFAULT NULL, + notes TEXT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (insurance_company_id) REFERENCES insurance_companies(id) ON DELETE CASCADE +); diff --git a/db/migrations/20260321_z_add_payment_method_to_insurance_payments.sql b/db/migrations/20260321_z_add_payment_method_to_insurance_payments.sql new file mode 100644 index 0000000..cab17fa --- /dev/null +++ b/db/migrations/20260321_z_add_payment_method_to_insurance_payments.sql @@ -0,0 +1 @@ +ALTER TABLE insurance_payments ADD COLUMN payment_method VARCHAR(50) DEFAULT 'Check' AFTER reference_number; diff --git a/helpers.php b/helpers.php index 6deb90a..5799547 100644 --- a/helpers.php +++ b/helpers.php @@ -1,24 +1,34 @@ query('SELECT setting_key, setting_value FROM settings'); $settings = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $settings[$row['setting_key']] = $row['setting_value']; } + $SYSTEM_SETTINGS = $settings; return $settings; } catch (Exception $e) { return []; } } + function apply_timezone() { $s = get_system_settings(); if (!empty($s['timezone'])) { @@ -27,6 +37,13 @@ function apply_timezone() { } apply_timezone(); +function format_currency($amount) { + $settings = get_system_settings(); + $currency_symbol = $settings['currency_symbol'] ?? '$'; + $decimal_digits = isset($settings['decimal_digits']) ? (int)$settings['decimal_digits'] : 2; + + return $currency_symbol . ' ' . number_format((float)$amount, $decimal_digits); +} session_start(); require_once __DIR__ . '/lang.php'; @@ -97,4 +114,4 @@ if (!function_exists('mb_strimwidth')) { return substr($string, 0, $targetLen) . $trimmarker; } -} \ No newline at end of file +} diff --git a/includes/actions.php b/includes/actions.php index adc4699..48f9ac9 100644 --- a/includes/actions.php +++ b/includes/actions.php @@ -1,5 +1,5 @@ prepare("INSERT INTO insurance_companies (name_en, name_ar, email, phone, discount_percentage) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$name_en, $name_ar, $email, $phone, $discount]); + $_SESSION['flash_message'] = __('add_insurance') . ' ' . __('successfully'); + $redirect = true; + } + } elseif ($_POST['action'] === 'edit_insurance') { + $id = $_POST['id'] ?? ''; + $name_en = $_POST['name_en'] ?? ''; + $name_ar = $_POST['name_ar'] ?? ''; + $email = $_POST['email'] ?? ''; + $phone = $_POST['phone'] ?? ''; + $discount = $_POST['discount_percentage'] ?? 0; + + if ($id && $name_en && $name_ar) { + $stmt = $db->prepare("UPDATE insurance_companies SET name_en = ?, name_ar = ?, email = ?, phone = ?, discount_percentage = ? WHERE id = ?"); + $stmt->execute([$name_en, $name_ar, $email, $phone, $discount, $id]); + $_SESSION['flash_message'] = __('edit') . ' ' . __('successfully'); + $redirect = true; + } + } elseif ($_POST['action'] === 'delete_insurance') { + $id = $_POST['id'] ?? ''; + if ($id) { + $stmt = $db->prepare("DELETE FROM insurance_companies WHERE id = ?"); + $stmt->execute([$id]); + $_SESSION['flash_message'] = __('delete') . ' ' . __('successfully'); + $redirect = true; + } + } elseif ($_POST['action'] === 'add_transaction') { + $insurance_company_id = $_POST['insurance_company_id'] ?: null; + $amount = $_POST['amount'] ?? 0; + $date = $_POST['payment_date'] ?? date('Y-m-d'); + $ref = $_POST['reference_number'] ?? ''; + $method = $_POST['payment_method'] ?? 'Check'; + $notes = $_POST['notes'] ?? ''; + + if ($insurance_company_id && $amount) { + $stmt = $db->prepare("INSERT INTO insurance_payments (insurance_company_id, amount, payment_date, reference_number, payment_method, notes) VALUES (?, ?, ?, ?, ?, ?)"); + $stmt->execute([$insurance_company_id, $amount, $date, $ref, $method, $notes]); + $_SESSION['flash_message'] = __('transaction_added_success'); + $redirect = true; + } + } elseif ($_POST['action'] === 'edit_transaction') { + $id = $_POST['id'] ?? ''; + $insurance_company_id = $_POST['insurance_company_id'] ?: null; + $amount = $_POST['amount'] ?? 0; + $date = $_POST['payment_date'] ?? date('Y-m-d'); + $ref = $_POST['reference_number'] ?? ''; + $method = $_POST['payment_method'] ?? 'Check'; + $notes = $_POST['notes'] ?? ''; + + if ($id && $insurance_company_id && $amount) { + $stmt = $db->prepare("UPDATE insurance_payments SET insurance_company_id = ?, amount = ?, payment_date = ?, reference_number = ?, payment_method = ?, notes = ? WHERE id = ?"); + $stmt->execute([$insurance_company_id, $amount, $date, $ref, $method, $notes, $id]); + $_SESSION['flash_message'] = __('transaction_updated_success'); + $redirect = true; + } + } elseif ($_POST['action'] === 'delete_transaction') { + $id = $_POST['id'] ?? ''; + if ($id) { + $stmt = $db->prepare("DELETE FROM insurance_payments WHERE id = ?"); + $stmt->execute([$id]); + $_SESSION['flash_message'] = __('transaction_deleted_success'); + $redirect = true; + } } } diff --git a/includes/layout/header.php b/includes/layout/header.php index 0f7e7af..8756560 100644 --- a/includes/layout/header.php +++ b/includes/layout/header.php @@ -48,6 +48,16 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp + + + + + +
+
+ + +
+ +
+ +
+
+
+ + + +

+ +
+
+ :
+ : +
+
+
+

+

+

+ : - +

+
+
+
+ + +
+
+
:
+
+

+ '; ?> + +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#
+ + +
+ +
+ + + +
+
+ + + diff --git a/print_pharmacy_receipt.php b/print_pharmacy_receipt.php index 0c92223..568f886 100644 --- a/print_pharmacy_receipt.php +++ b/print_pharmacy_receipt.php @@ -48,8 +48,11 @@ try { $items = $stmt->fetchAll(); // Fetch Company Settings (Logo, Address, etc.) - $stmt = $db->query("SELECT * FROM settings WHERE id = 1"); - $settings = $stmt->fetch(); + $stmt = $db->query("SELECT setting_key, setting_value FROM settings"); + $settings = []; + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $settings[$row['setting_key']] = $row['setting_value']; + } } catch (Exception $e) { die("Error: " . $e->getMessage()); @@ -178,8 +181,8 @@ try { - - + + @@ -189,7 +192,7 @@ try { TOTAL / الإجمالي - + diff --git a/print_pharmacy_report.php b/print_pharmacy_report.php index f6d81ba..ff9c227 100644 --- a/print_pharmacy_report.php +++ b/print_pharmacy_report.php @@ -209,17 +209,17 @@ if ($type === 'inventory_valuation') { - - - - + + + + # - + @@ -242,7 +242,7 @@ if ($type === 'inventory_valuation') { # - + @@ -255,18 +255,18 @@ if ($type === 'inventory_valuation') { : - - + + : - + : - + diff --git a/settings.php b/settings.php index caa5000..e1bae39 100644 --- a/settings.php +++ b/settings.php @@ -10,8 +10,9 @@ $message = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { foreach ($_POST as $key => $value) { if ($key !== 'submit') { - $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = ?"); - $stmt->execute([$value, $key]); + // Use INSERT ... ON DUPLICATE KEY UPDATE to handle both new and existing settings + $stmt = $db->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); + $stmt->execute([$key, $value]); } } @@ -25,7 +26,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $ext = pathinfo($_FILES['company_logo']['name'], PATHINFO_EXTENSION); $logo_name = 'logo_' . time() . '.' . $ext; move_uploaded_file($_FILES['company_logo']['tmp_name'], $upload_dir . $logo_name); - $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'company_logo'"); + + $stmt = $db->prepare("INSERT INTO settings (setting_key, setting_value) VALUES ('company_logo', ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); $stmt->execute(['assets/images/' . $logo_name]); } @@ -33,7 +35,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $ext = pathinfo($_FILES['company_favicon']['name'], PATHINFO_EXTENSION); $favicon_name = 'favicon_' . time() . '.' . $ext; move_uploaded_file($_FILES['company_favicon']['tmp_name'], $upload_dir . $favicon_name); - $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'company_favicon'"); + + $stmt = $db->prepare("INSERT INTO settings (setting_key, setting_value) VALUES ('company_favicon', ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); $stmt->execute(['assets/images/' . $favicon_name]); } @@ -51,4 +54,4 @@ require_once __DIR__ . '/includes/actions.php'; require_once __DIR__ . '/includes/common_data.php'; require_once __DIR__ . '/includes/layout/header.php'; require_once __DIR__ . '/includes/pages/settings.php'; -require_once __DIR__ . '/includes/layout/footer.php'; +require_once __DIR__ . '/includes/layout/footer.php'; \ No newline at end of file