diff --git a/edit_sale.php b/edit_sale.php index 8714123..31f34d6 100644 --- a/edit_sale.php +++ b/edit_sale.php @@ -20,7 +20,7 @@ $pageTitle = tr('تعديل فاتورة', 'Edit Invoice') . ' #' . h($editSale[ $activeNav = 'sales'; $error = ''; $catalog = catalog(); -$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']]; +$allowedBranches = get_user_branches($user); try { $customers = db()->query('SELECT id, name, phone FROM customers ORDER BY name ASC')->fetchAll(); diff --git a/expenses.php b/expenses.php index be24b46..dd59f5d 100644 --- a/expenses.php +++ b/expenses.php @@ -22,7 +22,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; if ($action === 'create' && has_permission('expenses', 'add')) { - $branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch; + $pb = $_POST['branch_code'] ?? ''; $branch_code = can_access_branch($pb) ? $pb : $userBranch; if ($pb === '' && $user['role'] === 'owner') { $branch_code = null; } else if ($branch_code === '') { $branch_code = null; } $stmt = $pdo->prepare('INSERT INTO expenses (branch_code, category_id, amount, expense_date, description, created_by) VALUES (?, ?, ?, ?, ?, ?)'); $stmt->execute([ $branch_code === '' ? null : $branch_code, @@ -35,7 +35,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { set_flash('success', tr('تمت إضافة المصروف بنجاح', 'Expense added successfully')); redirect_to('expenses.php'); } elseif ($action === 'edit' && has_permission('expenses', 'edit')) { - $branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch; + $pb = $_POST['branch_code'] ?? ''; $branch_code = can_access_branch($pb) ? $pb : $userBranch; if ($pb === '' && $user['role'] === 'owner') { $branch_code = null; } else if ($branch_code === '') { $branch_code = null; } $stmt = $pdo->prepare('UPDATE expenses SET branch_code = ?, category_id = ?, amount = ?, expense_date = ?, description = ? WHERE id = ?'); $stmt->execute([ $branch_code === '' ? null : $branch_code, @@ -68,9 +68,17 @@ if ($search) { $params[] = "%$search%"; } -if (!$isOwner && $userBranch) { - $where .= ' AND (e.branch_code = ? OR e.branch_code IS NULL)'; - $params[] = $userBranch; +if (!$isOwner) { + $ubranches = get_user_branches($user); + if (!empty($ubranches)) { + $inQuery = implode(',', array_fill(0, count($ubranches), '?')); + $where .= " AND (e.branch_code IN ($inQuery) OR e.branch_code IS NULL)"; + foreach ($ubranches as $ub) { + $params[] = $ub; + } + } else { + $where .= " AND e.branch_code IS NULL"; + } } $totalStmt = $pdo->prepare("SELECT COUNT(*) FROM expenses e WHERE $where"); diff --git a/includes/app.php b/includes/app.php index 27fe2c7..ed95c85 100644 --- a/includes/app.php +++ b/includes/app.php @@ -201,6 +201,35 @@ function require_roles(array $roles): array return $user; } +function get_user_branches($user): array +{ + if (!$user) return []; + if ($user['role'] === 'owner') return array_keys(branches()); + $list = [$user['branch_code']]; + if (!empty($user['allowed_branches'])) { + $extra = explode(',', $user['allowed_branches']); + foreach ($extra as $b) { + $b = trim($b); + if ($b) $list[] = $b; + } + } + return array_unique($list); +} + +function get_user_branches_assoc($user): array +{ + if (!$user) return []; + $all = branches(); + $allowed = get_user_branches($user); + $res = []; + foreach ($allowed as $b) { + if (isset($all[$b])) { + $res[$b] = $all[$b]; + } + } + return $res; +} + function can_access_branch(string $branchCode): bool { $user = current_user(); @@ -212,7 +241,8 @@ function can_access_branch(string $branchCode): bool return true; } - return $user['branch_code'] === $branchCode; + $allowed = get_user_branches($user); + return in_array($branchCode, $allowed, true); } function catalog(): array @@ -337,8 +367,18 @@ function base_sales_query_filters(array &$params, ?string $mode = null, ?string $user = current_user(); if ($user && $user['role'] !== 'owner') { - $sql .= ' AND branch_code = :viewer_branch '; - $params[':viewer_branch'] = $user['branch_code']; + $ubranches = get_user_branches($user); + if (empty($ubranches)) { + $sql .= ' AND 1=0 '; // No branches allowed + } else { + $namedParams = []; + foreach ($ubranches as $i => $ub) { + $key = ':v_branch_' . $i; + $namedParams[] = $key; + $params[$key] = $ub; + } + $sql .= ' AND branch_code IN (' . implode(', ', $namedParams) . ') '; + } } return $sql; diff --git a/includes/purchase_form.php b/includes/purchase_form.php index 21ae9de..ffdc3b4 100644 --- a/includes/purchase_form.php +++ b/includes/purchase_form.php @@ -5,7 +5,7 @@ $pageTitle = tr('فاتورة مشتريات جديدة', 'New Purchase'); $activeNav = 'new_purchase'; $error = ''; $catalog = catalog(); -$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']]; +$allowedBranches = get_user_branches($user); try { $customers = $customers = []; diff --git a/includes/sale_form.php b/includes/sale_form.php index e7b04c2..a06394e 100644 --- a/includes/sale_form.php +++ b/includes/sale_form.php @@ -5,7 +5,7 @@ $pageTitle = $saleMode === 'normal' ? tr('إنشاء فاتورة ضريبية', $activeNav = $saleMode === 'normal' ? 'normal' : 'pos'; $error = ''; $catalog = catalog(); -$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']]; +$allowedBranches = get_user_branches($user); try { $customers = db()->query('SELECT id, name, phone FROM customers ORDER BY name ASC')->fetchAll(); diff --git a/patch_export.php b/patch_export.php deleted file mode 100644 index 17e0445..0000000 --- a/patch_export.php +++ /dev/null @@ -1,13 +0,0 @@ -" href=""> - - - - - - - - -HTML; - -$replace = << - - - - - - - - - - - -HTML; - -$newContent = str_replace($search, $replace, $content); -file_put_contents('includes/header.php', $newContent); -echo "Done"; diff --git a/patch_import.php b/patch_import.php deleted file mode 100644 index 290ac7c..0000000 --- a/patch_import.php +++ /dev/null @@ -1,69 +0,0 @@ -beginTransaction(); - try { - $stmtInsert = $pdo->prepare("INSERT INTO items (sku, name, price, cost_price, base_stock, vat, category_id, supplier_id, unit_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmtUpdate = $pdo->prepare("UPDATE items SET name=?, price=?, cost_price=?, base_stock=?, vat=?, category_id=?, supplier_id=?, unit_id=? WHERE sku=?"); - $stmtCheck = $pdo->prepare("SELECT id FROM items WHERE sku=?"); - while (($row = fgetcsv($file)) !== false) { -REPLACE; - -$replace = <<<'REPLACE' - if (isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) { - $pdo = db(); - $file_path = $_FILES['csv_file']['tmp_name']; - $raw_content = file_get_contents($file_path); - - // Prevent ZIP / XLSX - if (str_starts_with($raw_content, 'PK')) { - header('Location: stock.php?import_error=' . urlencode('يرجى حفظ الملف بصيغة CSV وليس كملف إكسل (XLSX)')); - exit; - } - - // Remove UTF-8 BOM if present - if (str_starts_with($raw_content, "\xEF\xBB\xBF")) { - $raw_content = substr($raw_content, 3); - } - - // Fix encoding for Windows-1256 (common in Arabic Excel exports) - if (!mb_check_encoding($raw_content, 'UTF-8')) { - $raw_content = mb_convert_encoding($raw_content, 'UTF-8', 'Windows-1256'); - } - - // Determine delimiter by checking first line - $first_line = strtok($raw_content, "\r\n"); - $delimiter = ','; - if ($first_line !== false && substr_count($first_line, ';') > substr_count($first_line, ',')) { - $delimiter = ';'; - } - - $clean_file = tmpfile(); - fwrite($clean_file, $raw_content); - rewind($clean_file); - - $header = fgetcsv($clean_file, 0, $delimiter); - $imported = 0; $updated = 0; - $pdo->beginTransaction(); - try { - $stmtInsert = $pdo->prepare("INSERT INTO items (sku, name, price, cost_price, base_stock, vat, category_id, supplier_id, unit_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmtUpdate = $pdo->prepare("UPDATE items SET name=?, price=?, cost_price=?, base_stock=?, vat=?, category_id=?, supplier_id=?, unit_id=? WHERE sku=?"); - $stmtCheck = $pdo->prepare("SELECT id FROM items WHERE sku=?"); - while (($row = fgetcsv($clean_file, 0, $delimiter)) !== false) { -REPLACE; - -if (strpos($content, $search) !== false) { - $content = str_replace($search, $replace, $content); - file_put_contents('stock.php', $content); - echo "Replaced successfully.\n"; -} else { - echo "Search string not found.\n"; -} - diff --git a/pos.php b/pos.php index 2694133..f946e77 100644 --- a/pos.php +++ b/pos.php @@ -6,7 +6,7 @@ $pageTitle = tr('نقاط البيع', 'Smart POS'); $activeNav = 'pos'; $error = ''; $catalog = catalog(); -$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']]; +$allowedBranches = get_user_branches($user); try { $pdo = db(); diff --git a/reports.php b/reports.php index 3321ae9..290fa68 100644 --- a/reports.php +++ b/reports.php @@ -109,13 +109,29 @@ if ($tab === 'sales') { $params[':date_to'] = $dateTo; if ($user['role'] !== 'owner') { - $whereConditions[] = "(e.branch_code = :ubranch OR e.branch_code IS NULL)"; - $params[':ubranch'] = $user['branch_code']; - if ($branchFilter && $branchFilter === $user['branch_code']) { + $ubranches = get_user_branches($user); + if ($branchFilter && $branchFilter === 'general') { + $whereConditions[] = "e.branch_code IS NULL"; + } elseif ($branchFilter && in_array($branchFilter, $ubranches, true)) { $whereConditions[] = "e.branch_code = :branch"; $params[':branch'] = $branchFilter; - } elseif ($branchFilter && $branchFilter === 'general') { - $whereConditions[] = "e.branch_code IS NULL"; + } else { + if (empty($ubranches)) { + $whereConditions[] = "e.branch_code IS NULL"; + } else { + $inQuery = implode(',', array_fill(0, count($ubranches), '?')); + // We must use numbered placeholders if mixing with named placeholders? + // PDO might not like mixing ? and :name. + // Let's create named placeholders for in query. + $namedParams = []; + foreach($ubranches as $i => $ub) { + $key = ':ubranch_' . $i; + $namedParams[] = $key; + $params[$key] = $ub; + } + $inQuery = implode(', ', $namedParams); + $whereConditions[] = "(e.branch_code IN ($inQuery) OR e.branch_code IS NULL)"; + } } } else { if ($branchFilter) { @@ -215,7 +231,7 @@ require __DIR__ . '/includes/header.php'; branches()[$user['branch_code']]]; + $availableBranches = get_user_branches_assoc($user); foreach ($availableBranches as $code => $b): ?> @@ -620,7 +636,7 @@ require __DIR__ . '/includes/header.php';