Compare commits
2 Commits
2d79f6ac5f
...
aabdb7b681
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aabdb7b681 | ||
|
|
393595fe77 |
238
db/schema.sql
Normal file
238
db/schema.sql
Normal file
@ -0,0 +1,238 @@
|
||||
-- Table structure for `branches`
|
||||
CREATE TABLE IF NOT EXISTS `branches` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(50) NOT NULL,
|
||||
`name_ar` varchar(100) NOT NULL,
|
||||
`name_en` varchar(100) NOT NULL,
|
||||
`city_ar` varchar(100) DEFAULT NULL,
|
||||
`city_en` varchar(100) DEFAULT NULL,
|
||||
`created_at` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `categories`
|
||||
CREATE TABLE IF NOT EXISTS `categories` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name_ar` varchar(150) NOT NULL,
|
||||
`name_en` varchar(150) NOT NULL,
|
||||
`description` text DEFAULT NULL,
|
||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `customers`
|
||||
CREATE TABLE IF NOT EXISTS `customers` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`phone` varchar(50) DEFAULT NULL,
|
||||
`email` varchar(150) DEFAULT NULL,
|
||||
`address` text DEFAULT NULL,
|
||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `expense_categories`
|
||||
CREATE TABLE IF NOT EXISTS `expense_categories` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name_ar` varchar(255) NOT NULL,
|
||||
`name_en` varchar(255) NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `expenses`
|
||||
CREATE TABLE IF NOT EXISTS `expenses` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`branch_code` varchar(50) DEFAULT NULL,
|
||||
`category_id` int(11) NOT NULL,
|
||||
`amount` decimal(10,3) NOT NULL,
|
||||
`expense_date` date NOT NULL,
|
||||
`description` text DEFAULT NULL,
|
||||
`created_by` int(11) DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `category_id` (`category_id`),
|
||||
CONSTRAINT `expenses_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `expense_categories` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `items`
|
||||
CREATE TABLE IF NOT EXISTS `items` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`sku` varchar(50) NOT NULL,
|
||||
`name` varchar(200) NOT NULL,
|
||||
`price` decimal(10,3) NOT NULL,
|
||||
`cost_price` decimal(10,2) DEFAULT 0.00,
|
||||
`base_stock` int(11) NOT NULL DEFAULT 0,
|
||||
`vat` decimal(5,3) NOT NULL DEFAULT 5.000,
|
||||
`category_id` int(10) unsigned DEFAULT NULL,
|
||||
`supplier_id` int(10) unsigned DEFAULT NULL,
|
||||
`image_url` varchar(255) DEFAULT NULL,
|
||||
`created_at` datetime DEFAULT current_timestamp(),
|
||||
`unit_id` int(10) unsigned DEFAULT NULL,
|
||||
`in_catalog` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `sku` (`sku`),
|
||||
KEY `category_id` (`category_id`),
|
||||
KEY `supplier_id` (`supplier_id`),
|
||||
KEY `items_unit_fk` (`unit_id`),
|
||||
CONSTRAINT `items_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `items_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `suppliers` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `items_unit_fk` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `online_orders`
|
||||
CREATE TABLE IF NOT EXISTS `online_orders` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`customer_name` varchar(255) NOT NULL,
|
||||
`customer_phone` varchar(50) NOT NULL,
|
||||
`customer_address` text NOT NULL,
|
||||
`items_json` longtext NOT NULL,
|
||||
`subtotal` decimal(10,2) DEFAULT 0.00,
|
||||
`vat_amount` decimal(10,2) DEFAULT 0.00,
|
||||
`total_amount` decimal(10,2) NOT NULL,
|
||||
`status` varchar(20) NOT NULL DEFAULT 'pending',
|
||||
`created_at` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `purchase_orders`
|
||||
CREATE TABLE IF NOT EXISTS `purchase_orders` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`reference_no` varchar(50) NOT NULL,
|
||||
`branch_code` varchar(30) NOT NULL,
|
||||
`user_username` varchar(60) NOT NULL,
|
||||
`user_name` varchar(120) NOT NULL,
|
||||
`role_name` varchar(40) NOT NULL,
|
||||
`supplier_name` varchar(120) DEFAULT NULL,
|
||||
`items_json` longtext NOT NULL,
|
||||
`item_count` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`subtotal` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||
`vat_amount` decimal(10,3) NOT NULL DEFAULT 0.000,
|
||||
`total_amount` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||
`notes` text DEFAULT NULL,
|
||||
`status` varchar(20) NOT NULL DEFAULT 'completed',
|
||||
`purchase_date` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `reference_no` (`reference_no`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `sales_orders`
|
||||
CREATE TABLE IF NOT EXISTS `sales_orders` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`receipt_no` varchar(50) NOT NULL,
|
||||
`sale_mode` varchar(20) NOT NULL,
|
||||
`branch_code` varchar(30) NOT NULL,
|
||||
`cashier_username` varchar(60) NOT NULL,
|
||||
`cashier_name` varchar(120) NOT NULL,
|
||||
`role_name` varchar(40) NOT NULL,
|
||||
`customer_name` varchar(120) DEFAULT NULL,
|
||||
`payment_method` varchar(30) NOT NULL,
|
||||
`items_json` longtext NOT NULL,
|
||||
`item_count` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`subtotal` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||
`vat_amount` decimal(10,3) NOT NULL DEFAULT 0.000,
|
||||
`total_amount` decimal(10,2) NOT NULL DEFAULT 0.00,
|
||||
`notes` text DEFAULT NULL,
|
||||
`sale_date` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
`status` varchar(20) NOT NULL DEFAULT 'completed',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `receipt_no` (`receipt_no`),
|
||||
KEY `idx_sale_mode` (`sale_mode`),
|
||||
KEY `idx_branch_code` (`branch_code`),
|
||||
KEY `idx_sale_date` (`sale_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `settings`
|
||||
CREATE TABLE IF NOT EXISTS `settings` (
|
||||
`setting_key` varchar(50) NOT NULL,
|
||||
`setting_value` text DEFAULT NULL,
|
||||
PRIMARY KEY (`setting_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `suppliers`
|
||||
CREATE TABLE IF NOT EXISTS `suppliers` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`contact_person` varchar(150) DEFAULT NULL,
|
||||
`phone` varchar(50) DEFAULT NULL,
|
||||
`email` varchar(150) DEFAULT NULL,
|
||||
`address` text DEFAULT NULL,
|
||||
`created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `units`
|
||||
CREATE TABLE IF NOT EXISTS `units` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name_ar` varchar(150) NOT NULL,
|
||||
`name_en` varchar(150) NOT NULL,
|
||||
`created_at` datetime DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Table structure for `users`
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`role` varchar(50) NOT NULL,
|
||||
`permissions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`permissions`)),
|
||||
`branch_code` varchar(50) NOT NULL,
|
||||
`allowed_branches` varchar(255) DEFAULT NULL,
|
||||
`name_ar` varchar(100) NOT NULL,
|
||||
`name_en` varchar(100) NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Data for table `branches`
|
||||
INSERT IGNORE INTO `branches` (`id`, `code`, `name_ar`, `name_en`, `city_ar`, `city_en`, `created_at`) VALUES ('1', 'muscat', 'الفرع الرئيسي', 'Main Branch', 'مسقط', 'Muscat', '2026-04-19 15:16:52');
|
||||
INSERT IGNORE INTO `branches` (`id`, `code`, `name_ar`, `name_en`, `city_ar`, `city_en`, `created_at`) VALUES ('2', 'sohar', 'فرع صحار', 'Sohar Branch', 'صحار', 'Sohar', '2026-04-19 15:16:52');
|
||||
INSERT IGNORE INTO `branches` (`id`, `code`, `name_ar`, `name_en`, `city_ar`, `city_en`, `created_at`) VALUES ('3', 'nizwa', 'فرع نزوى', 'Nizwa Branch', 'نزوى', 'Nizwa', '2026-04-19 15:16:52');
|
||||
|
||||
-- Data for table `categories`
|
||||
INSERT IGNORE INTO `categories` (`id`, `name_ar`, `name_en`, `description`, `created_at`) VALUES ('1', 'إلكترونيات', 'Electronics', NULL, '2026-04-19 02:39:32');
|
||||
INSERT IGNORE INTO `categories` (`id`, `name_ar`, `name_en`, `description`, `created_at`) VALUES ('2', 'إكسسوارات', 'Accessories', NULL, '2026-04-19 02:39:32');
|
||||
INSERT IGNORE INTO `categories` (`id`, `name_ar`, `name_en`, `description`, `created_at`) VALUES ('3', 'ملابس', 'Clothing', NULL, '2026-04-19 02:39:32');
|
||||
|
||||
-- Data for table `expense_categories`
|
||||
INSERT IGNORE INTO `expense_categories` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('1', 'رواتب', 'Salary', '2026-04-20 02:33:54');
|
||||
INSERT IGNORE INTO `expense_categories` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('2', 'كهرباء وماء', 'Water & Electricity ', '2026-04-20 02:34:28');
|
||||
INSERT IGNORE INTO `expense_categories` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('3', 'أجور عمال', 'Labour', '2026-04-20 02:34:53');
|
||||
INSERT IGNORE INTO `expense_categories` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('4', 'ضرائب', 'Taxes', '2026-04-20 02:35:13');
|
||||
|
||||
-- Data for table `settings`
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_address', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_email', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_favicon', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_logo', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_name_ar', 'حلوى الريامي');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_name_en', 'Al Riyami Sweets');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_phone', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('company_vat_number', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('mail_from', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('mail_from_name', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('smtp_host', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('smtp_pass', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('smtp_port', '587');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('smtp_secure', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('smtp_user', '');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('timezone', 'Asia/Muscat');
|
||||
INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES ('vat_percentage', '5');
|
||||
|
||||
-- Data for table `units`
|
||||
INSERT IGNORE INTO `units` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('1', 'حبة', 'piece ', '2026-04-19 05:03:16');
|
||||
INSERT IGNORE INTO `units` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('2', 'كيلوم جرام', 'Kilogram', '2026-04-19 05:03:44');
|
||||
INSERT IGNORE INTO `units` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('3', 'جرام', 'gram', '2026-04-19 05:04:01');
|
||||
INSERT IGNORE INTO `units` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('4', 'كرتون', 'Carton', '2026-04-19 05:04:21');
|
||||
INSERT IGNORE INTO `units` (`id`, `name_ar`, `name_en`, `created_at`) VALUES ('5', 'كيس', 'bag', '2026-04-19 05:04:36');
|
||||
|
||||
-- Data for table `users`
|
||||
INSERT IGNORE INTO `users` (`id`, `username`, `password`, `role`, `permissions`, `branch_code`, `allowed_branches`, `name_ar`, `name_en`, `created_at`) VALUES ('1', 'owner', '$2y$10$QpW18WHHU8wSKQrYdYTRJuaNPw1v1puJgBpvfc6m9H8gnsws5C9/q', 'owner', NULL, 'muscat', NULL, 'مالك النظام', 'System Owner', '2026-04-19 09:23:45');
|
||||
INSERT IGNORE INTO `users` (`id`, `username`, `password`, `role`, `permissions`, `branch_code`, `allowed_branches`, `name_ar`, `name_en`, `created_at`) VALUES ('2', 'manager_muscat', '$2y$10$mXI290vI7qEIP.At1YFeFOt/pHf096S3h7CWHYfJYluw7QQlM7uDm', 'manager', NULL, 'muscat', NULL, 'مدير فرع مسقط', 'Muscat Branch Manager', '2026-04-19 09:23:45');
|
||||
INSERT IGNORE INTO `users` (`id`, `username`, `password`, `role`, `permissions`, `branch_code`, `allowed_branches`, `name_ar`, `name_en`, `created_at`) VALUES ('3', 'cashier_sohar', '$2y$10$.iWxSZWkRuWhuNrmt/LAv./HCWlHQJSpoYqa9pJMoobHCWbMpvXZe', 'cashier', NULL, 'sohar', NULL, 'كاشير فرع صحار', 'Sohar Cashier', '2026-04-19 09:23:46');
|
||||
|
||||
40
db/setup.php
Normal file
40
db/setup.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Database Setup & Migration Script
|
||||
*
|
||||
* Run this file once to set up the database structure and insert default values.
|
||||
* Access via browser: http://localhost/db/setup.php
|
||||
* Or via CLI: php db/setup.php
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
$sql_file = __DIR__ . '/schema.sql';
|
||||
|
||||
if (!file_exists($sql_file)) {
|
||||
die("Error: schema.sql not found in db directory.");
|
||||
}
|
||||
|
||||
$sql = file_get_contents($sql_file);
|
||||
|
||||
try {
|
||||
// Execute the full SQL file
|
||||
$pdo->exec($sql);
|
||||
$message = "Database schema and default data successfully migrated!";
|
||||
if (php_sapi_name() === 'cli') {
|
||||
echo $message . "\n";
|
||||
} else {
|
||||
echo "<h2 style='color:green; font-family:sans-serif;'>$message</h2>";
|
||||
echo "<p style='font-family:sans-serif;'><a href='../index.php'>Go to App</a></p>";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = "Migration Failed: " . $e->getMessage();
|
||||
if (php_sapi_name() === 'cli') {
|
||||
echo $error . "\n";
|
||||
} else {
|
||||
echo "<h2 style='color:red; font-family:sans-serif;'>$error</h2>";
|
||||
}
|
||||
}
|
||||
|
||||
36
db_seed.php
36
db_seed.php
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
require 'db/config.php';
|
||||
$db = db();
|
||||
|
||||
// 1. Create items table
|
||||
$db->exec("
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
sku VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
price DECIMAL(10,3) NOT NULL,
|
||||
base_stock INT NOT NULL DEFAULT 0,
|
||||
vat DECIMAL(5,3) NOT NULL DEFAULT 5.000,
|
||||
category_id INT UNSIGNED NULL,
|
||||
supplier_id INT UNSIGNED NULL,
|
||||
image_url VARCHAR(255) NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (supplier_id) REFERENCES suppliers(id) ON DELETE SET NULL
|
||||
);
|
||||
");
|
||||
|
||||
// 2. Insert Categories
|
||||
$db->exec("INSERT IGNORE INTO categories (id, name_ar, name_en) VALUES
|
||||
(1, 'إلكترونيات', 'Electronics'),
|
||||
(2, 'إكسسوارات', 'Accessories'),
|
||||
(3, 'ملابس', 'Clothing');");
|
||||
|
||||
// 3. Insert Suppliers
|
||||
$db->exec("INSERT IGNORE INTO suppliers (id, name, contact_person, phone) VALUES
|
||||
(1, 'TechCorp', 'John Doe', '123456789'),
|
||||
(2, 'ElectroWholesale', 'Jane Smith', '987654321'),
|
||||
(3, 'StyleCo', 'Mike Johnson', '555666777');");
|
||||
|
||||
echo "Database schema and base entities created.\n";
|
||||
|
||||
14
dump_schema.php
Normal file
14
dump_schema.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SHOW TABLES");
|
||||
$tables = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$sql = "";
|
||||
foreach ($tables as $table) {
|
||||
$createStmt = $pdo->query("SHOW CREATE TABLE `$table`")->fetch(PDO::FETCH_ASSOC);
|
||||
$sql .= "-- Table structure for `$table`\n";
|
||||
$sql .= $createStmt['Create Table'] . ";\n\n";
|
||||
}
|
||||
echo $sql;
|
||||
|
||||
@ -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();
|
||||
|
||||
18
expenses.php
18
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");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = [];
|
||||
|
||||
@ -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();
|
||||
|
||||
90
patch.php
90
patch.php
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('online_orders.php');
|
||||
|
||||
$phpBackend = <<<'PHP'
|
||||
} elseif ($_POST['action'] === 'edit_order') {
|
||||
$id = (int)$_POST['id'];
|
||||
$customer_name = trim($_POST['customer_name'] ?? '');
|
||||
$customer_phone = trim($_POST['customer_phone'] ?? '');
|
||||
$customer_address = trim($_POST['customer_address'] ?? '');
|
||||
|
||||
if ($customer_name && $customer_phone && $customer_address) {
|
||||
$stmt = $db->prepare("UPDATE online_orders SET customer_name = ?, customer_phone = ?, customer_address = ? WHERE id = ?");
|
||||
$stmt->execute([$customer_name, $customer_phone, $customer_address, $id]);
|
||||
set_flash('success', tr('تم تعديل الطلب بنجاح', 'Order updated successfully'));
|
||||
} else {
|
||||
set_flash('danger', tr('الرجاء تعبئة جميع الحقول', 'Please fill all fields'));
|
||||
}
|
||||
redirect_to('online_orders.php');
|
||||
PHP;
|
||||
|
||||
$content = str_replace("redirect_to('online_orders.php');\n }\n", "redirect_to('online_orders.php');\n }\n" . $phpBackend . "\n }\n", $content);
|
||||
|
||||
$editButton = <<<'HTML'
|
||||
<button class="btn btn-sm btn-info shadow-sm text-white" onclick='editOrder(<?= json_encode([
|
||||
"id" => $o["id"],
|
||||
"name" => $o["customer_name"],
|
||||
"phone" => $o["customer_phone"],
|
||||
"address" => $o["customer_address"]
|
||||
], JSON_UNESCAPED_UNICODE) ?>)'>
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
HTML;
|
||||
|
||||
$content = str_replace('<i class="bi bi-eye"></i>
|
||||
</button>', "<i class=\"bi bi-eye\"></i>\n </button>\n" . $editButton, $content);
|
||||
|
||||
$editModal = <<<'HTML'
|
||||
<!-- Edit Order Modal -->
|
||||
<div class="modal fade d-print-none" id="editOrderModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content rounded-4 border-0 shadow">
|
||||
<form method="post">
|
||||
<input type="hidden" name="action" value="edit_order">
|
||||
<input type="hidden" name="id" id="editOrderId" value="">
|
||||
<div class="modal-header border-bottom-0 pb-0 pt-4 px-4">
|
||||
<h5 class="modal-title fw-bold"><?= h(tr('تعديل بيانات الطلب', 'Edit Order Details')) ?></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"><?= h(tr('اسم العميل', 'Customer Name')) ?></label>
|
||||
<input type="text" name="customer_name" id="editCustomerName" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= h(tr('رقم الهاتف', 'Phone Number')) ?></label>
|
||||
<input type="text" name="customer_phone" id="editCustomerPhone" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= h(tr('العنوان', 'Address')) ?></label>
|
||||
<textarea name="customer_address" id="editCustomerAddress" class="form-control" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-top-0 pt-0 pb-4 px-4">
|
||||
<button type="button" class="btn btn-secondary rounded-pill px-4" data-bs-dismiss="modal"><?= h(tr('إلغاء', 'Cancel')) ?></button>
|
||||
<button type="submit" class="btn btn-primary rounded-pill px-4"><?= h(tr('حفظ التعديلات', 'Save Changes')) ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$content = str_replace('<!-- Order Modal', $editModal . "\n\n<!-- Order Modal", $content);
|
||||
|
||||
$js = <<<'JS'
|
||||
const editOrderModal = new bootstrap.Modal(document.getElementById('editOrderModal'));
|
||||
|
||||
function editOrder(order) {
|
||||
document.getElementById('editOrderId').value = order.id;
|
||||
document.getElementById('editCustomerName').value = order.name;
|
||||
document.getElementById('editCustomerPhone').value = order.phone;
|
||||
document.getElementById('editCustomerAddress').value = order.address;
|
||||
editOrderModal.show();
|
||||
}
|
||||
JS;
|
||||
|
||||
$content = str_replace('const orderModal = new bootstrap.Modal', $js . "\n\nconst orderModal = new bootstrap.Modal", $content);
|
||||
|
||||
file_put_contents('online_orders.php', $content);
|
||||
echo "Patched\n";
|
||||
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('stock.php');
|
||||
$search = "echo \"\";";
|
||||
$replace = 'echo "\xEF\xBB\xBF";';
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('includes/header.php');
|
||||
|
||||
$search = <<<HTML
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'pos' ? 'active' : '' ?>" href="<?= h(url_for('pos.php')) ?>">
|
||||
<i class="bi bi-cart-check"></i> <?= h(tr('نقاط البيع', 'POS Sale')) ?>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'normal' ? 'active' : '' ?>" href="<?= h(url_for('normal_sale.php')) ?>">
|
||||
<i class="bi bi-receipt"></i> <?= h(tr('بيع عادي', 'Normal Sale')) ?>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'sales' ? 'active' : '' ?>" href="<?= h(url_for('sales.php')) ?>">
|
||||
<i class="bi bi-journal-text"></i> <?= h(tr('المبيعات', 'Sales')) ?>
|
||||
</a>
|
||||
HTML;
|
||||
|
||||
$replace = <<<HTML
|
||||
<div class="px-3 pt-3 pb-2 text-white-50 text-uppercase small fw-bold">
|
||||
<?= h(tr('المبيعات', 'Sales')) ?>
|
||||
</div>
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'sales' ? 'active' : '' ?>" href="<?= h(url_for('sales.php')) ?>">
|
||||
<i class="bi bi-journal-text"></i> <?= h(tr('قائمة الفواتير', 'Invoice list')) ?>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'normal' ? 'active' : '' ?>" href="<?= h(url_for('normal_sale.php')) ?>">
|
||||
<i class="bi bi-plus-circle"></i> <?= h(tr('فاتورة جديدة', 'New invoice')) ?>
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action <?= \$activeNav === 'pos' ? 'active' : '' ?>" href="<?= h(url_for('pos.php')) ?>">
|
||||
<i class="bi bi-cart-check"></i> <?= h(tr('نقاط البيع', 'POS')) ?>
|
||||
</a>
|
||||
HTML;
|
||||
|
||||
$newContent = str_replace($search, $replace, $content);
|
||||
file_put_contents('includes/header.php', $newContent);
|
||||
echo "Done";
|
||||
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
$content = file_get_contents('stock.php');
|
||||
$search = <<<'REPLACE'
|
||||
if (isset($_FILES['csv_file']) && $_FILES['csv_file']['error'] === UPLOAD_ERR_OK) {
|
||||
$pdo = db();
|
||||
$file = fopen($_FILES['csv_file']['tmp_name'], 'r');
|
||||
$bom = fread($file, 3);
|
||||
if ($bom !== "") rewind($file);
|
||||
$header = fgetcsv($file);
|
||||
$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($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";
|
||||
}
|
||||
|
||||
2
pos.php
2
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();
|
||||
|
||||
34
reports.php
34
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';
|
||||
<select name="branch" class="form-select">
|
||||
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
||||
<?php
|
||||
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
||||
$availableBranches = get_user_branches_assoc($user);
|
||||
foreach ($availableBranches as $code => $b):
|
||||
?>
|
||||
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
||||
@ -357,7 +373,7 @@ require __DIR__ . '/includes/header.php';
|
||||
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
||||
<option value="general" <?= $branchFilter === 'general' ? 'selected' : '' ?>><?= h(tr('مصروفات عامة', 'General Expenses')) ?></option>
|
||||
<?php
|
||||
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
||||
$availableBranches = get_user_branches_assoc($user);
|
||||
foreach ($availableBranches as $code => $b):
|
||||
?>
|
||||
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
||||
@ -488,7 +504,7 @@ require __DIR__ . '/includes/header.php';
|
||||
<select name="branch" class="form-select" onchange="this.form.submit()">
|
||||
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
||||
<?php
|
||||
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
||||
$availableBranches = get_user_branches_assoc($user);
|
||||
foreach ($availableBranches as $code => $b):
|
||||
?>
|
||||
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
||||
@ -620,7 +636,7 @@ require __DIR__ . '/includes/header.php';
|
||||
<select name="branch" class="form-select" onchange="this.form.submit()">
|
||||
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
||||
<?php
|
||||
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
||||
$availableBranches = get_user_branches_assoc($user);
|
||||
foreach ($availableBranches as $code => $b):
|
||||
?>
|
||||
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
||||
|
||||
14
sales.php
14
sales.php
@ -40,8 +40,18 @@ try {
|
||||
$params[':branch_code'] = $branch;
|
||||
}
|
||||
if ($user && $user['role'] !== 'owner') {
|
||||
$where .= ' AND branch_code = :viewer_branch ';
|
||||
$params[':viewer_branch'] = $user['branch_code'];
|
||||
$ubranches = get_user_branches($user);
|
||||
if (empty($ubranches)) {
|
||||
$where .= ' AND 1=0 ';
|
||||
} else {
|
||||
$namedParams = [];
|
||||
foreach ($ubranches as $i => $ub) {
|
||||
$key = ':v_branch_' . $i;
|
||||
$namedParams[] = $key;
|
||||
$params[$key] = $ub;
|
||||
}
|
||||
$where .= ' AND branch_code IN (' . implode(', ', $namedParams) . ') ';
|
||||
}
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
|
||||
27
users.php
27
users.php
@ -22,9 +22,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ($username && $password && $name_ar) {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
try {
|
||||
$stmt = db()->prepare("INSERT INTO users (username, password, role, branch_code, name_ar, name_en, permissions) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt = db()->prepare("INSERT INTO users (username, password, role, branch_code, allowed_branches, name_ar, name_en, permissions) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$perms = isset($_POST["permissions"]) ? json_encode($_POST["permissions"]) : "{}";
|
||||
$stmt->execute([$username, $hash, $role, $branch_code, $name_ar, $name_en, $perms]);
|
||||
$allowed_branches = isset($_POST["allowed_branches"]) && is_array($_POST["allowed_branches"]) ? implode(",", $_POST["allowed_branches"]) : null;
|
||||
$stmt->execute([$username, $hash, $role, $branch_code, $allowed_branches, $name_ar, $name_en, $perms]);
|
||||
set_flash('success', tr('تمت إضافة المستخدم بنجاح.', 'User added successfully.'));
|
||||
} catch (PDOException $e) {
|
||||
set_flash('error', tr('حدث خطأ، قد يكون اسم المستخدم موجوداً مسبقاً.', 'Error occurred, username might already exist.'));
|
||||
@ -49,13 +50,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
try {
|
||||
if ($password) {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$stmt = db()->prepare("UPDATE users SET username=?, password=?, role=?, branch_code=?, name_ar=?, name_en=?, permissions=? WHERE id=?");
|
||||
$stmt = db()->prepare("UPDATE users SET username=?, password=?, role=?, branch_code=?, allowed_branches=?, name_ar=?, name_en=?, permissions=? WHERE id=?");
|
||||
$perms = isset($_POST["permissions"]) ? json_encode($_POST["permissions"]) : "{}";
|
||||
$stmt->execute([$username, $hash, $role, $branch_code, $name_ar, $name_en, $perms, $id]);
|
||||
$allowed_branches = isset($_POST["allowed_branches"]) && is_array($_POST["allowed_branches"]) ? implode(",", $_POST["allowed_branches"]) : null;
|
||||
$stmt->execute([$username, $hash, $role, $branch_code, $allowed_branches, $name_ar, $name_en, $perms, $id]);
|
||||
} else {
|
||||
$stmt = db()->prepare("UPDATE users SET username=?, role=?, branch_code=?, name_ar=?, name_en=?, permissions=? WHERE id=?");
|
||||
$stmt = db()->prepare("UPDATE users SET username=?, role=?, branch_code=?, allowed_branches=?, name_ar=?, name_en=?, permissions=? WHERE id=?");
|
||||
$perms = isset($_POST["permissions"]) ? json_encode($_POST["permissions"]) : "{}";
|
||||
$stmt->execute([$username, $role, $branch_code, $name_ar, $name_en, $perms, $id]);
|
||||
$allowed_branches = isset($_POST["allowed_branches"]) && is_array($_POST["allowed_branches"]) ? implode(",", $_POST["allowed_branches"]) : null;
|
||||
$stmt->execute([$username, $role, $branch_code, $allowed_branches, $name_ar, $name_en, $perms, $id]);
|
||||
}
|
||||
set_flash('success', tr('تم تعديل المستخدم بنجاح.', 'User updated successfully.'));
|
||||
} catch (PDOException $e) {
|
||||
@ -293,7 +296,17 @@ function openAddModal() {
|
||||
document.getElementById('userAction').value = 'add';
|
||||
document.getElementById('userId').value = '';
|
||||
document.getElementById('userForm').reset();
|
||||
document.querySelectorAll('.perm-check').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('.additional-branch').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('.additional-branch').forEach(cb => cb.checked = false);
|
||||
if (account.allowed_branches) {
|
||||
let abs = account.allowed_branches.split(',');
|
||||
abs.forEach(b => {
|
||||
let cb = document.getElementById('ab_' + b.trim());
|
||||
if (cb) cb.checked = true;
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.perm-check').forEach(cb => cb.checked = false);
|
||||
document.getElementById('userModalLabel').innerText = '<?= h(tr('إضافة مستخدم جديد', 'Add New User')) ?>';
|
||||
document.getElementById('password').required = true;
|
||||
document.getElementById('passwordHelp').innerText = '';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user