diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..b77b249
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,88 @@
+# Installation Guide
+
+Follow these steps to set up the application on your server.
+
+## 1. Requirements
+
+Before you begin, ensure your server meets the following requirements:
+
+* **Operating System:** Linux, Windows, or macOS.
+* **Web Server:** Apache 2.4+ (with `mod_rewrite` enabled).
+* **PHP:** Version 8.0 or higher.
+* **Database:** MariaDB 10.4+ or MySQL 5.7+.
+* **PHP Extensions:**
+ * `pdo_mysql`
+ * `curl`
+ * `gd` (for image processing)
+ * `mbstring`
+ * `json`
+
+## 2. Database Setup
+
+1. **Create a Database:** Create a new MySQL/MariaDB database (e.g., `pos_system`).
+2. **Configure Connection:** Rename `db/config.php.example` to `db/config.php` (if not already present) and update the database credentials:
+ ```php
+ define('DB_HOST', 'localhost');
+ define('DB_NAME', 'your_database_name');
+ define('DB_USER', 'your_username');
+ define('DB_PASS', 'your_password');
+ ```
+3. **Import Schema:** Import the base schema from `db/schema.sql` into your database.
+4. **Run Migrations:** Import all SQL files located in `db/migrations/` in sequential order (001, 002, etc.).
+5. **Initialize Data:** Run the initialization script by visiting `http://your-domain.com/db/init.php` in your browser. This will seed categories, products, and outlets.
+
+## 3. Creating a Super Admin
+
+Since the initial setup does not include a default user for security reasons, you must create the first Administrator account.
+
+### Option A: Using the Setup Script (Recommended)
+Create a temporary file named `setup_admin.php` in the root directory with the following content:
+
+```php
+prepare("SELECT id FROM user_groups WHERE name = 'Administrator' LIMIT 1");
+$stmt->execute();
+$group_id = $stmt->fetchColumn();
+
+if (!$group_id) {
+ $pdo->exec("INSERT INTO user_groups (name, permissions) VALUES ('Administrator', 'all')");
+ $group_id = $pdo->lastInsertId();
+}
+
+// Create the user
+try {
+ $stmt = $pdo->prepare("INSERT INTO users (group_id, username, password, full_name, email, is_active) VALUES (?, ?, ?, ?, ?, 1)");
+ $stmt->execute([$group_id, $username, $password, $full_name, $email]);
+ echo "Super Admin created successfully!
Username: admin
Password: admin123
Please delete this file immediately!";
+} catch (Exception $e) {
+ echo "Error: " . $e->getMessage();
+}
+```
+
+Visit `http://your-domain.com/setup_admin.php` and then **delete the file**.
+
+### Option B: Manual SQL
+If you prefer SQL, run the following (replace the password hash with one generated via `password_hash()` in PHP):
+```sql
+INSERT INTO users (group_id, username, password, full_name, email, is_active)
+VALUES (1, 'admin', 'REPLACE_WITH_HASH', 'Super Admin', 'admin@example.com', 1);
+```
+
+## 4. Final Steps
+
+1. **File Permissions:** Ensure the `assets/images/` directory is writable by the web server for uploading product and ad images.
+2. **Login:** Go to `http://your-domain.com/login.php` and log in with your new credentials.
+3. **Company Settings:** Navigate to **Admin -> Company Settings** to configure your restaurant name, address, and currency.
+
+---
+**Security Note:** Always ensure your `db/config.php` and `.env` files are not accessible from the public web.
diff --git a/admin/includes/header.php b/admin/includes/header.php
index 24cdbb7..b8c3b0f 100644
--- a/admin/includes/header.php
+++ b/admin/includes/header.php
@@ -457,7 +457,7 @@ function can_view($module) {
@@ -488,6 +488,11 @@ function can_view($module) {
Attendance
+
+
+ Staff Ratings
+
+
@@ -578,4 +583,4 @@ function can_view($module) {
-
\ No newline at end of file
+
diff --git a/admin/rating.php b/admin/rating.php
new file mode 100644
index 0000000..bc4f3e7
--- /dev/null
+++ b/admin/rating.php
@@ -0,0 +1,3 @@
+query("
+ SELECT u.id, u.full_name, u.username, u.profile_pic,
+ AVG(r.rating) as avg_rating, COUNT(r.id) as total_ratings
+ FROM users u
+ JOIN staff_ratings r ON u.id = r.user_id
+ GROUP BY u.id
+ ORDER BY avg_rating DESC
+");
+$summaries = $summaryStmt->fetchAll(PDO::FETCH_ASSOC);
+
+// Fetch Service summary stats
+$serviceSummaryStmt = $pdo->query("
+ SELECT AVG(rating) as avg_rating, COUNT(id) as total_ratings FROM service_ratings
+");
+$serviceSummary = $serviceSummaryStmt->fetch(PDO::FETCH_ASSOC);
+
+if ($tab === 'service') {
+ $query = "SELECT * FROM service_ratings ORDER BY created_at DESC";
+} else {
+ $query = "
+ SELECT r.*, u.full_name, u.username, u.profile_pic
+ FROM staff_ratings r
+ JOIN users u ON r.user_id = u.id
+ ORDER BY r.created_at DESC
+ ";
+}
+
+$pagination = paginate_query($pdo, $query);
+$ratings = $pagination['data'];
+?>
+
+
+
+
+
+
+
+
+
+
+
No staff members have been rated yet.
+
+
+
+
+
+
+
+
+
 ?>)
+
+
+
+
+
+
+ = htmlspecialchars($summary['full_name'] ?: $summary['username']) ?>
+
+
+ ' : '';
+ }
+ ?>
+ (= number_format($summary['avg_rating'], 1) ?>)
+
+
= $summary['total_ratings'] ?> total ratings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Overall Service
+
+ 0): ?>
+ = number_format($serviceSummary['avg_rating'], 1) ?> / 5.0
+
+ N/A
+
+
+
+ Based on = $serviceSummary['total_ratings'] ?> customer reviews
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Date |
+ Staff Member |
+ Rating |
+ Comment |
+
+
+
+
+
+ | No ratings found yet. |
+
+
+
+
+ |
+ = date('M d, Y H:i', strtotime($rating['created_at'])) ?>
+ |
+
+
+
+
+  ?>)
+
+ = htmlspecialchars($rating['full_name'] ?: $rating['username']) ?>
+
+ |
+
+
+
+ ' : '';
+ }
+ ?>
+
+ |
+
+ = htmlspecialchars($rating['comment'] ?: '-') ?>
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Show this QR code to the customer to rate our staff and service.
+
+
![Rating QR Code]()
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/user_edit.php b/admin/user_edit.php
index ebffd8b..b34961a 100644
--- a/admin/user_edit.php
+++ b/admin/user_edit.php
@@ -26,6 +26,7 @@ if ($id) {
'group_id' => '',
'employee_id' => '',
'is_active' => 1,
+ 'is_ratable' => 0,
'profile_pic' => '',
'created_at' => date('Y-m-d H:i:s')
];
@@ -40,6 +41,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$group_id = $_POST['group_id'];
$employee_id = $_POST['employee_id'] ?? null;
$is_active = isset($_POST['is_active']) ? 1 : 0;
+ $is_ratable = isset($_POST['is_ratable']) ? 1 : 0;
$assigned_outlets = $_POST['outlets'] ?? [];
$password = $_POST['password'] ?? '';
@@ -60,8 +62,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if ($id) {
// Update
- $sql = "UPDATE users SET full_name = ?, username = ?, email = ?, group_id = ?, is_active = ?, employee_id = ? WHERE id = ?";
- $params = [$full_name, $username, $email, $group_id, $is_active, $employee_id, $id];
+ $sql = "UPDATE users SET full_name = ?, username = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, employee_id = ? WHERE id = ?";
+ $params = [$full_name, $username, $email, $group_id, $is_active, $is_ratable, $employee_id, $id];
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
@@ -73,8 +75,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} else {
// Insert
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
- $sql = "INSERT INTO users (full_name, username, email, group_id, is_active, employee_id, password) VALUES (?, ?, ?, ?, ?, ?, ?)";
- $params = [$full_name, $username, $email, $group_id, $is_active, $employee_id, $hashed_password];
+ $sql = "INSERT INTO users (full_name, username, email, group_id, is_active, is_ratable, employee_id, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+ $params = [$full_name, $username, $email, $group_id, $is_active, $is_ratable, $employee_id, $hashed_password];
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$user_id = $pdo->lastInsertId();
@@ -237,10 +239,19 @@ include 'includes/header.php';
Assign one or more outlets to this user.
-