diff --git a/includes/lang.php b/includes/lang.php index f77face..00e3f43 100644 --- a/includes/lang.php +++ b/includes/lang.php @@ -222,7 +222,7 @@ $translations = [ 'customer_has_orders' => 'Cannot delete customer because they have existing orders', 'loyalty_settings' => 'Loyalty System Settings', 'loyalty_enabled' => 'Loyalty System Enabled', - 'loyalty_points_per_currency' => 'Points earned per 1 unit spent', + 'loyalty_points_per_currency' => 'Points earned per 1 Omani Rial spent', 'loyalty_currency_per_point' => 'Value of 1 point (discount amount)', 'loyalty_points' => 'Loyalty Points', 'points_adjusted' => 'Points adjusted successfully', @@ -348,7 +348,7 @@ $translations = [ 'order' => 'الطلب', 'customer' => 'العميل', 'qty' => 'الكمية', - 'close' => 'إغلاق', + 'close' => 'إإغلاق', 'payments' => 'المدفوعات', 'no_payments' => 'لا يوجد مدفوعات', 'update_status' => 'تحديث الحالة', @@ -444,7 +444,7 @@ $translations = [ 'customer_has_orders' => 'لا يمكن حذف العميل لوجود طلبات مرتبطة به', 'loyalty_settings' => 'إعدادات نظام الولاء', 'loyalty_enabled' => 'تفعيل نظام الولاء', - 'loyalty_points_per_currency' => 'النقاط المكتسبة لكل وحدة عملة يتم إنفاقها', + 'loyalty_points_per_currency' => 'النقاط المكتسبة لكل ريال عماني يتم إنفاقه', 'loyalty_currency_per_point' => 'قيمة النقطة الواحدة (مبلغ الخصم)', 'loyalty_points' => 'نقاط الولاء', 'points_adjusted' => 'تم تعديل النقاط بنجاح', @@ -491,4 +491,4 @@ function branch_url($new_branch_id) { $params = $_GET; $params['switch_branch'] = $new_branch_id; return '?' . http_build_query($params); -} +} \ No newline at end of file diff --git a/install.php b/install.php new file mode 100644 index 0000000..e7131bf --- /dev/null +++ b/install.php @@ -0,0 +1,284 @@ +exec($query); + } catch (PDOException $e) { + // Ignore errors if table already exists during re-run + if (strpos($e->getMessage(), 'already exists') === false) { + throw $e; + } + } + } + } + return true; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if ($step === 2) { + $host = $_POST['db_host'] ?? '127.0.0.1'; + $user = $_POST['db_user'] ?? ''; + $pass = $_POST['db_pass'] ?? ''; + $name = $_POST['db_name'] ?? ''; + + try { + $pdo = new PDO("mysql:host=$host;charset=utf8mb4", $user, $pass); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $pdo->exec("CREATE DATABASE IF NOT EXISTS `$name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); + $pdo->exec("USE `$name` text"); + + // Read existing helpers from current config if it exists + $helpers = ''; + if (file_exists(__DIR__ . '/db/config.php')) { + $currentConfig = file_get_contents(__DIR__ . '/db/config.php'); + // Extract functions after the db() function or constants + if (preg_match('/function check_permission.*$/s', $currentConfig, $matches)) { + $helpers = $matches[0]; + } + } + + // If helpers weren't found, use a set of default ones + if (empty($helpers)) { + $helpers = " +function check_permission(\$page = null, \$user_id = null) { + if (!\$user_id) \$user_id = \$_SESSION['user_id'] ?? null; + if (!\$page) \$page = basename(\$_SERVER['PHP_SELF']); + if (!\$user_id) return ['view' => 0, 'add' => 0, 'edit' => 0, 'delete' => 0]; + static \$permissions_cache = []; + \$cache_key = \$user_id . '_' . \$page; + if (isset(\$permissions_cache[\$cache_key])) return \$permissions_cache[\$cache_key]; + \$stmt = db()->prepare(\"SELECT can_view as view, can_add as `add`, can_edit as edit, can_delete as `delete` FROM user_permissions WHERE user_id = ? AND page = ?\"); + \$stmt->execute([\$user_id, \$page]); + \$perms = \$stmt->fetch(); + if (!\$perms) return ['view' => 0, 'add' => 0, 'edit' => 0, 'delete' => 0]; + \$result = ['view' => (int)\$perms['view'], 'add' => (int)\$perms['add'], 'edit' => (int)\$perms['edit'], 'delete' => (int)\$perms['delete']]; + \$permissions_cache[\$cache_key] = \$result; + return \$result; +} +function has_permission(\$action, \$page = null, \$user_id = null) { + \$perms = check_permission(\$page, \$user_id); + return !empty(\$perms[\$action]); +}"; + } + + $configContent = " PDO::ERRMODE_EXCEPTION,\n" + . " PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n" + . " PDO::ATTR_EMULATE_PREPARES => false,\n" + . " ]);\n" + . " }\n" + . " return \$pdo;\n" + . "}\n\n" + . trim($helpers) . "\n"; + + if (!is_dir(__DIR__ . '/db')) mkdir(__DIR__ . '/db', 0755, true); + file_put_contents(__DIR__ . '/db/config.php', $configContent); + + // Run initial schema + runSqlFile($pdo, __DIR__ . '/db/migrations/01_initial_schema.sql'); + + $_SESSION['db_configured'] = true; + header("Location: install.php?step=3"); + exit; + } catch (PDOException $e) { + $error = "Connection failed: " . $e->getMessage(); + } + } elseif ($step === 3) { + require_once __DIR__ . '/db/config.php'; + $user = $_POST['admin_user'] ?? ''; + $pass = $_POST['admin_pass'] ?? ''; + $email = $_POST['admin_email'] ?? ''; + + if (empty($user) || empty($pass)) { + $error = "Username and password are required."; + } else { + try { + $hash = password_hash($pass, PASSWORD_DEFAULT); + $db = db(); + + // Clear existing users + $db->exec("SET FOREIGN_KEY_CHECKS = 0;"); + $db->exec("TRUNCATE users;"); + $db->exec("SET FOREIGN_KEY_CHECKS = 1;"); + + // Ensure company and branch exist (schema usually seeds them, but we ensure) + $db->exec("INSERT IGNORE INTO companies (id, name_en, name_ar) VALUES (1, 'Laundry Brand', 'علامة غسيل')"); + $db->exec("INSERT IGNORE INTO branches (id, company_id, name_en, name_ar) VALUES (1, 1, 'Main Branch', 'الفرع الرئيسي')"); + + $stmt = $db->prepare("INSERT INTO users (branch_id, company_id, username, password_hash, full_name_en, role, email) VALUES (1, 1, ?, ?, 'System Administrator', 'super_admin', ?)"); + $stmt->execute([$user, $hash, $email]); + + file_put_contents($lockFile, date('Y-m-d H:i:s')); + header("Location: install.php?step=4"); + exit; + } catch (Exception $e) { + $error = "Admin setup failed: " . $e->getMessage(); + } + } + } +} + +// Environment Checks +$checks = [ + 'PHP Version >= 8.0' => version_compare(PHP_VERSION, '8.0.0', '>='), + 'PDO Extension' => extension_loaded('pdo_mysql'), + 'Config Writable' => is_writable(__DIR__ . '/db/config.php') || is_writable(__DIR__), + 'Assets Writable' => (is_writable(__DIR__ . '/assets/images') || (is_dir(__DIR__ . '/assets/images') && is_writable(__DIR__ . '/assets/images'))) +]; +$envReady = !in_array(false, $checks, true); + +?> + + + + + + Fresh Installation + + + + + +
+
+

Setup Wizard

+

Step-by-step application installation

+
+ +
+
1
+
2
+
3
+
4
+
+ + +
+ + + +
Checking Environment
+
+ $pass): ?> +
+ + + Passed + + Failed + +
+ +
+
+ Continue to Database +
+ + +
Database Configuration
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ +
+
+ + +
Administrator Account
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+
+ + + + +
+
+
Installation Complete!
+

The application has been configured and the administrator account is ready.

+
+ Login to System +

Warning: Delete install.php for production security.

+
+
+ +
+ + + \ No newline at end of file