Autosave: 20260225-095814

This commit is contained in:
Flatlogic Bot 2026-02-25 09:58:14 +00:00
parent 08a58d8cfc
commit 94afa7ad81
26 changed files with 16736 additions and 17 deletions

17
check.php Normal file
View File

@ -0,0 +1,17 @@
<?php
require 'db/config.php';
$db = db();
$tables = ['payments', 'purchase_payments', 'pos_payments'];
foreach ($tables as $t) {
try {
$stmt = $db->query("SHOW COLUMNS FROM `$t`");
$has = false;
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if($row['Field'] == 'outlet_id') $has = true;
}
if($has) echo "$t has outlet_id\n";
else echo "$t missing outlet_id\n";
} catch (Exception $e) {
echo "Error on $t: " . $e->getMessage() . "\n";
}
}

54
create_tenant_views.php Normal file
View File

@ -0,0 +1,54 @@
<?php
require 'db/config.php';
$db = db();
$tables = [
'users', 'invoices', 'lpos', 'purchases', 'quotations',
'expenses', 'payments', 'purchase_payments', 'pos_transactions',
'customers', 'suppliers', 'stock_items', 'pos_held_carts',
'loyalty_transactions', 'purchase_returns', 'sales_returns', 'pos_payments'
];
try {
// 1. Create function
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
foreach ($tables as $t) {
// Ensure table exists and isn't already a view
$stmt = $db->query("SHOW FULL TABLES LIKE '$t'");
$row = $stmt->fetch(PDO::FETCH_NUM);
if (!$row) continue;
if ($row[1] === 'VIEW') continue; // Already processed
// Make sure it has outlet_id
$hasCol = false;
$cols = $db->query("SHOW COLUMNS FROM `$t`")->fetchAll(PDO::FETCH_ASSOC);
foreach ($cols as $c) {
if ($c['Field'] === 'outlet_id') $hasCol = true;
}
if (!$hasCol) {
$db->exec("ALTER TABLE `$t` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT 1 AFTER `id`");
}
// Alter default to 1 if it's NULL
$db->exec("ALTER TABLE `$t` MODIFY `outlet_id` int(11) DEFAULT 1");
// Rename table to _table
$db->exec("RENAME TABLE `$t` TO `_$t`");
// Create view
$db->exec("CREATE VIEW `$t` AS SELECT * FROM `_$t` WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL OR current_outlet_id() = 0");
// Create trigger
$db->exec("CREATE TRIGGER `trg_ins_$t` BEFORE INSERT ON `_$t` FOR EACH ROW BEGIN
IF current_outlet_id() IS NOT NULL AND current_outlet_id() != 0 THEN
SET NEW.outlet_id = current_outlet_id();
END IF;
END");
echo "Processed $t\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}

1001
data_fetch.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,14 @@ function db() {
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]); ]);
if (session_status() === PHP_SESSION_NONE && !headers_sent()) {
@session_start();
}
if (isset($_SESSION['outlet_id'])) {
$pdo->exec("SET @session_outlet_id = " . (int)$_SESSION['outlet_id']);
} else {
$pdo->exec("SET @session_outlet_id = 0");
}
} }
return $pdo; return $pdo;
} }

View File

@ -0,0 +1,14 @@
ALTER TABLE `purchase_payments` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `purchase_returns` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `sales_returns` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `stock_items` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `customers` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `suppliers` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `invoices` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `lpos` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `purchases` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `quotations` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `expenses` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `payments` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;
ALTER TABLE `pos_transactions` ADD COLUMN IF NOT EXISTS `outlet_id` int(11) DEFAULT NULL AFTER `id`;

17
db_inspect.php Normal file
View File

@ -0,0 +1,17 @@
<?php
require 'db/config.php';
try {
$pdo = db();
$stmt = $pdo->query("SHOW TABLES");
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
foreach ($tables as $table) {
echo "Table: $table\n";
$stmt2 = $pdo->query("DESCRIBE `$table`");
$cols = $stmt2->fetchAll(PDO::FETCH_ASSOC);
foreach ($cols as $col) {
echo " - " . $col['Field'] . " (" . $col['Type'] . ")\n";
}
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}

6
db_inspect2.php Normal file
View File

@ -0,0 +1,6 @@
<?php
require 'db/config.php';
$stmt = db()->query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'outlet_id' AND TABLE_SCHEMA = DATABASE()");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['TABLE_NAME'] . "\n";
}

47
db_migrations_outlet.php Normal file
View File

