Autosave: 20260321-140606
This commit is contained in:
parent
dad73767a1
commit
b5ea341aa5
@ -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!
|
||||
Next Steps:
|
||||
* Go to **Insurance > Transactions**.
|
||||
* Try adding a transaction again. It should work now.
|
||||
* **Reminder:** Click Save in the editor to sync changes.
|
||||
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("DESCRIBE patients");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($rows as $row) {
|
||||
echo $row['Field'] . "\n";
|
||||
}
|
||||
|
||||
10
db/migrations/20260321_create_insurance_payments.sql
Normal file
10
db/migrations/20260321_create_insurance_payments.sql
Normal file
@ -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
|
||||
);
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE insurance_payments ADD COLUMN payment_method VARCHAR(50) DEFAULT 'Check' AFTER reference_number;
|
||||
19
helpers.php
19
helpers.php
@ -1,24 +1,34 @@
|
||||
<?php
|
||||
|
||||
$SYSTEM_SETTINGS = null;
|
||||
|
||||
function get_system_settings() {
|
||||
global $db; // Assuming db() is already initialized or we can initialize it
|
||||
global $db, $SYSTEM_SETTINGS;
|
||||
|
||||
if ($SYSTEM_SETTINGS !== null) {
|
||||
return $SYSTEM_SETTINGS;
|
||||
}
|
||||
|
||||
if (!isset($db)) {
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
$local_db = db();
|
||||
} else {
|
||||
$local_db = $db;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $local_db->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';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/../helpers.php';
|
||||
$db = db();
|
||||
@ -1130,6 +1130,78 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$_SESSION['flash_message'] = __('delete') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'add_insurance') {
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
$discount = $_POST['discount_percentage'] ?? 0;
|
||||
|
||||
if ($name_en && $name_ar) {
|
||||
$stmt = $db->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +48,16 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
|
||||
<!-- Flatpickr CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
|
||||
<script>
|
||||
const SYSTEM_SETTINGS = <?php echo json_encode(get_system_settings()); ?>;
|
||||
const CURRENCY_SYMBOL = SYSTEM_SETTINGS.currency_symbol || '$';
|
||||
const DECIMAL_DIGITS = parseInt(SYSTEM_SETTINGS.decimal_digits || 2);
|
||||
|
||||
function formatCurrency(amount) {
|
||||
return CURRENCY_SYMBOL + ' ' + parseFloat(amount).toFixed(DECIMAL_DIGITS);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body { font-family: 'Inter', 'Tajawal', sans-serif; background-color: #f4f7f6; }
|
||||
.sidebar { min-height: 100vh; width: 250px; background-color: #002D62; color: white; transition: all 0.3s; flex-shrink: 0; }
|
||||
|
||||
@ -82,9 +82,9 @@ $bills = $stmt->fetchAll();
|
||||
<td class="px-4 text-secondary">#<?php echo $b['id']; ?></td>
|
||||
<td class="text-secondary"><?php echo date('Y-m-d H:i', strtotime($b['created_at'])); ?></td>
|
||||
<td class="fw-semibold text-dark"><?php echo htmlspecialchars($b['patient_name']); ?></td>
|
||||
<td class="text-dark">$<?php echo number_format($b['total_amount'], 2); ?></td>
|
||||
<td class="text-primary">$<?php echo number_format($b['insurance_covered'], 2); ?></td>
|
||||
<td class="fw-bold text-dark">$<?php echo number_format($b['patient_payable'], 2); ?></td>
|
||||
<td class="text-dark"><?php echo format_currency($b['total_amount']); ?></td>
|
||||
<td class="text-primary"><?php echo format_currency($b['insurance_covered']); ?></td>
|
||||
<td class="fw-bold text-dark"><?php echo format_currency($b['patient_payable']); ?></td>
|
||||
<td>
|
||||
<span class="badge <?php echo $b['status'] === 'Paid' ? 'bg-success bg-opacity-10 text-success border border-success border-opacity-25' : 'bg-warning bg-opacity-10 text-warning border border-warning border-opacity-25'; ?> px-2 py-1">
|
||||
<?php echo __($b['status']); ?>
|
||||
|
||||
@ -135,14 +135,14 @@ $appointments = $db->query($appointments_sql)->fetchAll();
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card stat-card h-100">
|
||||
<i class="bi bi-currency-dollar text-success"></i>
|
||||
<h3>$<?php echo number_format($total_revenue, 2); ?></h3>
|
||||
<h3><?php echo format_currency($total_revenue); ?></h3>
|
||||
<p class="text-muted mb-0"><?php echo __('revenue'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card stat-card h-100">
|
||||
<i class="bi bi-hourglass-split text-warning"></i>
|
||||
<h3>$<?php echo number_format($pending_revenue, 2); ?></h3>
|
||||
<h3><?php echo format_currency($pending_revenue); ?></h3>
|
||||
<p class="text-muted mb-0"><?php echo __('pending'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
@ -502,10 +502,10 @@ $appointments = $db->query($appointments_sql)->fetchAll();
|
||||
<select id="checkout_service_select" class="form-select form-select-sm select2-modal-checkout">
|
||||
<option value=""><?php echo __('select_service'); ?>...</option>
|
||||
<?php foreach ($all_services as $s): ?>
|
||||
<option value="<?php echo $s['name']; ?>" data-price="<?php echo $s['price']; ?>"><?php echo htmlspecialchars($s['name']); ?> ($<?php echo $s['price']; ?>)</option>
|
||||
<option value="<?php echo $s['name']; ?>" data-price="<?php echo $s['price']; ?>"><?php echo htmlspecialchars($s['name']); ?> (<?php echo format_currency($s['price']); ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($all_tests as $t): ?>
|
||||
<option value="<?php echo $t['name']; ?>" data-price="<?php echo $t['price']; ?>"><?php echo htmlspecialchars($t['name']); ?> ($<?php echo $t['price']; ?>)</option>
|
||||
<option value="<?php echo $t['name']; ?>" data-price="<?php echo $t['price']; ?>"><?php echo htmlspecialchars($t['name']); ?> (<?php echo format_currency($t['price']); ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
@ -557,14 +557,14 @@ $appointments = $db->query($appointments_sql)->fetchAll();
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small text-muted">Insurance Pays</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<span class="input-group-text"><?php echo $currency_symbol ?? '$'; ?></span>
|
||||
<input type="number" id="checkout_insurance_amount" class="form-control" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small text-muted fw-bold text-dark">Patient Pays</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<span class="input-group-text"><?php echo $currency_symbol ?? '$'; ?></span>
|
||||
<input type="number" id="checkout_patient_amount" class="form-control fw-bold" readonly>
|
||||
</div>
|
||||
</div>
|
||||
@ -646,7 +646,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
var text = element.text();
|
||||
|
||||
if (price) {
|
||||
document.getElementById('checkout_custom_item').value = text.split(' ($')[0];
|
||||
document.getElementById('checkout_custom_item').value = text.split(' (')[0];
|
||||
document.getElementById('checkout_item_price').value = price;
|
||||
}
|
||||
});
|
||||
@ -790,7 +790,7 @@ function renderBillItems(items) {
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td>${item.description}</td>
|
||||
<td class="text-end">$${parseFloat(item.amount).toFixed(2)}</td>
|
||||
<td class="text-end">${formatCurrency(item.amount)}</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-sm btn-link text-danger p-0" onclick="removeBillItem(${item.id})"><i class="bi bi-x-lg"></i></button>
|
||||
</td>
|
||||
@ -799,7 +799,7 @@ function renderBillItems(items) {
|
||||
});
|
||||
|
||||
currentTotal = total;
|
||||
document.getElementById('checkout_total_amount').innerText = '$' + total.toFixed(2);
|
||||
document.getElementById('checkout_total_amount').innerText = formatCurrency(total);
|
||||
calculateTotals();
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +48,9 @@ $all_drug_groups = $gStmt->fetchAll();
|
||||
$sStmt = $db->query("SELECT * FROM suppliers ORDER BY name_$lang");
|
||||
$all_suppliers = $sStmt->fetchAll();
|
||||
|
||||
$sys_settings = get_system_settings();
|
||||
$currency_symbol = $sys_settings['currency_symbol'] ?? '$';
|
||||
|
||||
// --- AJAX HANDLER ---
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
ob_start();
|
||||
@ -81,7 +84,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
</td>
|
||||
<td class="text-nowrap"><?php echo htmlspecialchars($drug['expiry_date'] ?? '-'); ?></td>
|
||||
<td class="text-wrap" style="max-width: 150px;"><?php echo htmlspecialchars($drug['supplier_name'] ?? '-'); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($drug['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($drug['price']); ?></td>
|
||||
<td class="text-end px-4 text-nowrap">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -240,7 +243,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
</td>
|
||||
<td class="text-nowrap"><?php echo htmlspecialchars($drug['expiry_date'] ?? '-'); ?></td>
|
||||
<td class="text-wrap" style="max-width: 150px;"><?php echo htmlspecialchars($drug['supplier_name'] ?? '-'); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($drug['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($drug['price']); ?></td>
|
||||
<td class="text-end px-4 text-nowrap">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -362,7 +365,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('price'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<span class="input-group-text"><?php echo htmlspecialchars($currency_symbol); ?></span>
|
||||
<input type="number" step="0.01" class="form-control" name="price" id="drugPrice">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -42,6 +42,9 @@ $tests = $stmt->fetchAll();
|
||||
$gStmt = $db->query("SELECT * FROM test_groups ORDER BY name_$lang");
|
||||
$all_test_groups = $gStmt->fetchAll();
|
||||
|
||||
$sys_settings = get_system_settings();
|
||||
$currency_symbol = $sys_settings['currency_symbol'] ?? '$';
|
||||
|
||||
// --- AJAX HANDLER ---
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
ob_start();
|
||||
@ -78,7 +81,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<?php echo htmlspecialchars($test['normal_range'] ?? '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($test['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($test['price']); ?></td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -239,7 +242,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<?php echo htmlspecialchars($test['normal_range'] ?? '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($test['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($test['price']); ?></td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -377,7 +380,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('price'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<span class="input-group-text"><?php echo htmlspecialchars($currency_symbol); ?></span>
|
||||
<input type="number" step="0.01" class="form-control" name="price" id="testPrice">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -155,7 +155,7 @@ function fetchDrugs(query = '') {
|
||||
<small class="text-muted">${skuHtml}${drug.name_ar || ''}</small>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold text-primary">${price.toFixed(2)}</div>
|
||||
<div class="fw-bold text-primary">${formatCurrency(price)}</div>
|
||||
<small class="${isOutOfStock ? 'text-danger' : 'text-success'}">
|
||||
${isOutOfStock ? '<?php echo __('out_of_stock'); ?>' : '<?php echo __('stock'); ?>: ' + stock}
|
||||
</small>
|
||||
@ -243,7 +243,7 @@ function renderCart() {
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-bold text-truncate" style="max-width: 180px;">${item.name}</div>
|
||||
<small class="text-muted">${item.price.toFixed(2)}</small>
|
||||
<small class="text-muted">${formatCurrency(item.price)}</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="input-group input-group-sm">
|
||||
@ -252,7 +252,7 @@ function renderCart() {
|
||||
<button class="btn btn-outline-secondary" onclick="updateQty(${item.id}, 1)">+</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-end fw-bold">${itemTotal.toFixed(2)}</td>
|
||||
<td class="text-end fw-bold">${formatCurrency(itemTotal)}</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-link text-danger p-0" onclick="updateQty(${item.id}, -1000)"><i class="bi bi-trash"></i></button>
|
||||
</td>
|
||||
@ -260,9 +260,9 @@ function renderCart() {
|
||||
`;
|
||||
});
|
||||
|
||||
cartTotalEl.textContent = total.toFixed(2);
|
||||
cartTotalEl.textContent = formatCurrency(total);
|
||||
cartCountEl.textContent = cart.length;
|
||||
checkoutTotalEl.textContent = total.toFixed(2);
|
||||
checkoutTotalEl.textContent = formatCurrency(total);
|
||||
|
||||
if (cart.length === 0) {
|
||||
cartTableBody.innerHTML = '<tr><td colspan="4" class="text-center text-muted py-4"><?php echo __('cart_empty'); ?></td></tr>';
|
||||
@ -282,12 +282,13 @@ function showCheckout() {
|
||||
function processSale() {
|
||||
const patientId = $('#patientSelect').val();
|
||||
const paymentMethod = document.querySelector('input[name="payment_method"]:checked').value;
|
||||
const total = cart.reduce((sum, item) => sum + (item.quantity * item.price), 0);
|
||||
|
||||
const payload = {
|
||||
patient_id: patientId || null,
|
||||
visit_id: null,
|
||||
payment_method: paymentMethod,
|
||||
total_amount: parseFloat(cartTotalEl.textContent),
|
||||
total_amount: total,
|
||||
items: cart.map(i => ({
|
||||
drug_id: i.id,
|
||||
quantity: i.quantity,
|
||||
|
||||
@ -211,7 +211,7 @@ function loadReturns(page = 1) {
|
||||
<td>${r.id}</td>
|
||||
<td>${r.return_date}</td>
|
||||
<td>${r.supplier_name || '-'}</td>
|
||||
<td class="fw-bold text-danger">$${parseFloat(r.total_amount).toFixed(2)}</td>
|
||||
<td class="fw-bold text-danger">${formatCurrency(r.total_amount)}</td>
|
||||
<td>${r.reason || '-'}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="viewReturn(${r.id}, '${r.supplier_name}', '${r.return_date}', '${r.total_amount}', '${r.reason || ''}')">
|
||||
@ -440,7 +440,7 @@ function viewReturn(id, supplier, date, total, reason) {
|
||||
document.getElementById('view_return_id').innerText = id;
|
||||
document.getElementById('view_return_supplier').innerText = supplier;
|
||||
document.getElementById('view_return_date').innerText = date;
|
||||
document.getElementById('view_return_total').innerText = '$' + parseFloat(total).toFixed(2);
|
||||
document.getElementById('view_return_total').innerText = formatCurrency(total);
|
||||
document.getElementById('view_return_reason').innerText = reason;
|
||||
|
||||
const tbody = document.getElementById('viewReturnItemsBody');
|
||||
@ -459,8 +459,8 @@ function viewReturn(id, supplier, date, total, reason) {
|
||||
<td>${item.drug_name} <small class="text-muted">(${item.sku || '-'})</small></td>
|
||||
<td>${item.batch_number || '-'}</td>
|
||||
<td class="text-center">${item.quantity}</td>
|
||||
<td class="text-end">$${parseFloat(item.unit_price).toFixed(2)}</td>
|
||||
<td class="text-end">$${parseFloat(item.total_price).toFixed(2)}</td>
|
||||
<td class="text-end">${formatCurrency(item.unit_price)}</td>
|
||||
<td class="text-end">${formatCurrency(item.total_price)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
@ -264,7 +264,7 @@ function loadPurchases(page = 1) {
|
||||
<td>${p.id}</td>
|
||||
<td>${p.lpo_date}</td>
|
||||
<td>${p.supplier_name || '-'}</td>
|
||||
<td class="fw-bold text-success">$${parseFloat(p.total_amount).toFixed(2)}</td>
|
||||
<td class="fw-bold text-success">${formatCurrency(p.total_amount)}</td>
|
||||
<td>${statusBadge}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="viewPurchase(${p.id}, '${p.supplier_name}', '${p.lpo_date}', '${p.total_amount}', '${p.status}', '${p.notes || ''}')">
|
||||
@ -453,7 +453,7 @@ function viewPurchase(id, supplier, date, total, status, notes) {
|
||||
document.getElementById('view_purchase_id').innerText = id;
|
||||
document.getElementById('view_purchase_supplier').innerText = supplier;
|
||||
document.getElementById('view_purchase_date').innerText = date;
|
||||
document.getElementById('view_purchase_total').innerText = '$' + parseFloat(total).toFixed(2);
|
||||
document.getElementById('view_purchase_total').innerText = formatCurrency(total);
|
||||
document.getElementById('view_purchase_status').innerText = status;
|
||||
document.getElementById('view_purchase_notes').innerText = notes;
|
||||
|
||||
@ -474,8 +474,8 @@ function viewPurchase(id, supplier, date, total, status, notes) {
|
||||
<td>${item.batch_number || '-'}</td>
|
||||
<td>${item.expiry_date || '-'}</td>
|
||||
<td class="text-center">${item.quantity}</td>
|
||||
<td class="text-end">$${parseFloat(item.cost_price).toFixed(2)}</td>
|
||||
<td class="text-end">$${parseFloat(item.total_cost).toFixed(2)}</td>
|
||||
<td class="text-end">${formatCurrency(item.cost_price)}</td>
|
||||
<td class="text-end">${formatCurrency(item.total_cost)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
@ -72,7 +72,7 @@ $sales = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo $item_count_stmt->fetchColumn() . ' ' . __('items');
|
||||
?>
|
||||
</td>
|
||||
<td class="fw-bold"><?php echo number_format($sale['total_amount'], 2); ?></td>
|
||||
<td class="fw-bold"><?php echo format_currency($sale['total_amount']); ?></td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark border">
|
||||
<?php echo ucfirst($sale['payment_method']); ?>
|
||||
@ -171,8 +171,8 @@ function viewReceipt(saleId) {
|
||||
<tr>
|
||||
<td>${item.drug_name}</td>
|
||||
<td class="text-end">${item.quantity}</td>
|
||||
<td class="text-end">${parseFloat(item.unit_price).toFixed(2)}</td>
|
||||
<td class="text-end">${parseFloat(item.total_price).toFixed(2)}</td>
|
||||
<td class="text-end">${formatCurrency(item.unit_price)}</td>
|
||||
<td class="text-end">${formatCurrency(item.total_price)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
@ -182,7 +182,7 @@ function viewReceipt(saleId) {
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="3" class="text-end pt-3">Total Amount</td>
|
||||
<td class="text-end pt-3 fs-5">${parseFloat(data.total_amount).toFixed(2)}</td>
|
||||
<td class="text-end pt-3 fs-5">${formatCurrency(data.total_amount)}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
@ -43,6 +43,9 @@ $query = "
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$services = $stmt->fetchAll();
|
||||
|
||||
$sys_settings = get_system_settings();
|
||||
$currency_symbol = $sys_settings['currency_symbol'] ?? '$';
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
@ -113,7 +116,7 @@ $services = $stmt->fetchAll();
|
||||
</span>
|
||||
</td>
|
||||
<td class="fw-bold text-success">
|
||||
<?php echo number_format($s['price'], 2); ?>
|
||||
<?php echo format_currency($s['price']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($s['is_active']): ?>
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
<input type="text" class="form-control" id="company_vat_no" name="company_vat_no" value="<?php echo htmlspecialchars($settings['company_vat_no'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<!-- Timezone & Working Hours -->
|
||||
<!-- Timezone & Working Hours -->
|
||||
<div class="col-12 mt-4"><hr></div>
|
||||
<div class="col-md-4">
|
||||
<label for="timezone" class="form-label fw-semibold text-muted small text-uppercase"><?php echo __('timezone'); ?></label>
|
||||
@ -75,8 +75,23 @@
|
||||
<input type="time" class="form-control" id="working_hours_end" name="working_hours_end" value="<?php echo htmlspecialchars($settings['working_hours_end'] ?? '17:00'); ?>">
|
||||
</div>
|
||||
|
||||
<!-- Currency Settings -->
|
||||
<div class="col-12 mt-4"><hr></div>
|
||||
<div class="col-12 mb-2">
|
||||
<h6 class="fw-bold text-dark"><i class="bi bi-cash-coin me-2"></i> <?php echo __('currency_settings'); ?></h6>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="currency_symbol" class="form-label fw-semibold text-muted small text-uppercase"><?php echo __('currency_symbol'); ?></label>
|
||||
<input type="text" class="form-control" id="currency_symbol" name="currency_symbol" value="<?php echo htmlspecialchars($settings['currency_symbol'] ?? '$'); ?>" placeholder="$">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="decimal_digits" class="form-label fw-semibold text-muted small text-uppercase"><?php echo __('decimal_digits'); ?></label>
|
||||
<input type="number" class="form-control" id="decimal_digits" name="decimal_digits" value="<?php echo htmlspecialchars($settings['decimal_digits'] ?? '2'); ?>" min="0" max="4">
|
||||
</div>
|
||||
|
||||
<!-- Branding -->
|
||||
<div class="col-md-6 mt-5">
|
||||
<div class="col-12 mt-4"><hr></div>
|
||||
<div class="col-md-6 mt-2">
|
||||
<label for="company_logo" class="form-label fw-semibold text-muted small text-uppercase"><?php echo __('company_logo'); ?></label>
|
||||
<?php if (!empty($settings['company_logo'])): ?>
|
||||
<div class="mb-2">
|
||||
@ -85,7 +100,7 @@
|
||||
<?php endif; ?>
|
||||
<input type="file" class="form-control" id="company_logo" name="company_logo" accept="image/*">
|
||||
</div>
|
||||
<div class="col-md-6 mt-5">
|
||||
<div class="col-md-6 mt-2">
|
||||
<label for="company_favicon" class="form-label fw-semibold text-muted small text-uppercase"><?php echo __('company_favicon'); ?></label>
|
||||
<?php if (!empty($settings['company_favicon'])): ?>
|
||||
<div class="mb-2">
|
||||
|
||||
@ -41,6 +41,9 @@ $tests = $stmt->fetchAll();
|
||||
// Fetch all xray groups for the dropdown
|
||||
$all_xray_groups_list = $db->query("SELECT id, name_$lang as name FROM xray_groups ORDER BY name_$lang ASC")->fetchAll();
|
||||
|
||||
$sys_settings = get_system_settings();
|
||||
$currency_symbol = $sys_settings['currency_symbol'] ?? '$';
|
||||
|
||||
// --- AJAX HANDLER ---
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
ob_start();
|
||||
@ -72,7 +75,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<?php echo htmlspecialchars($test['group_name'] ?? '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($test['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($test['price']); ?></td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -222,7 +225,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<?php echo htmlspecialchars($test['group_name'] ?? '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-secondary fw-bold"><?php echo number_format($test['price'], 2); ?></td>
|
||||
<td class="text-secondary fw-bold"><?php echo format_currency($test['price']); ?></td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
@ -332,7 +335,7 @@ if (isset($_GET['ajax_search'])) {
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('price'); ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<span class="input-group-text"><?php echo htmlspecialchars($currency_symbol); ?></span>
|
||||
<input type="number" step="0.01" class="form-control" name="price" id="xrayTestPrice">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -8,6 +8,12 @@ $lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
require_once __DIR__ . '/includes/pages/insurance.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
require_once __DIR__ . '/includes/pages/insurance.php';
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
53
lang.php
53
lang.php
@ -331,6 +331,7 @@ $translations = [
|
||||
'payment_method' => 'Payment Method',
|
||||
'cash' => 'Cash',
|
||||
'card' => 'Card',
|
||||
'insurance' => 'Insurance',
|
||||
'receipt' => 'Receipt',
|
||||
'total_amount' => 'Total Amount',
|
||||
'quantity' => 'Quantity',
|
||||
@ -341,6 +342,8 @@ $translations = [
|
||||
'out_of_stock' => 'Out of Stock',
|
||||
'low_stock' => 'Low Stock',
|
||||
'in_stock' => 'In Stock',
|
||||
'waiting' => 'Waiting',
|
||||
'serving' => 'Serving',
|
||||
'CheckIn' => 'Check In',
|
||||
'In Progress' => 'In Progress',
|
||||
'in_progress' => 'In Progress',
|
||||
@ -398,7 +401,29 @@ $translations = [
|
||||
'receive_warning_msg' => 'Receiving this purchase will add items to stock.',
|
||||
'ensure_batch_expiry_msg' => 'Ensure Batch Numbers and Expiry Dates are correct.',
|
||||
'confirm_received' => 'Confirm Received',
|
||||
'purchase_report' => 'Purchase Report'
|
||||
'purchase_report' => 'Purchase Report',
|
||||
'currency_settings' => 'Currency Settings',
|
||||
'currency_symbol' => 'Currency Symbol',
|
||||
'decimal_digits' => 'Decimal Digits',
|
||||
'statement' => 'Statement',
|
||||
'print_statement' => 'Print Statement',
|
||||
'insurance_transactions' => 'Insurance Transactions',
|
||||
'add_transaction' => 'Add Transaction',
|
||||
'edit_transaction' => 'Edit Transaction',
|
||||
'delete_transaction' => 'Delete Transaction',
|
||||
'payment_date' => 'Payment Date',
|
||||
'reference_number' => 'Reference Number',
|
||||
'no_transactions_found' => 'No transactions found',
|
||||
'confirm_delete_transaction' => 'Are you sure you want to delete this transaction?',
|
||||
'transaction_added_success' => 'Transaction added successfully',
|
||||
'transaction_updated_success' => 'Transaction updated successfully',
|
||||
'transaction_deleted_success' => 'Transaction deleted successfully',
|
||||
'payment_method_check' => 'Check',
|
||||
'payment_method_transfer' => 'Bank Transfer',
|
||||
'payment_method_cash' => 'Cash',
|
||||
'payment_method_card' => 'Credit Card',
|
||||
'transactions' => 'Transactions',
|
||||
'companies' => 'Companies'
|
||||
],
|
||||
'ar' => [
|
||||
'attachment' => 'المرفق',
|
||||
@ -617,7 +642,7 @@ $translations = [
|
||||
'company_logo' => 'شعار الشركة',
|
||||
'company_favicon' => 'أيقونة الشركة',
|
||||
'save_changes' => 'حفظ التغييرات',
|
||||
'settings_updated_successfully' => 'Settings updated successfully',
|
||||
'settings_updated_successfully' => 'تم تحديث الإعدادات بنجاح',
|
||||
'prescriptions' => 'الوصفات الطبية',
|
||||
'add_drug' => 'إضافة دواء',
|
||||
'drug_name' => 'اسم الدواء',
|
||||
@ -813,6 +838,28 @@ $translations = [
|
||||
'receive_warning_msg' => 'استلام هذا الشراء سيضيف العناصر إلى المخزون.',
|
||||
'ensure_batch_expiry_msg' => 'تأكد من صحة أرقام التشغيلات وتواريخ الانتهاء.',
|
||||
'confirm_received' => 'تأكيد الاستلام',
|
||||
'purchase_report' => 'تقرير المشتريات'
|
||||
'purchase_report' => 'تقرير المشتريات',
|
||||
'currency_settings' => 'إعدادات العملة',
|
||||
'currency_symbol' => 'رمز العملة',
|
||||
'decimal_digits' => 'الأرقام العشرية',
|
||||
'statement' => 'كشف حساب',
|
||||
'print_statement' => 'طباعة كشف حساب',
|
||||
'insurance_transactions' => 'معاملات التأمين',
|
||||
'add_transaction' => 'إضافة معاملة',
|
||||
'edit_transaction' => 'تعديل معاملة',
|
||||
'delete_transaction' => 'حذف معاملة',
|
||||
'payment_date' => 'تاريخ الدفع',
|
||||
'reference_number' => 'رقم المرجع',
|
||||
'no_transactions_found' => 'لم يتم العثور على معاملات',
|
||||
'confirm_delete_transaction' => 'هل أنت متأكد من حذف هذه المعاملة؟',
|
||||
'transaction_added_success' => 'تم إضافة المعاملة بنجاح',
|
||||
'transaction_updated_success' => 'تم تحديث المعاملة بنجاح',
|
||||
'transaction_deleted_success' => 'تم حذف المعاملة بنجاح',
|
||||
'payment_method_check' => 'شيك',
|
||||
'payment_method_transfer' => 'تحويل بنكي',
|
||||
'payment_method_cash' => 'نقدي',
|
||||
'payment_method_card' => 'بطاقة ائتمان',
|
||||
'transactions' => 'المعاملات',
|
||||
'companies' => 'الشركات'
|
||||
]
|
||||
];
|
||||
@ -145,24 +145,24 @@ try {
|
||||
<tr>
|
||||
<td class="text-center"><?php echo $i++; ?></td>
|
||||
<td><?php echo htmlspecialchars($item['description']); ?></td>
|
||||
<td class="text-end">$<?php echo number_format($item['amount'], 2); ?></td>
|
||||
<td class="text-end"><?php echo format_currency($item['amount']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2" class="text-end fw-bold">Total Amount</td>
|
||||
<td class="text-end fw-bold">$<?php echo number_format($bill['total_amount'], 2); ?></td>
|
||||
<td class="text-end fw-bold"><?php echo format_currency($bill['total_amount']); ?></td>
|
||||
</tr>
|
||||
<?php if ($bill['insurance_covered'] > 0): ?>
|
||||
<tr>
|
||||
<td colspan="2" class="text-end text-success">Insurance Covered</td>
|
||||
<td class="text-end text-success">-$<?php echo number_format($bill['insurance_covered'], 2); ?></td>
|
||||
<td class="text-end text-success">- <?php echo format_currency($bill['insurance_covered']); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
<td colspan="2" class="text-end fw-bold fs-5">Patient Due</td>
|
||||
<td class="text-end fw-bold fs-5">$<?php echo number_format($bill['patient_payable'], 2); ?></td>
|
||||
<td class="text-end fw-bold fs-5"><?php echo format_currency($bill['patient_payable']); ?></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
191
print_insurance_statement.php
Normal file
191
print_insurance_statement.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
require 'helpers.php';
|
||||
|
||||
// Enable error reporting
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
try {
|
||||
$db = db();
|
||||
$insurance_id = $_GET['id'] ?? 0;
|
||||
$start_date = $_GET['start_date'] ?? date('Y-m-01');
|
||||
$end_date = $_GET['end_date'] ?? date('Y-m-d');
|
||||
|
||||
if (!$insurance_id) {
|
||||
throw new Exception("Invalid Insurance Company ID");
|
||||
}
|
||||
|
||||
// Fetch Insurance Company Details
|
||||
$stmt = $db->prepare("SELECT * FROM insurance_companies WHERE id = ?");
|
||||
$stmt->execute([$insurance_id]);
|
||||
$insurance = $stmt->fetch();
|
||||
|
||||
if (!$insurance) {
|
||||
throw new Exception("Insurance Company not found");
|
||||
}
|
||||
|
||||
// Fetch Linked Bills
|
||||
// Linking via patients table: bills -> patients -> insurance_company_id
|
||||
$query = "
|
||||
SELECT
|
||||
b.*,
|
||||
p.name as patient_name,
|
||||
p.policy_number,
|
||||
p.civil_id,
|
||||
d.name_en as doctor_name_en
|
||||
FROM bills b
|
||||
JOIN patients p ON b.patient_id = p.id
|
||||
LEFT JOIN visits v ON b.visit_id = v.id
|
||||
LEFT JOIN doctors d ON v.doctor_id = d.id
|
||||
WHERE p.insurance_company_id = ?
|
||||
AND b.insurance_covered > 0
|
||||
AND DATE(b.created_at) BETWEEN ? AND ?
|
||||
ORDER BY b.created_at DESC
|
||||
";
|
||||
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->execute([$insurance_id, $start_date, $end_date]);
|
||||
$bills = $stmt->fetchAll();
|
||||
|
||||
// Calculate Totals
|
||||
$total_claim = 0;
|
||||
foreach ($bills as $bill) {
|
||||
$total_claim += $bill['insurance_covered'];
|
||||
}
|
||||
|
||||
// Fetch Company Settings (Logo, Address, etc.)
|
||||
$stmt = $db->query("SELECT * FROM settings WHERE id = 1");
|
||||
$settings = $stmt->fetch();
|
||||
|
||||
$lang = $_SESSION['lang'] ?? 'en';
|
||||
} catch (Exception $e) {
|
||||
die("Error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $lang; ?>" dir="<?php echo $lang == 'ar' ? 'rtl' : 'ltr'; ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Statement - <?php echo htmlspecialchars($insurance['name_en']); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { font-family: 'Times New Roman', Times, serif; color: #333; }
|
||||
.invoice-header { border-bottom: 2px solid #ddd; padding-bottom: 20px; margin-bottom: 30px; }
|
||||
.invoice-footer { border-top: 2px solid #ddd; padding-top: 20px; margin-top: 50px; }
|
||||
.company-logo { max-height: 80px; }
|
||||
.invoice-title { font-size: 2rem; color: #555; text-transform: uppercase; letter-spacing: 2px; }
|
||||
|
||||
.table thead th { border-bottom: 2px solid #333; background-color: #f8f9fa; }
|
||||
.table-bordered td, .table-bordered th { border-color: #dee2e6; }
|
||||
|
||||
@media print {
|
||||
.no-print { display: none !important; }
|
||||
body { padding: 20px; background: white; }
|
||||
.card { border: none !important; box-shadow: none !important; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="window.print()">
|
||||
|
||||
<div class="container my-5">
|
||||
<div class="no-print mb-4 text-end">
|
||||
<button onclick="window.print()" class="btn btn-primary"><i class="bi bi-printer"></i> <?php echo __('print'); ?></button>
|
||||
<button onclick="window.close()" class="btn btn-secondary"><?php echo __('close'); ?></button>
|
||||
</div>
|
||||
|
||||
<div class="card p-4">
|
||||
<!-- Header -->
|
||||
<div class="invoice-header">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-6">
|
||||
<?php if (!empty($settings['company_logo'])): ?>
|
||||
<img src="<?php echo htmlspecialchars($settings['company_logo']); ?>" alt="Logo" class="company-logo mb-2">
|
||||
<?php else: ?>
|
||||
<h2 class="fw-bold m-0"><?php echo htmlspecialchars($settings['company_name'] ?? 'Hospital Name'); ?></h2>
|
||||
<?php endif; ?>
|
||||
<div class="small text-muted">
|
||||
<?php echo htmlspecialchars($settings['company_address'] ?? '123 Medical Center St.'); ?><br>
|
||||
<?php echo __('phone'); ?>: <?php echo htmlspecialchars($settings['company_phone'] ?? '+123 456 7890'); ?><br>
|
||||
<?php echo __('email'); ?>: <?php echo htmlspecialchars($settings['company_email'] ?? 'info@hospital.com'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<h1 class="invoice-title"><?php echo __('statement'); ?></h1>
|
||||
<p class="lead mb-0"><?php echo htmlspecialchars($insurance['name_en']); ?></p>
|
||||
<p class="text-muted small">
|
||||
<?php echo __('date'); ?>: <?php echo date('d M Y', strtotime($start_date)); ?> - <?php echo date('d M Y', strtotime($end_date)); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Insurance Details -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h6 class="text-uppercase text-muted small fw-bold mb-2"><?php echo __('insurance_company'); ?>:</h6>
|
||||
<h5 class="fw-bold mb-1"><?php echo htmlspecialchars($insurance['name_en']); ?></h5>
|
||||
<p class="mb-0 text-muted">
|
||||
<?php if ($insurance['phone']) echo __('phone') . ': ' . htmlspecialchars($insurance['phone']) . '<br>'; ?>
|
||||
<?php if ($insurance['email']) echo __('email') . ': ' . htmlspecialchars($insurance['email']); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bills Table -->
|
||||
<table class="table table-bordered mb-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center" width="50">#</th>
|
||||
<th><?php echo __('date'); ?></th>
|
||||
<th><?php echo __('patient'); ?></th>
|
||||
<th><?php echo __('policy_number'); ?></th>
|
||||
<th><?php echo __('doctor'); ?></th>
|
||||
<th class="text-end"><?php echo __('total_amount'); ?></th>
|
||||
<th class="text-end"><?php echo __('insurance_covered'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($bills)): ?>
|
||||
<tr>
|
||||
<td colspan="7" class="text-center py-4 text-muted"><?php echo __('no_records_found'); ?></td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php $i = 1; foreach ($bills as $bill): ?>
|
||||
<tr>
|
||||
<td class="text-center"><?php echo $i++; ?></td>
|
||||
<td><?php echo date('Y-m-d', strtotime($bill['created_at'])); ?></td>
|
||||
<td>
|
||||
<?php echo htmlspecialchars($bill['patient_name']); ?>
|
||||
<?php if ($bill['civil_id']): ?>
|
||||
<br><small class="text-muted"><?php echo htmlspecialchars($bill['civil_id']); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($bill['policy_number'] ?: '-'); ?></td>
|
||||
<td><?php echo htmlspecialchars($bill['doctor_name_en'] ?: '-'); ?></td>
|
||||
<td class="text-end"><?php echo format_currency($bill['total_amount']); ?></td>
|
||||
<td class="text-end fw-bold"><?php echo format_currency($bill['insurance_covered']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr class="table-light">
|
||||
<td colspan="6" class="text-end fw-bold fs-5"><?php echo __('total'); ?></td>
|
||||
<td class="text-end fw-bold fs-5"><?php echo format_currency($total_claim); ?></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="invoice-footer text-center small text-muted">
|
||||
<p class="mb-1">Thank you for your partnership!</p>
|
||||
<p>Generated on <?php echo date('Y-m-d H:i:s'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -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 {
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-center"><?php echo $item['quantity']; ?></td>
|
||||
<td class="text-end"><?php echo number_format($item['unit_price'], 2); ?></td>
|
||||
<td class="text-end"><?php echo number_format($item['total_price'], 2); ?></td>
|
||||
<td class="text-end"><?php echo format_currency($item['unit_price']); ?></td>
|
||||
<td class="text-end"><?php echo format_currency($item['total_price']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
@ -189,7 +192,7 @@ try {
|
||||
TOTAL / الإجمالي
|
||||
</td>
|
||||
<td class="text-end fw-bold fs-5">
|
||||
<?php echo number_format($sale['total_amount'], 2); ?>
|
||||
<?php echo format_currency($sale['total_amount']); ?>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
@ -209,17 +209,17 @@ if ($type === 'inventory_valuation') {
|
||||
<td><?php echo htmlspecialchars($row['drug_name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['category_name'] ?? '-'); ?></td>
|
||||
<td><?php echo $row['stock_quantity']; ?></td>
|
||||
<td><?php echo number_format($row['avg_cost'], 2); ?></td>
|
||||
<td><?php echo number_format($row['selling_price'], 2); ?></td>
|
||||
<td><?php echo number_format($row['total_cost_value'], 2); ?></td>
|
||||
<td><?php echo number_format($row['total_sales_value'], 2); ?></td>
|
||||
<td><?php echo format_currency($row['avg_cost']); ?></td>
|
||||
<td><?php echo format_currency($row['selling_price']); ?></td>
|
||||
<td><?php echo format_currency($row['total_cost_value']); ?></td>
|
||||
<td><?php echo format_currency($row['total_sales_value']); ?></td>
|
||||
|
||||
<?php elseif ($type === 'sales'): ?>
|
||||
<td><?php echo $row['created_at']; ?></td>
|
||||
<td>#<?php echo $row['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($row['patient_name'] ?? 'Guest'); ?></td>
|
||||
<td><?php echo $row['item_count']; ?></td>
|
||||
<td><?php echo number_format($row['total_amount'], 2); ?></td>
|
||||
<td><?php echo format_currency($row['total_amount']); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['payment_method']); ?></td>
|
||||
|
||||
<?php elseif ($type === 'expiry'): ?>
|
||||
@ -242,7 +242,7 @@ if ($type === 'inventory_valuation') {
|
||||
<td>#<?php echo $row['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($row['supplier_name'] ?? '-'); ?></td>
|
||||
<td><?php echo htmlspecialchars($row['status']); ?></td>
|
||||
<td><?php echo number_format($row['total_amount'], 2); ?></td>
|
||||
<td><?php echo format_currency($row['total_amount']); ?></td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@ -255,18 +255,18 @@ if ($type === 'inventory_valuation') {
|
||||
<?php if ($type === 'inventory_valuation'): ?>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="5" class="text-end"><?php echo __('grand_total'); ?>:</td>
|
||||
<td><?php echo number_format($grandTotals['total_cost'] ?? 0, 2); ?></td>
|
||||
<td><?php echo number_format($grandTotals['total_sales'] ?? 0, 2); ?></td>
|
||||
<td><?php echo format_currency($grandTotals['total_cost'] ?? 0); ?></td>
|
||||
<td><?php echo format_currency($grandTotals['total_sales'] ?? 0); ?></td>
|
||||
</tr>
|
||||
<?php elseif ($type === 'sales'): ?>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="4" class="text-end"><?php echo __('grand_total'); ?>:</td>
|
||||
<td colspan="2"><?php echo number_format($grandTotals['total_sales'] ?? 0, 2); ?></td>
|
||||
<td colspan="2"><?php echo format_currency($grandTotals['total_sales'] ?? 0); ?></td>
|
||||
</tr>
|
||||
<?php elseif ($type === 'purchase_report'): ?>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="4" class="text-end"><?php echo __('grand_total'); ?>:</td>
|
||||
<td><?php echo number_format($grandTotals['total_purchases'] ?? 0, 2); ?></td>
|
||||
<td><?php echo format_currency($grandTotals['total_purchases'] ?? 0); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tfoot>
|
||||
|
||||
11
settings.php
11
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]);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user