diff --git a/complete_schema.sql b/complete_schema.sql index 5d94d0a..ad25a50 100644 --- a/complete_schema.sql +++ b/complete_schema.sql @@ -1327,12 +1327,25 @@ DROP TABLE IF EXISTS `role_groups`; CREATE TABLE `role_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, - `permissions` text DEFAULT NULL, `created_at` timestamp NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `role_permissions` +-- + +DROP TABLE IF EXISTS `role_permissions`; +CREATE TABLE `role_permissions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role_id` int(11) NOT NULL, + `permission` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `role_id` (`role_id`,`permission`), + CONSTRAINT `role_permissions_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `role_groups` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + -- -- Dumping data for table `role_groups` -- @@ -1340,13 +1353,27 @@ CREATE TABLE `role_groups` ( LOCK TABLES `role_groups` WRITE; /*!40000 ALTER TABLE `role_groups` DISABLE KEYS */; INSERT INTO `role_groups` VALUES -(1,'Administrator','all','2026-02-18 05:30:12'), -(4,'Cashier','[\"pos_view\",\"pos_add\",\"items_view\",\"items_add\"]','2026-02-18 09:32:14'), -(5,'Admin','[\"pos_view\",\"pos_add\",\"pos_edit\",\"quotations_view\",\"quotations_add\",\"quotations_edit\",\"customers_view\",\"customers_add\",\"customers_edit\",\"suppliers_view\",\"suppliers_add\",\"suppliers_edit\",\"sales_view\",\"sales_add\",\"sales_edit\",\"purchases_view\",\"purchases_add\",\"purchases_edit\",\"hr_view\",\"hr_add\",\"hr_edit\",\"hr_delete\",\"users_view\"]','2026-02-18 09:33:29'), -(6,'Accountant','[\"accounting_view\",\"accounting_add\",\"accounting_edit\"]','2026-02-18 09:34:03'); +(1,'Administrator','2026-02-18 05:30:12'), +(4,'Cashier','2026-02-18 09:32:14'), +(5,'Admin','2026-02-18 09:33:29'), +(6,'Accountant','2026-02-18 09:34:03'); /*!40000 ALTER TABLE `role_groups` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Dumping data for table `role_permissions` +-- + +LOCK TABLES `role_permissions` WRITE; +/*!40000 ALTER TABLE `role_permissions` DISABLE KEYS */; +INSERT INTO `role_permissions` (role_id, permission) VALUES +(1,'all'), +(4,'pos_view'),(4,'pos_add'),(4,'items_view'),(4,'items_add'), +(5,'pos_view'),(5,'pos_add'),(5,'pos_edit'),(5,'quotations_view'),(5,'quotations_add'),(5,'quotations_edit'),(5,'customers_view'),(5,'customers_add'),(5,'customers_edit'),(5,'suppliers_view'),(5,'suppliers_add'),(5,'suppliers_edit'),(5,'sales_view'),(5,'sales_add'),(5,'sales_edit'),(5,'purchases_view'),(5,'purchases_add'),(5,'purchases_edit'),(5,'hr_view'),(5,'hr_add'),(5,'hr_edit'),(5,'hr_delete'),(5,'users_view'), +(6,'accounting_view'),(6,'accounting_add'),(6,'accounting_edit'); +/*!40000 ALTER TABLE `role_permissions` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `sales_return_items` -- diff --git a/index.php b/index.php index 83e35b4..1786d2a 100644 --- a/index.php +++ b/index.php @@ -145,13 +145,18 @@ require_once 'includes/accounting_helper.php'; // Helper to check permissions function can(string $permission): bool { if (!isset($_SESSION['user_id'])) return false; - if (($_SESSION['user_role_name'] ?? '') === 'Administrator' || ($_SESSION['user_permissions'] ?? '') === 'all') return true; - $perms = json_decode($_SESSION['user_permissions'] ?? '[]', true); - return is_array($perms) && in_array($permission, $perms); + if (($_SESSION['user_role_name'] ?? '') === 'Administrator') return true; + $user_perms = $_SESSION['user_permissions'] ?? []; + if ($user_perms === 'all') return true; + if (is_array($user_perms)) { + return in_array('all', $user_perms) || in_array($permission, $user_perms); + } + $perms = json_decode((string)$user_perms, true); + return is_array($perms) && (in_array('all', $perms) || in_array($permission, $perms)); } function getPurchaseAlerts() { - if (($_SESSION['user_role_name'] ?? '') !== 'Administrator' && ($_SESSION['user_permissions'] ?? '') !== 'all') return []; + if (!can('dashboard_view')) return []; $db = db(); $stmt = $db->query("SELECT p.id, p.due_date, p.total_with_vat, s.name as supplier_name FROM purchases p @@ -213,14 +218,20 @@ $login_error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) { $user = $_POST['username'] ?? ''; $pass = $_POST['password'] ?? ''; - $stmt = db()->prepare("SELECT u.*, g.permissions, g.name as role_name FROM users u LEFT JOIN role_groups g ON u.group_id = g.id WHERE u.username = ? AND u.status = 'active'"); + $stmt = db()->prepare("SELECT u.*, g.name as role_name FROM users u LEFT JOIN role_groups g ON u.group_id = g.id WHERE u.username = ? AND u.status = 'active'"); $stmt->execute([$user]); $u = $stmt->fetch(); if ($u && password_verify($pass, $u['password'])) { $_SESSION['user_id'] = $u['id']; $_SESSION['username'] = $u['username']; $_SESSION['user_role_name'] = $u['role_name']; - $_SESSION['user_permissions'] = $u['permissions']; + + // Fetch permissions from the new role_permissions table + $permStmt = db()->prepare("SELECT permission FROM role_permissions WHERE role_id = ?"); + $permStmt->execute([$u['group_id']]); + $permissions = $permStmt->fetchAll(PDO::FETCH_COLUMN); + $_SESSION['user_permissions'] = $permissions; + $_SESSION['profile_pic'] = $u['profile_pic']; $_SESSION['theme'] = $u['theme'] ?? 'default'; header("Location: index.php"); @@ -1441,13 +1452,25 @@ if (isset($_POST['add_hr_department'])) { // --- User & Role Groups Handlers --- if (isset($_POST['add_role_group'])) { $name = $_POST['name'] ?? ''; - $permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]'; + $permissions = isset($_POST['permissions']) ? $_POST['permissions'] : []; if ($name) { try { - $stmt = db()->prepare("INSERT INTO role_groups (name, permissions) VALUES (?, ?)"); - $stmt->execute([$name, $permissions]); + $db = db(); + $db->beginTransaction(); + $stmt = $db->prepare("INSERT INTO role_groups (name) VALUES (?)"); + $stmt->execute([$name]); + $role_id = $db->lastInsertId(); + + if (!empty($permissions)) { + $stmtPerm = $db->prepare("INSERT INTO role_permissions (role_id, permission) VALUES (?, ?)"); + foreach ($permissions as $p) { + $stmtPerm->execute([$role_id, $p]); + } + } + $db->commit(); $message = "Role Group added successfully!"; } catch (PDOException $e) { + if ($db->inTransaction()) $db->rollBack(); $message = "Error adding role group: " . $e->getMessage(); } } @@ -1477,11 +1500,30 @@ if (isset($_POST['add_hr_department'])) { if (isset($_POST['edit_role_group'])) { $id = (int)$_POST['id']; $name = $_POST['name'] ?? ''; - $permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]'; + $permissions = isset($_POST['permissions']) ? $_POST['permissions'] : []; if ($id && $name) { - $stmt = db()->prepare("UPDATE role_groups SET name = ?, permissions = ? WHERE id = ?"); - $stmt->execute([$name, $permissions, $id]); - $message = "Role Group updated successfully!"; + try { + $db = db(); + $db->beginTransaction(); + $stmt = $db->prepare("UPDATE role_groups SET name = ? WHERE id = ?"); + $stmt->execute([$name, $id]); + + // Refresh permissions + $stmtDel = $db->prepare("DELETE FROM role_permissions WHERE role_id = ?"); + $stmtDel->execute([$id]); + + if (!empty($permissions)) { + $stmtPerm = $db->prepare("INSERT INTO role_permissions (role_id, permission) VALUES (?, ?)"); + foreach ($permissions as $p) { + $stmtPerm->execute([$id, $p]); + } + } + $db->commit(); + $message = "Role Group updated successfully!"; + } catch (PDOException $e) { + if ($db->inTransaction()) $db->rollBack(); + $message = "Error updating role group: " . $e->getMessage(); + } } } if (isset($_POST['delete_role_group'])) { @@ -7421,7 +7463,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
prepare("SELECT permission FROM role_permissions WHERE role_id = ?"); + $stmtP->execute([$group['id']]); + $perms = $stmtP->fetchAll(PDO::FETCH_COLUMN); foreach ($permission_groups as $group_name => $modules): ?>
diff --git a/installation/index.php b/installation/index.php index 26701a8..18494b5 100644 --- a/installation/index.php +++ b/installation/index.php @@ -106,7 +106,15 @@ if ($step === 3 && $_SERVER['REQUEST_METHOD'] === 'POST') { $pdo->exec("CREATE TABLE IF NOT EXISTS role_groups ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, - permissions TEXT + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )"); + + $pdo->exec("CREATE TABLE IF NOT EXISTS role_permissions ( + id INT AUTO_INCREMENT PRIMARY KEY, + role_id INT NOT NULL, + permission VARCHAR(255) NOT NULL, + UNIQUE KEY (role_id, permission), + FOREIGN KEY (role_id) REFERENCES role_groups(id) ON DELETE CASCADE )"); $pdo->exec("CREATE TABLE IF NOT EXISTS users ( @@ -127,10 +135,17 @@ if ($step === 3 && $_SERVER['REQUEST_METHOD'] === 'POST') { $stmt->execute(); $role = $stmt->fetch(); if (!$role) { - $pdo->exec("INSERT INTO role_groups (name, permissions) VALUES ('Administrator', 'all')"); + $pdo->exec("INSERT INTO role_groups (name) VALUES ('Administrator')"); $roleId = $pdo->lastInsertId(); + $pdo->exec("INSERT INTO role_permissions (role_id, permission) VALUES ($roleId, 'all')"); } else { $roleId = $role['id']; + // Also ensure 'all' permission exists for it + $stmt = $pdo->prepare("SELECT id FROM role_permissions WHERE role_id = ? AND permission = 'all'"); + $stmt->execute([$roleId]); + if (!$stmt->fetch()) { + $pdo->exec("INSERT INTO role_permissions (role_id, permission) VALUES ($roleId, 'all')"); + } } // Insert Admin User (Use ON DUPLICATE KEY UPDATE to handle existing user from schema) diff --git a/post_debug.log b/post_debug.log index 823ca75..1bcc3d5 100644 --- a/post_debug.log +++ b/post_debug.log @@ -131,3 +131,5 @@ 2026-02-20 07:28:32 - POST: {"type":"customer","name":"Hamed Mohammed","email":"","phone":"","tax_id":"","balance":"0.000","add_customer":""} 2026-02-20 07:29:31 - POST: {"type":"sale","customer_id":"7","invoice_date":"2026-02-20","due_date":"","payment_type":"cash","status":"paid","paid_amount":"0.000","item_ids":["1"],"quantities":["1"],"prices":["0.450"],"add_invoice":""} 2026-02-20 07:30:15 - POST: {"type":"purchase","customer_id":"7","invoice_date":"2026-02-20","due_date":"","payment_type":"cash","status":"paid","paid_amount":"0.000","item_ids":["1"],"quantities":["150"],"prices":["0.400"],"add_invoice":""} +2026-02-20 09:27:36 - POST: {"invoice_id":"7","return_date":"2026-02-20","quantities":["5"],"item_ids":["1"],"prices":["0.400"],"notes":"","add_purchase_return":""} +2026-02-20 09:28:59 - POST: {"invoice_id":"7","return_date":"2026-02-20","quantities":["3"],"item_ids":["1"],"prices":["0.400"],"notes":"","add_purchase_return":""}