@ -0,0 +1,47 @@
<?php
require 'db/config.php';
try {
$pdo = db();
// Create outlets table
$pdo->exec("CREATE TABLE IF NOT EXISTS `outlets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`address` text,
`phone` varchar(50),
`status` enum('active','inactive') DEFAULT 'active',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
// Insert a default Main Branch if table is empty
$stmt = $pdo->query("SELECT COUNT(*) FROM outlets");
if ($stmt->fetchColumn() == 0) {
$pdo->exec("INSERT INTO outlets (name, address, status) VALUES ('Main Branch', 'Headquarters', 'active')");
}
// Add outlet_id to tables
$tablesToUpdate = [
'users',
'invoices',
'purchases',
'lpos',
'quotations',
'expenses',
'payments'
];
foreach ($tablesToUpdate as $table) {
$stmt = $pdo->query("SHOW COLUMNS FROM `$table` LIKE 'outlet_id'");
if ($stmt->rowCount() == 0) {
$pdo->exec("ALTER TABLE `$table` ADD COLUMN `outlet_id` int(11) NULL DEFAULT 1 AFTER `id`");
echo "Added outlet_id to $table\n";
} else {
echo "outlet_id already exists in $table\n";
}
}
echo "Migration completed successfully.";
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}

2
debug.log Normal file
View File

@ -0,0 +1,2 @@
2026-02-25 09:56:17 - Items case hit
2026-02-25 09:56:38 - Requesting AI. UUID: [e1f9b5b3-fcef-4c8d-87d2-8630b1f72491] CFG: {"base_url":"https:\/\/flatlogic.com","responses_path":"\/projects\/38471\/ai-request","project_id":"38471","project_uuid":"e1f9b5b3-fcef-4c8d-87d2-8630b1f72491","project_header":"Project-UUID","default_model":"gpt-4o-mini","timeout":30,"verify_tls":true}

181
diff.txt Normal file
View File

@ -0,0 +1,181 @@
diff --git a/index.php b/index.php
index b15ee60..3f88b32 100644
--- a/index.php
+++ b/index.php
@@ -35,6 +35,15 @@ if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER[
}
session_start();
+if (isset($_GET['action']) && $_GET['action'] === 'switch_outlet') {
+ $target = (int)$_GET['id'];
+ if (($_SESSION['user_role_name'] ?? '') === 'Administrator') {
+ $_SESSION['outlet_id'] = $target === 0 ? null : $target;
+ }
+ header("Location: " . ($_SERVER['HTTP_REFERER'] ?? 'index.php'));
+ exit;
+}
+
if (isset($_GET['action']) && $_GET['action'] === 'download_items_template') {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=items_import_template.csv');
@@ -3014,6 +3023,11 @@ $page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
if ($page_num < 1) $page_num = 1;
$offset = ($page_num - 1) * $limit;
switch ($page) {
+ case 'outlets':
+ $stmt = db()->prepare("SELECT * FROM outlets ORDER BY id DESC");
+ $stmt->execute();
+ $data['outlets'] = $stmt->fetchAll();
+ break;
case 'suppliers':
$where = ["1=1"];
$params = [];
@@ -4184,6 +4198,26 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div>
</div>
<?php endif; ?>
+ <?php
+ if (($_SESSION['user_role_name'] ?? '') === 'Administrator'):
+ $outlets = db()->query("SELECT * FROM outlets WHERE status = 'active'")->fetchAll(PDO::FETCH_ASSOC);
+ $cur_out = $_SESSION['outlet_id'] ?? 0;
+ $cur_name = 'All Outlets';
+ foreach ($outlets as $o) { if ($o['id'] == $cur_out) $cur_name = $o['name']; }
+ ?>
+ <div class="dropdown me-3">
+ <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
+ <i class="bi bi-shop"></i> <span class="d-none d-md-inline"><?= htmlspecialchars($cur_name) ?></span>
+ </button>
+ <ul class="dropdown-menu shadow-sm border-0">
+ <li><a class="dropdown-item <?= $cur_out == 0 ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=0">All Outlets</a></li>
+ <li><hr class="dropdown-divider"></li>
+ <?php foreach ($outlets as $o): ?>
+ <li><a class="dropdown-item <?= $cur_out == $o['id'] ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=<?= $o['id'] ?>"><?= htmlspecialchars($o['name']) ?></a></li>
+ <?php endforeach; ?>
+ </ul>
+ </div>
+ <?php endif; ?>
<div class="dropdown me-3">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-palette"></i> <span><?= $lang === 'ar' ? 'المظهر' : 'Theme' ?></span>
@@ -4488,6 +4522,121 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<h1 class="display-4 fw-bold text-muted text-center mt-3"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Company Name') ?></h1>
</div>
<?php endif; ?>
+ <?php elseif ($page === 'outlets' && ($_SESSION['user_role_name'] ?? '') === 'Administrator'): ?>
+ <div class="card border-0 shadow-sm rounded-4 mb-4">
+ <div class="card-header bg-white border-bottom-0 pt-4 pb-0 px-4 d-flex justify-content-between align-items-center">
+ <h5 class="fw-bold mb-0"><i class="bi bi-shop text-primary me-2"></i> Manage Outlets</h5>
+ <button class="btn btn-primary rounded-pill px-3 py-2" data-bs-toggle="modal" data-bs-target="#addOutletModal">
+ <i class="bi bi-plus-lg me-1"></i> Add Outlet
+ </button>
+ </div>
+ <div class="card-body p-4">
+ <div class="table-responsive">
+ <table class="table table-hover align-middle mb-0">
+ <thead class="table-light">
+ <tr>
+ <th>ID</th>
+ <th>Name</th>
+ <th>Address</th>
+ <th>Phone</th>
+ <th>Status</th>
+ <th>Created At</th>
+ <th class="text-end">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php foreach ($data['outlets'] as $o): ?>
+ <tr>
+ <td>#<?= $o['id'] ?></td>
+ <td class="fw-semibold text-dark"><?= htmlspecialchars($o['name']) ?></td>
+ <td class="text-muted small"><?= htmlspecialchars($o['address'] ?: '-') ?></td>
+ <td><?= htmlspecialchars($o['phone'] ?: '-') ?></td>
+ <td><span class="badge bg-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> bg-opacity-10 text-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> rounded-pill px-2"><?= ucfirst($o['status']) ?></span></td>
+ <td class="small text-muted"><?= htmlspecialchars($o['created_at']) ?></td>
+ <td class="text-end">
+ <button class="btn btn-light btn-sm rounded-circle me-1" onclick="editOutlet(<?= htmlspecialchars(json_encode($o)) ?>)" title="Edit">
+ <i class="bi bi-pencil"></i>
+ </button>
+ <?php if ($o['id'] !== 1): ?>
+ <form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this outlet?');">
+ <input type="hidden" name="id" value="<?= $o['id'] ?>">
+ <button type="submit" name="delete_outlet" class="btn btn-light btn-sm rounded-circle text-danger" title="Delete">
+ <i class="bi bi-trash"></i>
+ </button>
+ </form>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ <!-- Add/Edit Modal -->
+ <div class="modal fade" id="addOutletModal" tabindex="-1">
+ <div class="modal-dialog modal-dialog-centered">
+ <div class="modal-content border-0 shadow rounded-4">
+ <form method="POST">
+ <input type="hidden" name="id" id="outlet_id">
+ <div class="modal-header border-bottom-0 pb-0">
+ <h5 class="modal-title fw-bold" id="outletModalTitle">Add Outlet</h5>
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+ <div class="modal-body p-4">
+ <div class="mb-3">
+ <label class="form-label small fw-semibold text-muted">Name</label>
+ <input type="text" name="name" id="outlet_name" class="form-control rounded-3" required>
+ </div>
+ <div class="mb-3">
+ <label class="form-label small fw-semibold text-muted">Phone</label>
+ <input type="text" name="phone" id="outlet_phone" class="form-control rounded-3">
+ </div>
+ <div class="mb-3">
+ <label class="form-label small fw-semibold text-muted">Address</label>
+ <textarea name="address" id="outlet_address" class="form-control rounded-3" rows="2"></textarea>
+ </div>
+ <div class="mb-0">
+ <label class="form-label small fw-semibold text-muted">Status</label>
+ <select name="status" id="outlet_status" class="form-select rounded-3">
+ <option value="active">Active</option>
+ <option value="inactive">Inactive</option>
+ </select>
+ </div>
+ </div>
+ <div class="modal-footer border-top-0 pt-0">
+ <button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">Cancel</button>
+ <button type="submit" name="add_outlet" id="outletSubmitBtn" class="btn btn-primary rounded-pill px-4">Save Outlet</button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ <script>
+ function editOutlet(o) {
+ document.getElementById('outlet_id').value = o.id;
+ document.getElementById('outlet_name').value = o.name;
+ document.getElementById('outlet_phone').value = o.phone || '';
+ document.getElementById('outlet_address').value = o.address || '';
+ document.getElementById('outlet_status').value = o.status;
+ document.getElementById('outletModalTitle').innerText = 'Edit Outlet';
+ document.getElementById('outletSubmitBtn').name = 'edit_outlet';
+ document.getElementById('outletSubmitBtn').innerText = 'Update Outlet';
+ new bootstrap.Modal(document.getElementById('addOutletModal')).show();
+ }
+ document.getElementById('addOutletModal').addEventListener('hidden.bs.modal', function () {
+ document.getElementById('outlet_id').value = '';
+ document.getElementById('outlet_name').value = '';
+ document.getElementById('outlet_phone').value = '';
+ document.getElementById('outlet_address').value = '';
+ document.getElementById('outlet_status').value = 'active';
+ document.getElementById('outletModalTitle').innerText = 'Add Outlet';
+ document.getElementById('outletSubmitBtn').name = 'add_outlet';
+ document.getElementById('outletSubmitBtn').innerText = 'Save Outlet';
+ });
+ </script>
+
<?php elseif ($page === 'customers' || $page === 'suppliers'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">

183
index.php
View File

@ -35,6 +35,15 @@ if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER[
} }
session_start(); session_start();
if (isset($_GET['action']) && $_GET['action'] === 'switch_outlet') {
$target = (int)$_GET['id'];
if (($_SESSION['user_role_name'] ?? '') === 'Administrator') {
$_SESSION['outlet_id'] = $target === 0 ? null : $target;
}
header("Location: " . ($_SERVER['HTTP_REFERER'] ?? 'index.php'));
exit;
}
if (isset($_GET['action']) && $_GET['action'] === 'download_items_template') { if (isset($_GET['action']) && $_GET['action'] === 'download_items_template') {
header('Content-Type: text/csv; charset=utf-8'); header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=items_import_template.csv'); header('Content-Disposition: attachment; filename=items_import_template.csv');
@ -478,8 +487,8 @@ if (isset($_GET['action']) || isset($_POST['action'])) {
$items_for_journal[] = ['id' => $item['id'], 'qty' => $item['qty']]; $items_for_journal[] = ['id' => $item['id'], 'qty' => $item['qty']];
} }
$stmt = $db->prepare("INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'paid', ?, 1, ?, ?, ?)"); $stmt = $db->prepare("INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'paid', ?, 1, ?, ?, ?)");
$stmt->execute([$transaction_no, $customer_id, date('Y-m-d'), 'pos', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION['user_id']]); $stmt->execute([(int)($_SESSION["outlet_id"] ?? 1), $transaction_no, $customer_id, date('Y-m-d'), 'pos', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION['user_id']]);
$transaction_id = (int)$db->lastInsertId(); $transaction_id = (int)$db->lastInsertId();
// Insert Items & Update Stock // Insert Items & Update Stock
@ -1107,8 +1116,8 @@ function getPromotionalPrice($item) {
$total_with_vat = $total_subtotal + $total_vat; $total_with_vat = $total_subtotal + $total_vat;
$stmt = $db->prepare("INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, 'pending', ?, ?, ?, ?)"); $stmt = $db->prepare("INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?)");
$stmt->execute([$supp_id, $lpo_date, $delivery_date, $total_subtotal, $total_vat, $total_with_vat, $terms]); $stmt->execute([(int)($_SESSION["outlet_id"] ?? 1), $supp_id, $lpo_date, $delivery_date, $total_subtotal, $total_vat, $total_with_vat, $terms]);
$lpo_id = $db->lastInsertId(); $lpo_id = $db->lastInsertId();
foreach ($items as $i => $item_id) { foreach ($items as $i => $item_id) {
@ -1212,8 +1221,8 @@ function getPromotionalPrice($item) {
// Create Invoice // Create Invoice
$inv_date = date('Y-m-d'); $inv_date = date('Y-m-d');
$stmtInv = $db->prepare("INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, 'unpaid', 'credit', ?, ?, ?, 0)"); $stmtInv = $db->prepare("INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, 'unpaid', 'credit', ?, ?, ?, 0)");
$stmtInv->execute([$quot['customer_id'], $inv_date, $quot['total_amount'], $quot['vat_amount'], $quot['total_with_vat']]); $stmtInv->execute([(int)($_SESSION["outlet_id"] ?? 1), $quot['customer_id'], $inv_date, $quot['total_amount'], $quot['vat_amount'], $quot['total_with_vat']]);
$inv_id = $db->lastInsertId(); $inv_id = $db->lastInsertId();
$items_for_journal = []; $items_for_journal = [];
@ -1255,8 +1264,8 @@ function getPromotionalPrice($item) {
// Create Purchase Invoice // Create Purchase Invoice
$pur_date = date('Y-m-d'); $pur_date = date('Y-m-d');
$stmtPur = $db->prepare("INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, 'unpaid', 'credit', ?, ?, ?, 0)"); $stmtPur = $db->prepare("INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, 'unpaid', 'credit', ?, ?, ?, 0)");
$stmtPur->execute([$lpo['supplier_id'], $pur_date, $lpo['total_amount'], $lpo['vat_amount'], $lpo['total_with_vat']]); $stmtPur->execute([(int)($_SESSION["outlet_id"] ?? 1), $lpo['supplier_id'], $pur_date, $lpo['total_amount'], $lpo['vat_amount'], $lpo['total_with_vat']]);
$pur_id = $db->lastInsertId(); $pur_id = $db->lastInsertId();
$items_for_journal = []; $items_for_journal = [];
@ -1303,7 +1312,7 @@ function getPromotionalPrice($item) {
$amt = (float)$_POST['amount']; $amt = (float)$_POST['amount'];
$date = $_POST['expense_date'] ?: date('Y-m-d'); $date = $_POST['expense_date'] ?: date('Y-m-d');
$desc = $_POST['description'] ?? ''; $desc = $_POST['description'] ?? '';
db()->prepare("INSERT INTO expenses (category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?)")->execute([(int)$_POST['category_id'], $amt, $date, $_POST['reference_no'] ?? '', $desc]); db()->prepare("INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?, ?)")->execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST['category_id'], $amt, $date, $_POST['reference_no'] ?? '', $desc]);
recordExpenseJournal(db()->lastInsertId(), $amt, $date, $desc); recordExpenseJournal(db()->lastInsertId(), $amt, $date, $desc);
redirectWithMessage("Expense recorded!", "index.php?page=expenses"); redirectWithMessage("Expense recorded!", "index.php?page=expenses");
} }
@ -1448,8 +1457,8 @@ function getPromotionalPrice($item) {
$total_with_vat = $total_subtotal + $total_vat; $total_with_vat = $total_subtotal + $total_vat;
$stmt = $db->prepare("INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, 'pending', ?, ?, ?, ?)"); $stmt = $db->prepare("INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?)");
$stmt->execute([$supp_id, $lpo_date, $delivery_date, $total_subtotal, $total_vat, $total_with_vat, $terms]); $stmt->execute([(int)($_SESSION["outlet_id"] ?? 1), $supp_id, $lpo_date, $delivery_date, $total_subtotal, $total_vat, $total_with_vat, $terms]);
$lpo_id = $db->lastInsertId(); $lpo_id = $db->lastInsertId();
foreach ($items as $i => $item_id) { foreach ($items as $i => $item_id) {
@ -1556,8 +1565,8 @@ function getPromotionalPrice($item) {
// Create Invoice // Create Invoice
$inv_date = date('Y-m-d'); $inv_date = date('Y-m-d');
$stmtInv = $db->prepare("INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, 'unpaid', 'credit', ?, ?, ?, 0)"); $stmtInv = $db->prepare("INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, 'unpaid', 'credit', ?, ?, ?, 0)");
$stmtInv->execute([$quot['customer_id'], $inv_date, $quot['total_amount'], $quot['vat_amount'], $quot['total_with_vat']]); $stmtInv->execute([(int)($_SESSION["outlet_id"] ?? 1), $quot['customer_id'], $inv_date, $quot['total_amount'], $quot['vat_amount'], $quot['total_with_vat']]);
$inv_id = $db->lastInsertId(); $inv_id = $db->lastInsertId();
$items_for_journal = []; $items_for_journal = [];
@ -1599,8 +1608,8 @@ function getPromotionalPrice($item) {
// Create Purchase Invoice // Create Purchase Invoice
$inv_date = date('Y-m-d'); $inv_date = date('Y-m-d');
$stmtPur = $db->prepare("INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, 'unpaid', 'credit', ?, ?, ?, 0)"); $stmtPur = $db->prepare("INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, 'unpaid', 'credit', ?, ?, ?, 0)");
$stmtPur->execute([$lpo['supplier_id'], $inv_date, $lpo['total_amount'], $lpo['vat_amount'], $lpo['total_with_vat']]); $stmtPur->execute([(int)($_SESSION["outlet_id"] ?? 1), $lpo['supplier_id'], $inv_date, $lpo['total_amount'], $lpo['vat_amount'], $lpo['total_with_vat']]);
$pur_id = $db->lastInsertId(); $pur_id = $db->lastInsertId();
$items_for_journal = []; $items_for_journal = [];
@ -1652,7 +1661,7 @@ function getPromotionalPrice($item) {
$amt = (float)$_POST['amount']; $amt = (float)$_POST['amount'];
$date = $_POST['expense_date'] ?: date('Y-m-d'); $date = $_POST['expense_date'] ?: date('Y-m-d');
$desc = $_POST['description'] ?? ''; $desc = $_POST['description'] ?? '';
db()->prepare("INSERT INTO expenses (category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?)")->execute([(int)$_POST['category_id'], $amt, $date, $_POST['reference_no'] ?? '', $desc]); db()->prepare("INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?, ?)")->execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST['category_id'], $amt, $date, $_POST['reference_no'] ?? '', $desc]);
recordExpenseJournal(db()->lastInsertId(), $amt, $date, $desc); recordExpenseJournal(db()->lastInsertId(), $amt, $date, $desc);
$message = "Expense recorded!"; $message = "Expense recorded!";
} }
@ -2245,7 +2254,7 @@ if (isset($_POST['add_hr_department'])) {
$group_id = (int)($_POST['group_id'] ?? 0) ?: null; $group_id = (int)($_POST['group_id'] ?? 0) ?: null;
if ($username && $password) { if ($username && $password) {
$hashed_password = password_hash($password, PASSWORD_DEFAULT); $hashed_password = password_hash($password, PASSWORD_DEFAULT);
$stmt = db()->prepare("INSERT INTO users (username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?)"); $stmt = db()->prepare("INSERT INTO users (outlet_id, username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?, ?)");
try { try {
$stmt->execute([$username, $hashed_password, $email, $phone, $group_id]); $stmt->execute([$username, $hashed_password, $email, $phone, $group_id]);
$message = "User added successfully!"; $message = "User added successfully!";
@ -3014,6 +3023,11 @@ $page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
if ($page_num < 1) $page_num = 1; if ($page_num < 1) $page_num = 1;
$offset = ($page_num - 1) * $limit; $offset = ($page_num - 1) * $limit;
switch ($page) { switch ($page) {
case 'outlets':
$stmt = db()->prepare("SELECT * FROM outlets ORDER BY id DESC");
$stmt->execute();
$data['outlets'] = $stmt->fetchAll();
break;
case 'suppliers': case 'suppliers':
$where = ["1=1"]; $where = ["1=1"];
$params = []; $params = [];
@ -4184,6 +4198,26 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div> </div>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php
if (($_SESSION['user_role_name'] ?? '') === 'Administrator'):
$outlets = db()->query("SELECT * FROM outlets WHERE status = 'active'")->fetchAll(PDO::FETCH_ASSOC);
$cur_out = $_SESSION['outlet_id'] ?? 0;
$cur_name = 'All Outlets';
foreach ($outlets as $o) { if ($o['id'] == $cur_out) $cur_name = $o['name']; }
?>
<div class="dropdown me-3">
<button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-shop"></i> <span class="d-none d-md-inline"><?= htmlspecialchars($cur_name) ?></span>
</button>
<ul class="dropdown-menu shadow-sm border-0">
<li><a class="dropdown-item <?= $cur_out == 0 ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=0">All Outlets</a></li>
<li><hr class="dropdown-divider"></li>
<?php foreach ($outlets as $o): ?>
<li><a class="dropdown-item <?= $cur_out == $o['id'] ? 'active' : '' ?>" href="index.php?action=switch_outlet&id=<?= $o['id'] ?>"><?= htmlspecialchars($o['name']) ?></a></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<div class="dropdown me-3"> <div class="dropdown me-3">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown"> <button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-palette"></i> <span><?= $lang === 'ar' ? 'المظهر' : 'Theme' ?></span> <i class="bi bi-palette"></i> <span><?= $lang === 'ar' ? 'المظهر' : 'Theme' ?></span>
@ -4488,6 +4522,121 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<h1 class="display-4 fw-bold text-muted text-center mt-3"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Company Name') ?></h1> <h1 class="display-4 fw-bold text-muted text-center mt-3"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Company Name') ?></h1>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php elseif ($page === 'outlets' && ($_SESSION['user_role_name'] ?? '') === 'Administrator'): ?>
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-header bg-white border-bottom-0 pt-4 pb-0 px-4 d-flex justify-content-between align-items-center">
<h5 class="fw-bold mb-0"><i class="bi bi-shop text-primary me-2"></i> Manage Outlets</h5>
<button class="btn btn-primary rounded-pill px-3 py-2" data-bs-toggle="modal" data-bs-target="#addOutletModal">
<i class="bi bi-plus-lg me-1"></i> Add Outlet
</button>
</div>
<div class="card-body p-4">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
<th>Status</th>
<th>Created At</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['outlets'] as $o): ?>
<tr>
<td>#<?= $o['id'] ?></td>
<td class="fw-semibold text-dark"><?= htmlspecialchars($o['name']) ?></td>
<td class="text-muted small"><?= htmlspecialchars($o['address'] ?: '-') ?></td>
<td><?= htmlspecialchars($o['phone'] ?: '-') ?></td>
<td><span class="badge bg-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> bg-opacity-10 text-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> rounded-pill px-2"><?= ucfirst($o['status']) ?></span></td>
<td class="small text-muted"><?= htmlspecialchars($o['created_at']) ?></td>
<td class="text-end">
<button class="btn btn-light btn-sm rounded-circle me-1" onclick="editOutlet(<?= htmlspecialchars(json_encode($o)) ?>)" title="Edit">
<i class="bi bi-pencil"></i>
</button>
<?php if ($o['id'] !== 1): ?>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this outlet?');">
<input type="hidden" name="id" value="<?= $o['id'] ?>">
<button type="submit" name="delete_outlet" class="btn btn-light btn-sm rounded-circle text-danger" title="Delete">
<i class="bi bi-trash"></i>
</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Add/Edit Modal -->
<div class="modal fade" id="addOutletModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow rounded-4">
<form method="POST">
<input type="hidden" name="id" id="outlet_id">
<div class="modal-header border-bottom-0 pb-0">
<h5 class="modal-title fw-bold" id="outletModalTitle">Add Outlet</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Name</label>
<input type="text" name="name" id="outlet_name" class="form-control rounded-3" required>
</div>
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Phone</label>
<input type="text" name="phone" id="outlet_phone" class="form-control rounded-3">
</div>
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Address</label>
<textarea name="address" id="outlet_address" class="form-control rounded-3" rows="2"></textarea>
</div>
<div class="mb-0">
<label class="form-label small fw-semibold text-muted">Status</label>
<select name="status" id="outlet_status" class="form-select rounded-3">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
</div>
<div class="modal-footer border-top-0 pt-0">
<button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_outlet" id="outletSubmitBtn" class="btn btn-primary rounded-pill px-4">Save Outlet</button>
</div>
</form>
</div>
</div>
</div>
<script>
function editOutlet(o) {
document.getElementById('outlet_id').value = o.id;
document.getElementById('outlet_name').value = o.name;
document.getElementById('outlet_phone').value = o.phone || '';
document.getElementById('outlet_address').value = o.address || '';
document.getElementById('outlet_status').value = o.status;
document.getElementById('outletModalTitle').innerText = 'Edit Outlet';
document.getElementById('outletSubmitBtn').name = 'edit_outlet';
document.getElementById('outletSubmitBtn').innerText = 'Update Outlet';
new bootstrap.Modal(document.getElementById('addOutletModal')).show();
}
document.getElementById('addOutletModal').addEventListener('hidden.bs.modal', function () {
document.getElementById('outlet_id').value = '';
document.getElementById('outlet_name').value = '';
document.getElementById('outlet_phone').value = '';
document.getElementById('outlet_address').value = '';
document.getElementById('outlet_status').value = 'active';
document.getElementById('outletModalTitle').innerText = 'Add Outlet';
document.getElementById('outletSubmitBtn').name = 'add_outlet';
document.getElementById('outletSubmitBtn').innerText = 'Save Outlet';
});
</script>
<?php elseif ($page === 'customers' || $page === 'suppliers'): ?> <?php elseif ($page === 'customers' || $page === 'suppliers'): ?>
<div class="card p-4"> <div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">

14185
index.php.bak Normal file

File diff suppressed because it is too large Load Diff

65
insert_lines.txt Normal file
View File

@ -0,0 +1,65 @@
431
481
486
498
514
518
781
828
832
855
916
932
989
1003
1062
1110
1125
1183
1215
1221
1258
1264
1290
1306
1370
1387
1393
1451
1466
1527
1559
1565
1602
1608
1641
1655
1733
1757
1762
1848
1867
1900
1945
1974
2040
2045
2091
2096
2126
2173
2177
2187
2221
2226
2248
2277
2335
2400
2413
2454
2487
2523
2559
2592
2628

114
outlets_html.php Normal file
View File

@ -0,0 +1,114 @@
<?php elseif ($page === 'outlets' && ($_SESSION['user_role_name'] ?? '') === 'Administrator'): ?>
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-header bg-white border-bottom-0 pt-4 pb-0 px-4 d-flex justify-content-between align-items-center">
<h5 class="fw-bold mb-0"><i class="bi bi-shop text-primary me-2"></i> Manage Outlets</h5>
<button class="btn btn-primary rounded-pill px-3 py-2" data-bs-toggle="modal" data-bs-target="#addOutletModal">
<i class="bi bi-plus-lg me-1"></i> Add Outlet
</button>
</div>
<div class="card-body p-4">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
<th>Status</th>
<th>Created At</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['outlets'] as $o): ?>
<tr>
<td>#<?= $o['id'] ?></td>
<td class="fw-semibold text-dark"><?= htmlspecialchars($o['name']) ?></td>
<td class="text-muted small"><?= htmlspecialchars($o['address'] ?: '-') ?></td>
<td><?= htmlspecialchars($o['phone'] ?: '-') ?></td>
<td><span class="badge bg-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> bg-opacity-10 text-<?= $o['status'] === 'active' ? 'success' : 'secondary' ?> rounded-pill px-2"><?= ucfirst($o['status']) ?></span></td>
<td class="small text-muted"><?= htmlspecialchars($o['created_at']) ?></td>
<td class="text-end">
<button class="btn btn-light btn-sm rounded-circle me-1" onclick="editOutlet(<?= htmlspecialchars(json_encode($o)) ?>)" title="Edit">
<i class="bi bi-pencil"></i>
</button>
<?php if ($o['id'] !== 1): ?>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this outlet?');">
<input type="hidden" name="id" value="<?= $o['id'] ?>">
<button type="submit" name="delete_outlet" class="btn btn-light btn-sm rounded-circle text-danger" title="Delete">
<i class="bi bi-trash"></i>
</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Add/Edit Modal -->
<div class="modal fade" id="addOutletModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow rounded-4">
<form method="POST">
<input type="hidden" name="id" id="outlet_id">
<div class="modal-header border-bottom-0 pb-0">
<h5 class="modal-title fw-bold" id="outletModalTitle">Add Outlet</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Name</label>
<input type="text" name="name" id="outlet_name" class="form-control rounded-3" required>
</div>
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Phone</label>
<input type="text" name="phone" id="outlet_phone" class="form-control rounded-3">
</div>
<div class="mb-3">
<label class="form-label small fw-semibold text-muted">Address</label>
<textarea name="address" id="outlet_address" class="form-control rounded-3" rows="2"></textarea>
</div>
<div class="mb-0">
<label class="form-label small fw-semibold text-muted">Status</label>
<select name="status" id="outlet_status" class="form-select rounded-3">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
</div>
</div>
<div class="modal-footer border-top-0 pt-0">
<button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_outlet" id="outletSubmitBtn" class="btn btn-primary rounded-pill px-4">Save Outlet</button>
</div>
</form>
</div>
</div>
</div>
<script>
function editOutlet(o) {
document.getElementById('outlet_id').value = o.id;
document.getElementById('outlet_name').value = o.name;
document.getElementById('outlet_phone').value = o.phone || '';
document.getElementById('outlet_address').value = o.address || '';
document.getElementById('outlet_status').value = o.status;
document.getElementById('outletModalTitle').innerText = 'Edit Outlet';
document.getElementById('outletSubmitBtn').name = 'edit_outlet';
document.getElementById('outletSubmitBtn').innerText = 'Update Outlet';
new bootstrap.Modal(document.getElementById('addOutletModal')).show();
}
document.getElementById('addOutletModal').addEventListener('hidden.bs.modal', function () {
document.getElementById('outlet_id').value = '';
document.getElementById('outlet_name').value = '';
document.getElementById('outlet_phone').value = '';
document.getElementById('outlet_address').value = '';
document.getElementById('outlet_status').value = 'active';
document.getElementById('outletModalTitle').innerText = 'Add Outlet';
document.getElementById('outletSubmitBtn').name = 'add_outlet';
document.getElementById('outletSubmitBtn').innerText = 'Save Outlet';
});
</script>

90
patch_all.php Normal file
View File

@ -0,0 +1,90 @@
$content = file_get_contents('index.php');
$search = " default:
if (can('dashboard_view')) {
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
\$data['stats'] = [
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed'\")->fetchColumn() ?: 0),
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments\")->fetchColumn() ?: 0),
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases\")->fetchColumn() ?: 0,
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments\")->fetchColumn() ?: 0,
'expired_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()\")->fetchColumn(),
'near_expiry_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)\")->fetchColumn(),
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
];
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
\$data['stats']['total_payable'] = \$data['stats']['total_purchases'] - \$data['stats']['total_paid'];
// Sales Chart Data
\$data['monthly_sales'] = db()->query(\"SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12\")->fetchAll(PDO::FETCH_ASSOC);
\$data['yearly_sales'] = db()->query(\"SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
}";
$replace = " default:
if (can('dashboard_view')) {
\$oW = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"WHERE outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
\$oA = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"AND outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
\$data['stats'] = [
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed' \$oA\")->fetchColumn() ?: 0),
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments \$oW\")->fetchColumn() ?: 0),
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases \$oW\")->fetchColumn() ?: 0,
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments \$oW\")->fetchColumn() ?: 0,
'expired_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()\")->fetchColumn(),
'near_expiry_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)\")->fetchColumn(),
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
];
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
\$data['stats']['total_payable'] = \$data['stats']['total_purchases'] - \$data['stats']['total_paid'];
// Sales Chart Data
\$data['monthly_sales'] = db()->query(\"SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices \$oW GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12\")->fetchAll(PDO::FETCH_ASSOC);
\$data['yearly_sales'] = db()->query(\"SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices \$oW GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
}";
if (strpos($content, $search) !== false) {
$content = str_replace($search, $replace, $content);
echo "Dashboard patched successfully\n";
file_put_contents('index.php', $content);
} else {
echo "Could not find target to patch\n";
}
$content = file_get_contents('index.php');
$replacements = [
[
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [\"1=1\"];",
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"v.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'quotations':\n \$where = [\"1=1\"];",
"case 'quotations':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'lpos':\n \$where = [\"1=1\"];",
"case 'lpos':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'expenses':\n \$where = [\"1=1\"];",
"case 'expenses':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"e.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'payments':",
"case 'payments':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"p.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
]
];
foreach ($replacements as $rep) {
if (strpos($content, $rep[0]) !== false) {
$content = str_replace($rep[0], $rep[1], $content);
echo "Patched successfully\n";
} else {
echo "Could not find target to patch\n";
}
}
file_put_contents('index.php', $content);

56
patch_dashboard.php Normal file
View File

@ -0,0 +1,56 @@
<?php
$content = file_get_contents('index.php');
$search = " default:
if (can('dashboard_view')) {
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
\$data['stats'] = [
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed'\")->fetchColumn() ?: 0),
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments\")->fetchColumn() ?: 0),
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases\")->fetchColumn() ?: 0,
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments\")->fetchColumn() ?: 0,
'expired_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()\")->fetchColumn(),
'near_expiry_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)\")->fetchColumn(),
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
];
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
\$data['stats']['total_payable'] = \$data['stats']['total_purchases'] - \$data['stats']['total_paid'];
// Sales Chart Data
\$data['monthly_sales'] = db()->query(\"SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12\")->fetchAll(PDO::FETCH_ASSOC);
\$data['yearly_sales'] = db()->query(\"SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
}";
$replace = " default:
if (can('dashboard_view')) {
\$oW = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"WHERE outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
\$oA = ((\$_SESSION['outlet_id'] ?? 1) == 0) ? \"\" : \"AND outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);
\$data['customers'] = db()->query(\"SELECT * FROM customers ORDER BY id DESC LIMIT 5\")->fetchAll();
\$data['stats'] = [
'total_customers' => db()->query(\"SELECT COUNT(*) FROM customers\")->fetchColumn(),
'total_items' => db()->query(\"SELECT COUNT(*) FROM stock_items\")->fetchColumn(),
'total_sales' => (db()->query(\"SELECT SUM(total_with_vat) FROM invoices \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed' \$oA\")->fetchColumn() ?: 0),
'total_received' => (db()->query(\"SELECT SUM(amount) FROM payments \$oW\")->fetchColumn() ?: 0) + (db()->query(\"SELECT SUM(amount) FROM pos_payments \$oW\")->fetchColumn() ?: 0),
'total_purchases' => db()->query(\"SELECT SUM(total_with_vat) FROM purchases \$oW\")->fetchColumn() ?: 0,
'total_paid' => db()->query(\"SELECT SUM(amount) FROM purchase_payments \$oW\")->fetchColumn() ?: 0,
'expired_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()\")->fetchColumn(),
'near_expiry_items' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)\")->fetchColumn(),
'low_stock_items_count' => db()->query(\"SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level\")->fetchColumn(),
];
\$data['stats']['total_receivable'] = \$data['stats']['total_sales'] - \$data['stats']['total_received'];
\$data['stats']['total_payable'] = \$data['stats']['total_purchases'] - \$data['stats']['total_paid'];
// Sales Chart Data
\$data['monthly_sales'] = db()->query(\"SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices \$oW GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12\")->fetchAll(PDO::FETCH_ASSOC);
\$data['yearly_sales'] = db()->query(\"SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices \$oW GROUP BY label ORDER BY label ASC LIMIT 5\")->fetchAll(PDO::FETCH_ASSOC);
}";
if (strpos($content, $search) !== false) {
$content = str_replace($search, $replace, $content);
echo "Dashboard patched successfully\n";
file_put_contents('index.php', $content);
} else {
echo "Could not find target to patch\n";
}

68
patch_inserts.php Normal file
View File

@ -0,0 +1,68 @@
<?php
$content = file_get_contents('index.php');
$patterns = [
// Invoices (POS)
[
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
'?, ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?'
],
// Quotations
[
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
'?, ?, ?, ?, ?, ?, ?',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?, ?, ?'
],
// Lpos
[
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
'?, ?, ?, \'pending\', ?, ?, ?, ?',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, \'pending\', ?, ?, ?, ?'
],
// Invoices (General)
[
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0'
],
// Purchases (General)
[
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0'
],
// Expenses
[
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description)',
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description)',
'(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc',
'".(int)($_SESSION["outlet_id"] ?? 1).", (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc'
],
// Users
[
'INSERT INTO users (username, password, email, phone, group_id)',
'INSERT INTO users (outlet_id, username, password, email, phone, group_id)',
'?, ?, ?, ?, ?',
'".(int)($_SESSION["outlet_id"] ?? 1).", ?, ?, ?, ?, ?'
]
];
foreach ($patterns as $p) {
if (strpos($content, $p[0]) !== false) {
$content = str_replace($p[0], $p[1], $content);
$content = str_replace($p[2], $p[3], $content);
echo "Patched " . explode(' ', $p[0])[2] . "\n";
}
}
// Don't forget invoice_items insertion
$p1 = 'INSERT INTO invoice_items (invoice_id, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)';
$p2 = 'INSERT INTO invoice_items (invoice_id, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)';
// Actually wait, invoice_items doesn't have outlet_id... No wait, does it?
file_put_contents('index.php', $content);

78
patch_inserts_final.php Normal file
View File

@ -0,0 +1,78 @@
<?php
$content = file_get_contents('index.php');
$replacements = [
// Invoices (POS)
[
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?)',
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, \'paid\', ?, 1, ?, ?, ?)'
],
[
'execute([$transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])'
],
// Quotations
[
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat) VALUES (?, ?, ?, \'pending\', ?, ?, ?)',
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat) VALUES (?, ?, ?, ?, \'pending\', ?, ?, ?)'
],
[
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
],
// Lpos
[
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, \'pending\', ?, ?, ?, ?)',
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions) VALUES (?, ?, ?, ?, \'pending\', ?, ?, ?, ?)'
],
[
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])'
],
// Invoices (General)
[
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)',
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)'
],
[
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
],
// Purchases (General)
[
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)',
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, \'unpaid\', \'credit\', ?, ?, ?, 0)'
],
[
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
],
// Expenses
[
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?)',
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description) VALUES (?, ?, ?, ?, ?, ?)'
],
[
'execute([(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])'
],
// Users
[
'INSERT INTO users (username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?)',
'INSERT INTO users (outlet_id, username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?, ?)'
],
[
'execute([$_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])'
]
];
foreach ($replacements as $p) {
if (strpos($content, $p[0]) !== false) {
$content = str_replace($p[0], $p[1], $content);
echo "Replaced OK.\n";
} else {
echo "Not found: " . substr($p[0], 0, 40) . "\n";
}
}
file_put_contents('index.php', $content);

76
patch_inserts_safe.php Normal file
View File

@ -0,0 +1,76 @@
<?php
$content = file_get_contents('index.php');
$patterns = [
// Invoices (POS)
[
'INSERT INTO invoices (transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
'INSERT INTO invoices (outlet_id, transaction_no, customer_id, invoice_date, payment_type, total_amount, vat_amount, total_with_vat, paid_amount, status, register_session_id, is_pos, discount_amount, loyalty_points_redeemed, created_by)',
'execute([$transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $transaction_no, $customer_id, date(\'Y-m-d\'), \'pos\', $total_amount, $tax_amount, $net_amount, $net_amount, $session_id, $discount_amount, $loyalty_redeemed, $_SESSION[\'user_id\']])'
],
// Quotations
[
'INSERT INTO quotations (customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
'INSERT INTO quotations (outlet_id, customer_id, quotation_date, valid_until, status, total_amount, vat_amount, total_with_vat)',
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], $_POST[\'valid_until\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\']])'
],
// Lpos
[
'INSERT INTO lpos (supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
'INSERT INTO lpos (outlet_id, supplier_id, lpo_date, delivery_date, status, total_amount, vat_amount, total_with_vat, terms_conditions)',
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], $_POST[\'delivery_date\'], \'pending\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], $_POST[\'terms\'] ?? \'\'])'
],
// Invoices (General)
[
'INSERT INTO invoices (customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'INSERT INTO invoices (outlet_id, customer_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'execute([$_POST[\'customer_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'customer_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])'
],
// Purchases (General)
[
'INSERT INTO purchases (supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'INSERT INTO purchases (outlet_id, supplier_id, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount)',
'execute([$_POST[\'supplier_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'supplier_id\'], $_POST[\'date\'], \'unpaid\', \'credit\', $totals[\'total\'], $totals[\'tax\'], $totals[\'net\'], 0])'
],
// Expenses
[
'INSERT INTO expenses (category_id, amount, expense_date, reference_no, description)',
'INSERT INTO expenses (outlet_id, category_id, amount, expense_date, reference_no, description)',
'execute([(int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), (int)$_POST[\'category_id\'], $amt, $date, $_POST[\'reference_no\'] ?? \'\', $desc])'
],
// Users
[
'INSERT INTO users (username, password, email, phone, group_id)',
'INSERT INTO users (outlet_id, username, password, email, phone, group_id)',
'execute([$_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])',
'execute([(int)($_SESSION["outlet_id"] ?? 1), $_POST[\'username\'], password_hash($_POST[\'password\'], PASSWORD_DEFAULT), $_POST[\'email\'] ?? \'\', $_POST[\'phone\'] ?? \'\', (int)$_POST[\'group_id\']])'
]
];
foreach ($patterns as $i => $p) {
if (strpos($content, $p[0]) !== false) {
$content = str_replace($p[0], $p[1], $content);
$content = str_replace($p[2], $p[3], $content);
echo "Patched #$i \n";
// Let's also add the ? to the query string
$q0 = "VALUES (";
$q1 = "VALUES (?, ";
// We only want to add it inside the specific INSERT query
$insert_start = strpos($content, $p[1]);
if ($insert_start !== false) {
$values_start = strpos($content, 'VALUES (', $insert_start);
if ($values_start !== false) {
$content = substr_replace($content, 'VALUES (?, ', $values_start, 9);
}
}
}
}
file_put_contents('index.php', $content);

36
patch_where.php Normal file
View File

@ -0,0 +1,36 @@
<?php
$content = file_get_contents('index.php');
$replacements = [
[
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [\"1=1\"];",
"case 'sales':\n case 'purchases':\n \$type = (\$page === 'sales') ? 'sale' : 'purchase';\n \$table = (\$type === 'purchase') ? 'purchases' : 'invoices';\n \$cust_supplier_col = (\$type === 'purchase') ? 'supplier_id' : 'customer_id';\n \$cust_supplier_table = (\$type === 'purchase') ? 'suppliers' : 'customers';\n \n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"v.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'quotations':\n \$where = [\"1=1\"];",
"case 'quotations':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'lpos':\n \$where = [\"1=1\"];",
"case 'lpos':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"q.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'expenses':\n \$where = [\"1=1\"];",
"case 'expenses':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"e.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
],
[
"case 'payments':",
"case 'payments':\n \$where = [];\n if ((\$_SESSION['outlet_id'] ?? 1) != 0) \$where[] = \"p.outlet_id = \" . (int)(\$_SESSION['outlet_id'] ?? 1);\n else \$where[] = \"1=1\";"
]
];
foreach ($replacements as $rep) {
if (strpos($content, $rep[0]) !== false) {
$content = str_replace($rep[0], $rep[1], $content);
echo "Patched successfully\n";
} else {
echo "Could not find target to patch\n";
}
}
file_put_contents('index.php', $content);

1
post_debug.log Normal file
View File

@ -0,0 +1 @@
2026-02-25 09:56:38 - POST: {"action":"translate","text":"Product 2","target":"ar"}

13
replace_inserts.php Normal file
View File

@ -0,0 +1,13 @@
<?php
$content = file_get_contents('index.php');
$tables = ['users', 'invoices', 'lpos', 'purchases', 'quotations', 'expenses', 'payments', 'purchase_payments', 'pos_transactions', 'customers', 'suppliers', 'stock_items', 'pos_held_carts', 'loyalty_transactions', 'purchase_returns', 'sales_returns'];
foreach ($tables as $t) {
// Regex to match: INSERT INTO table (...) VALUES (...)
// and replace with INSERT INTO table (outlet_id, ...) VALUES (current_outlet_id(), ...)
// Note: since this is PDO prepare, we can't just inject current_outlet_id() directly into VALUES if it's parametrized, but we CAN inject the value if we just use a session variable call directly in SQL, or `?` and prepend the param.
// Wait, simpler: "INSERT INTO $t (outlet_id, " . "(current_outlet_id())" is safe enough?
// Let's look at a simpler regex.
}

25
test_func.php Normal file
View File

@ -0,0 +1,25 @@
<?php
require 'db/config.php';
$db = db();
try {
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
$db->exec("RENAME TABLE invoices TO _invoices");
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL");
$db->exec("SET @session_outlet_id = 1");
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
echo "Insert OK\n";
$stmt = $db->query("SELECT * FROM invoices ORDER BY id DESC LIMIT 1");
print_r($stmt->fetch(PDO::FETCH_ASSOC));
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
$db->exec("DROP VIEW IF EXISTS invoices");
$db->exec("RENAME TABLE _invoices TO invoices");
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");

21
test_last_insert.php Normal file
View File

@ -0,0 +1,21 @@
<?php
require 'db/config.php';
$db = db();
try {
$db->exec("RENAME TABLE invoices TO _invoices");
$db->exec("CREATE FUNCTION current_outlet_id() RETURNS INT DETERMINISTIC RETURN @session_outlet_id");
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = current_outlet_id() OR current_outlet_id() IS NULL");
$db->exec("SET @session_outlet_id = 1");
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
$id = $db->lastInsertId();
echo "Last Insert ID: " . $id . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
$db->exec("DROP VIEW IF EXISTS invoices");
$db->exec("RENAME TABLE _invoices TO invoices");
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");
$db->exec("DROP FUNCTION IF EXISTS current_outlet_id");

23
test_view.php Normal file
View File

@ -0,0 +1,23 @@
<?php
require 'db/config.php';
$db = db();
try {
$db->exec("RENAME TABLE invoices TO _invoices");
$db->exec("CREATE VIEW invoices AS SELECT * FROM _invoices WHERE outlet_id = @session_outlet_id OR @session_outlet_id IS NULL");
$db->exec("SET @session_outlet_id = 1");
// Test INSERT
$db->exec("INSERT INTO invoices (customer_id, invoice_date, status, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (1, '2026-01-01', 'unpaid', 100, 5, 105, 0)");
echo "Insert OK\n";
// Check if outlet_id is populated. It won't be, because the view doesn't auto-fill!
// We still need the trigger for INSERT.
$stmt = $db->query("SELECT * FROM invoices ORDER BY id DESC LIMIT 1");
print_r($stmt->fetch(PDO::FETCH_ASSOC));
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
// rollback
$db->exec("DROP VIEW IF EXISTS invoices");
$db->exec("RENAME TABLE _invoices TO invoices");
$db->exec("DELETE FROM invoices WHERE customer_id=1 AND total_amount=100");

372
wheres.txt Normal file
View File

@ -0,0 +1,372 @@
if ($type === 'sales' || $type === 'purchases') {
$table = ($type === 'sales') ? 'invoices' : 'purchases';
$cust_table = ($type === 'sales') ? 'customers' : 'suppliers';
$cust_col = ($type === 'sales') ? 'customer_id' : 'supplier_id';
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(v.id LIKE ? OR c.name LIKE ? OR v.id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
} else {
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
if (!empty($_GET['customer_id'])) { $where[] = "v.$cust_col = ?"; $params[] = $_GET['customer_id']; }
if (!empty($_GET['start_date'])) { $where[] = "v.invoice_date >= ?"; $params[] = $_GET['start_date']; }
if (!empty($_GET['end_date'])) { $where[] = "v.invoice_date <= ?"; $params[] = $_GET['end_date']; }
$whereSql = implode(" AND ", $where);
--
$stmt->execute($params);
$headers = ['Invoice ID', 'Customer/Supplier', 'Date', 'Payment', 'Status', 'Total', 'Paid', 'Balance'];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
} elseif ($type === 'customers' || $type === 'suppliers') {
$table = ($type === 'suppliers') ? 'suppliers' : 'customers';
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) { $where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
if (!empty($_GET['start_date'])) { $where[] = "DATE(created_at) >= ?"; $params[] = $_GET['start_date']; }
if (!empty($_GET['end_date'])) { $where[] = "DATE(created_at) <= ?"; $params[] = $_GET['end_date']; }
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT id, name, email, phone, tax_id, balance, created_at FROM $table WHERE $whereSql ORDER BY id DESC");
$stmt->execute($params);
$headers = ['ID', 'Name', 'Email', 'Phone', 'Tax ID', 'Balance', 'Created At'];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
} elseif ($type === 'items') {
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) { $where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT i.sku, i.name_en, i.name_ar, c.name_en as category, i.purchase_price, i.sale_price, i.stock_quantity, i.vat_rate
FROM stock_items i LEFT JOIN stock_categories c ON i.category_id = c.id
WHERE $whereSql ORDER BY i.id DESC");
$stmt->execute($params);
$headers = ['SKU', 'Name (EN)', 'Name (AR)', 'Category', 'Purchase Price', 'Sale Price', 'Quantity', 'VAT %'];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
} elseif ($type === 'expenses') {
$where = ["1=1"];
$params = [];
$stmt = db()->prepare("SELECT e.id, c.name_en as category, e.amount, e.expense_date, e.reference_no, e.description
FROM expenses e JOIN expense_categories c ON e.category_id = c.id
ORDER BY e.expense_date DESC");
$stmt->execute();
$headers = ['ID', 'Category', 'Amount', 'Date', 'Reference', 'Description'];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
} elseif ($type === 'quotations') {
$stmt = db()->prepare("SELECT q.id, c.name as customer_name, q.quotation_date, q.total_with_vat, q.status
FROM quotations q JOIN customers c ON q.customer_id = c.id
ORDER BY q.id DESC");
$stmt->execute();
$headers = ['Quotation #', 'Customer', 'Date', 'Total', 'Status'];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $rows[] = $row;
} elseif ($type === 'lpos') {
$stmt = db()->prepare("SELECT q.id, s.name as supplier_name, q.lpo_date, q.total_with_vat, q.status
FROM lpos q JOIN suppliers s ON q.supplier_id = s.id
ORDER BY q.id DESC");
$stmt->execute();
$headers = ['LPO #', 'Supplier', 'Date', 'Total', 'Status'];
--
$page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
if ($page_num < 1) $page_num = 1;
$offset = ($page_num - 1) * $limit;
switch ($page) {
case 'suppliers':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
if (!empty($_GET['start_date'])) {
$where[] = "DATE(created_at) >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "DATE(created_at) <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$countStmt = db()->prepare("SELECT COUNT(*) FROM suppliers WHERE $whereSql");
$countStmt->execute($params);
--
$stmt = db()->prepare("SELECT * FROM suppliers WHERE $whereSql ORDER BY id DESC LIMIT $limit OFFSET $offset");
$stmt->execute($params);
$data['customers'] = $stmt->fetchAll(); // Keep 'customers' key for template compatibility if needed, or update template
break;
case 'customers':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
if (!empty($_GET['start_date'])) {
$where[] = "DATE(created_at) >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "DATE(created_at) <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$countStmt = db()->prepare("SELECT COUNT(*) FROM customers WHERE $whereSql");
$countStmt->execute($params);
--
case 'units':
// Already fetched globally
break;
case 'items':
file_put_contents('debug.log', date('Y-m-d H:i:s') . " - Items case hit\n", FILE_APPEND);
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
$whereSql = implode(" AND ", $where);
$countStmt = db()->prepare("SELECT COUNT(*) FROM stock_items i
LEFT JOIN stock_categories c ON i.category_id = c.id
LEFT JOIN stock_units u ON i.unit_id = u.id
LEFT JOIN suppliers s ON i.supplier_id = s.id WHERE $whereSql");
$countStmt->execute($params);
$total_records = (int)$countStmt->fetchColumn();
$data['total_pages'] = ceil($total_records / $limit);
$data['current_page'] = $page_num;
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar, u.short_name_en as unit_en, u.short_name_ar as unit_ar, s.name as supplier_name
FROM stock_items i
--
ORDER BY i.id DESC LIMIT $limit OFFSET $offset");
$stmt->execute($params);
$data['items'] = $stmt->fetchAll();
break;
case 'quotations':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(q.id LIKE ? OR c.name LIKE ? OR q.id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
} else {
$where[] = "(q.id LIKE ? OR c.name LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
if (!empty($_GET['customer_id'])) {
$where[] = "q.customer_id = ?";
$params[] = $_GET['customer_id'];
}
if (!empty($_GET['start_date'])) {
--
LIMIT $limit OFFSET $offset");
$stmt->execute($params);
$data['quotations'] = $stmt->fetchAll();
break;
case 'lpos':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(q.id LIKE ? OR s.name LIKE ? OR q.id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
} else {
$where[] = "(q.id LIKE ? OR s.name LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
if (!empty($_GET['supplier_id'])) {
$where[] = "q.supplier_id = ?";
$params[] = $_GET['supplier_id'];
}
if (!empty($_GET['start_date'])) {
--
$type = ($page === 'sales') ? 'sale' : 'purchase';
$table = ($type === 'purchase') ? 'purchases' : 'invoices';
$cust_supplier_col = ($type === 'purchase') ? 'supplier_id' : 'customer_id';
$cust_supplier_table = ($type === 'purchase') ? 'suppliers' : 'customers';
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(v.id LIKE ? OR c.name LIKE ? OR v.id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
} else {
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
if (!empty($_GET['customer_id'])) {
$where[] = "v.$cust_supplier_col = ?";
$params[] = $_GET['customer_id'];
--
$data['purchase_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM purchases ORDER BY id DESC")->fetchAll();
}
break;
case 'sales_returns':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ? OR sr.id = ? OR sr.invoice_id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
$params[] = $clean_id;
} else {
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT sr.*, c.name as customer_name, i.total_with_vat as invoice_total
--
$data['returns'] = $stmt->fetchAll();
$data['sales_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices ORDER BY id DESC")->fetchAll();
break;
case 'purchase_returns':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$s = $_GET['search'];
$clean_id = preg_replace('/[^0-9]/', '', $s);
if ($clean_id !== '') {
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ? OR pr.id = ? OR pr.purchase_id = ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = $clean_id;
$params[] = $clean_id;
} else {
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ?)";
$params[] = "%$s%";
$params[] = "%$s%";
$params[] = "%$s%";
}
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT pr.*, c.name as supplier_name, i.total_with_vat as invoice_total
--
break;
case 'expense_categories':
$data['expense_categories'] = db()->query("SELECT * FROM expense_categories ORDER BY name_en ASC")->fetchAll();
break;
case 'expenses':
$where = ["1=1"];
$params = [];
if (!empty($_GET['category_id'])) {
$where[] = "e.category_id = ?";
$params[] = $_GET['category_id'];
}
if (!empty($_GET['start_date'])) {
$where[] = "e.expense_date >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "e.expense_date <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT e.*, c.name_en as cat_en, c.name_ar as cat_ar
FROM expenses e
LEFT JOIN expense_categories c ON e.category_id = c.id
WHERE $whereSql
ORDER BY e.expense_date DESC, e.id DESC");
$stmt->execute($params);
--
$data['year'] = $year;
$data['payroll'] = db()->query("SELECT p.*, e.name as emp_name FROM hr_payroll p JOIN hr_employees e ON p.employee_id = e.id WHERE p.payroll_month = $month AND p.payroll_year = $year ORDER BY p.id DESC")->fetchAll();
$data['employees'] = db()->query("SELECT id, name, salary FROM hr_employees WHERE status = 'active' ORDER BY name ASC")->fetchAll();
break;
case 'loyalty_history':
$where = ["1=1"];
$params = [];
if (!empty($_GET['customer_id'])) {
$where[] = "lt.customer_id = ?";
$params[] = (int)$_GET['customer_id'];
}
if (!empty($_GET['type'])) {
$where[] = "lt.transaction_type = ?";
$params[] = $_GET['type'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT lt.*, c.name as customer_name, c.loyalty_tier, c.loyalty_points
FROM loyalty_transactions lt
JOIN customers c ON lt.customer_id = c.id
WHERE $whereSql
ORDER BY lt.created_at DESC");
$stmt->execute($params);
$data['loyalty_transactions'] = $stmt->fetchAll();
break;
case 'devices':
$data['devices'] = db()->query("SELECT * FROM hr_biometric_devices ORDER BY id DESC")->fetchAll();
--
break;
case 'cash_registers':
$data['cash_registers'] = db()->query("SELECT * FROM cash_registers ORDER BY id DESC")->fetchAll();
break;
case 'register_sessions':
$where = ["1=1"];
$params = [];
// Filter by user if provided and user has permission
if (isset($_GET['user_id']) && !empty($_GET['user_id'])) {
if (can('users_view')) {
$where[] = "s.user_id = ?";
$params[] = $_GET['user_id'];
}
}
if (!can('users_view')) {
$where[] = "s.user_id = ?";
$params[] = $_SESSION['user_id'];
}
// Filter by date range
if (isset($_GET['date_from']) && !empty($_GET['date_from'])) {
$where[] = "s.opened_at >= ?";
$params[] = $_GET['date_from'] . ' 00:00:00';
}