Autosave: 20260220-093052

This commit is contained in:
Flatlogic Bot 2026-02-20 09:30:52 +00:00
parent 680e4a7098
commit deddf67d73
4 changed files with 109 additions and 21 deletions

View File

@ -1327,12 +1327,25 @@ DROP TABLE IF EXISTS `role_groups`;
CREATE TABLE `role_groups` ( CREATE TABLE `role_groups` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
`permissions` text DEFAULT NULL,
`created_at` timestamp NULL DEFAULT current_timestamp(), `created_at` timestamp NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!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` -- Dumping data for table `role_groups`
-- --
@ -1340,13 +1353,27 @@ CREATE TABLE `role_groups` (
LOCK TABLES `role_groups` WRITE; LOCK TABLES `role_groups` WRITE;
/*!40000 ALTER TABLE `role_groups` DISABLE KEYS */; /*!40000 ALTER TABLE `role_groups` DISABLE KEYS */;
INSERT INTO `role_groups` VALUES INSERT INTO `role_groups` VALUES
(1,'Administrator','all','2026-02-18 05:30:12'), (1,'Administrator','2026-02-18 05:30:12'),
(4,'Cashier','[\"pos_view\",\"pos_add\",\"items_view\",\"items_add\"]','2026-02-18 09:32:14'), (4,'Cashier','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'), (5,'Admin','2026-02-18 09:33:29'),
(6,'Accountant','[\"accounting_view\",\"accounting_add\",\"accounting_edit\"]','2026-02-18 09:34:03'); (6,'Accountant','2026-02-18 09:34:03');
/*!40000 ALTER TABLE `role_groups` ENABLE KEYS */; /*!40000 ALTER TABLE `role_groups` ENABLE KEYS */;
UNLOCK TABLES; 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` -- Table structure for table `sales_return_items`
-- --

View File

@ -145,13 +145,18 @@ require_once 'includes/accounting_helper.php';
// Helper to check permissions // Helper to check permissions
function can(string $permission): bool { function can(string $permission): bool {
if (!isset($_SESSION['user_id'])) return false; if (!isset($_SESSION['user_id'])) return false;
if (($_SESSION['user_role_name'] ?? '') === 'Administrator' || ($_SESSION['user_permissions'] ?? '') === 'all') return true; if (($_SESSION['user_role_name'] ?? '') === 'Administrator') return true;
$perms = json_decode($_SESSION['user_permissions'] ?? '[]', true); $user_perms = $_SESSION['user_permissions'] ?? [];
return is_array($perms) && in_array($permission, $perms); 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() { function getPurchaseAlerts() {
if (($_SESSION['user_role_name'] ?? '') !== 'Administrator' && ($_SESSION['user_permissions'] ?? '') !== 'all') return []; if (!can('dashboard_view')) return [];
$db = db(); $db = db();
$stmt = $db->query("SELECT p.id, p.due_date, p.total_with_vat, s.name as supplier_name $stmt = $db->query("SELECT p.id, p.due_date, p.total_with_vat, s.name as supplier_name
FROM purchases p FROM purchases p
@ -213,14 +218,20 @@ $login_error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
$user = $_POST['username'] ?? ''; $user = $_POST['username'] ?? '';
$pass = $_POST['password'] ?? ''; $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]); $stmt->execute([$user]);
$u = $stmt->fetch(); $u = $stmt->fetch();
if ($u && password_verify($pass, $u['password'])) { if ($u && password_verify($pass, $u['password'])) {
$_SESSION['user_id'] = $u['id']; $_SESSION['user_id'] = $u['id'];
$_SESSION['username'] = $u['username']; $_SESSION['username'] = $u['username'];
$_SESSION['user_role_name'] = $u['role_name']; $_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['profile_pic'] = $u['profile_pic'];
$_SESSION['theme'] = $u['theme'] ?? 'default'; $_SESSION['theme'] = $u['theme'] ?? 'default';
header("Location: index.php"); header("Location: index.php");
@ -1441,13 +1452,25 @@ if (isset($_POST['add_hr_department'])) {
// --- User & Role Groups Handlers --- // --- User & Role Groups Handlers ---
if (isset($_POST['add_role_group'])) { if (isset($_POST['add_role_group'])) {
$name = $_POST['name'] ?? ''; $name = $_POST['name'] ?? '';
$permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]'; $permissions = isset($_POST['permissions']) ? $_POST['permissions'] : [];
if ($name) { if ($name) {
try { try {
$stmt = db()->prepare("INSERT INTO role_groups (name, permissions) VALUES (?, ?)"); $db = db();
$stmt->execute([$name, $permissions]); $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!"; $message = "Role Group added successfully!";
} catch (PDOException $e) { } catch (PDOException $e) {
if ($db->inTransaction()) $db->rollBack();
$message = "Error adding role group: " . $e->getMessage(); $message = "Error adding role group: " . $e->getMessage();
} }
} }
@ -1477,11 +1500,30 @@ if (isset($_POST['add_hr_department'])) {
if (isset($_POST['edit_role_group'])) { if (isset($_POST['edit_role_group'])) {
$id = (int)$_POST['id']; $id = (int)$_POST['id'];
$name = $_POST['name'] ?? ''; $name = $_POST['name'] ?? '';
$permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]'; $permissions = isset($_POST['permissions']) ? $_POST['permissions'] : [];
if ($id && $name) { if ($id && $name) {
$stmt = db()->prepare("UPDATE role_groups SET name = ?, permissions = ? WHERE id = ?"); try {
$stmt->execute([$name, $permissions, $id]); $db = db();
$message = "Role Group updated successfully!"; $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'])) { if (isset($_POST['delete_role_group'])) {
@ -7421,7 +7463,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div> </div>
<div class="row overflow-auto pe-2" style="max-height: 500px;"> <div class="row overflow-auto pe-2" style="max-height: 500px;">
<?php <?php
$perms = json_decode($group['permissions'] ?? '[]', true); $stmtP = db()->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): ?> foreach ($permission_groups as $group_name => $modules): ?>
<div class="permission-group-container col-12 mb-4"> <div class="permission-group-container col-12 mb-4">
<div class="mt-3 mb-2 bg-secondary bg-opacity-10 p-2 d-flex justify-content-between align-items-center rounded border-start border-primary border-3"> <div class="mt-3 mb-2 bg-secondary bg-opacity-10 p-2 d-flex justify-content-between align-items-center rounded border-start border-primary border-3">

View File

@ -106,7 +106,15 @@ if ($step === 3 && $_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo->exec("CREATE TABLE IF NOT EXISTS role_groups ( $pdo->exec("CREATE TABLE IF NOT EXISTS role_groups (
id INT AUTO_INCREMENT PRIMARY KEY, id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL, 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 ( $pdo->exec("CREATE TABLE IF NOT EXISTS users (
@ -127,10 +135,17 @@ if ($step === 3 && $_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt->execute(); $stmt->execute();
$role = $stmt->fetch(); $role = $stmt->fetch();
if (!$role) { 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(); $roleId = $pdo->lastInsertId();
$pdo->exec("INSERT INTO role_permissions (role_id, permission) VALUES ($roleId, 'all')");
} else { } else {
$roleId = $role['id']; $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) // Insert Admin User (Use ON DUPLICATE KEY UPDATE to handle existing user from schema)

View File

@ -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: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: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 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":""}