diff --git a/assets/css/custom.css b/assets/css/custom.css index 4688093..1334fb9 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -136,4 +136,19 @@ body.auth-body { /* Sidebar Sub-menu */ [data-bs-toggle="collapse"][aria-expanded="true"] .toggle-icon { transform: rotate(180deg); -} \ No newline at end of file +} +/* Fix for btn-close in modal-header */ +.modal-header { + position: relative; +} +.modal-header .btn-close { + margin: 0; + position: absolute; + top: 1rem; +} +[dir="rtl"] .modal-header .btn-close { + left: 1rem; +} +[dir="ltr"] .modal-header .btn-close { + right: 1rem; +} diff --git a/assets/images/items/18311171.jpg b/assets/images/items/18311171.jpg new file mode 100644 index 0000000..0b0206d Binary files /dev/null and b/assets/images/items/18311171.jpg differ diff --git a/assets/images/items/18641665.jpg b/assets/images/items/18641665.jpg new file mode 100644 index 0000000..e6deac9 Binary files /dev/null and b/assets/images/items/18641665.jpg differ diff --git a/assets/images/items/2537658.jpg b/assets/images/items/2537658.jpg new file mode 100644 index 0000000..02bcbb7 Binary files /dev/null and b/assets/images/items/2537658.jpg differ diff --git a/assets/images/items/29765806.jpg b/assets/images/items/29765806.jpg new file mode 100644 index 0000000..37e90e9 Binary files /dev/null and b/assets/images/items/29765806.jpg differ diff --git a/assets/images/items/9058886.jpg b/assets/images/items/9058886.jpg new file mode 100644 index 0000000..2ffd222 Binary files /dev/null and b/assets/images/items/9058886.jpg differ diff --git a/cookies.txt b/cookies.txt new file mode 100644 index 0000000..40643ba --- /dev/null +++ b/cookies.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +127.0.0.1 FALSE / FALSE 0 PHPSESSID b0jh7ohno1tnaa8tkh48odf595 diff --git a/db_seed.php b/db_seed.php new file mode 100644 index 0000000..6f99dac --- /dev/null +++ b/db_seed.php @@ -0,0 +1,36 @@ +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"; + diff --git a/includes/app.php b/includes/app.php index e804b31..4d391ed 100644 --- a/includes/app.php +++ b/includes/app.php @@ -193,14 +193,30 @@ function can_access_branch(string $branchCode): bool function catalog(): array { - return [ - 'baklava_box' => ['sku' => 'baklava_box', 'name_ar' => 'بقلاوة مشكلة', 'name_en' => 'Mixed Baklava Box', 'price' => 18.50, 'base_stock' => 72, 'unit_ar' => 'علبة', 'unit_en' => 'box'], - 'date_truffles' => ['sku' => 'date_truffles', 'name_ar' => 'ترافل التمر', 'name_en' => 'Date Truffles', 'price' => 9.25, 'base_stock' => 120, 'unit_ar' => 'علبة', 'unit_en' => 'box'], - 'saffron_maamoul' => ['sku' => 'saffron_maamoul', 'name_ar' => 'معمول الزعفران', 'name_en' => 'Saffron Maamoul', 'price' => 7.80, 'base_stock' => 88, 'unit_ar' => 'صندوق', 'unit_en' => 'pack'], - 'pistachio_bites' => ['sku' => 'pistachio_bites', 'name_ar' => 'لقيمات الفستق', 'name_en' => 'Pistachio Bites', 'price' => 11.40, 'base_stock' => 64, 'unit_ar' => 'علبة', 'unit_en' => 'box'], - 'halwa_classic' => ['sku' => 'halwa_classic', 'name_ar' => 'حلوى عمانية كلاسيك', 'name_en' => 'Classic Omani Halwa', 'price' => 6.20, 'base_stock' => 150, 'unit_ar' => 'عبوة', 'unit_en' => 'jar'], - 'gift_tin' => ['sku' => 'gift_tin', 'name_ar' => 'علبة هدايا فاخرة', 'name_en' => 'Premium Gift Tin', 'price' => 24.00, 'base_stock' => 36, 'unit_ar' => 'علبة', 'unit_en' => 'tin'], - ]; + try { + $db = db(); + $stmt = $db->query("SELECT * FROM items"); + $items = $stmt->fetchAll(PDO::FETCH_ASSOC); + $catalog = []; + foreach ($items as $item) { + $catalog[$item["sku"]] = [ + "sku" => $item["sku"], + "name_ar" => $item["name"], + "name_en" => $item["name"], + "price" => (float)$item["price"], + "base_stock" => (int)$item["base_stock"], + "vat" => (float)$item["vat"], + "category_id" => $item["category_id"], + "supplier_id" => $item["supplier_id"], + "image_url" => $item["image_url"], + "unit_ar" => "قطعة", + "unit_en" => "pcs" + ]; + } + return $catalog; + } catch (Throwable $e) { + return []; + } } function product_label(string $sku): string @@ -210,12 +226,13 @@ function product_label(string $sku): string return $sku; } - return current_lang() === 'ar' ? $item['name_ar'] : $item['name_en']; + return current_lang() === "ar" ? $item["name_ar"] : $item["name_en"]; } + function currency(float $amount): string { - return number_format($amount, 2) . ' ' . tr('ر.ع', 'OMR'); + return number_format($amount, 3) . ' ' . tr('ر.ع', 'OMR'); } function sale_mode_label(string $mode): string @@ -440,7 +457,11 @@ function stock_snapshot(): array 'base_stock' => $base, 'sold' => $used, 'available' => max(0, $base - $used), - 'price' => (float) $item['price'], + 'price' => $item['price'], + 'category_id' => $item['category_id'], + 'supplier_id' => $item['supplier_id'], + 'image_url' => $item['image_url'], + 'vat' => $item['vat'], ]; } diff --git a/includes/pexels.php b/includes/pexels.php new file mode 100644 index 0000000..0c04a85 --- /dev/null +++ b/includes/pexels.php @@ -0,0 +1,25 @@ + 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18'; +} +function pexels_get($url) { + $ch = curl_init(); + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ], + CURLOPT_TIMEOUT => 15, + ]); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true); + return null; +} +function download_to($srcUrl, $destPath) { + $data = file_get_contents($srcUrl); + if ($data === false) return false; + if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true); + return file_put_contents($destPath, $data) !== false; +} diff --git a/patch_app.php b/patch_app.php new file mode 100644 index 0000000..1a7d38b --- /dev/null +++ b/patch_app.php @@ -0,0 +1,17 @@ + max(0, $base - $used), + 'price' => $item['price'] + , + 'available' => max(0, $base - $used), + 'price' => $item['price'], + 'category_id' => $item['category_id'], + 'supplier_id' => $item['supplier_id'], + 'image_url' => $item['image_url'], + 'vat' => $item['vat'] + , + $content +); +file_put_contents('includes/app.php', $content); + diff --git a/patch_modal.php b/patch_modal.php new file mode 100644 index 0000000..fb4cee1 --- /dev/null +++ b/patch_modal.php @@ -0,0 +1,19 @@ +<\?= h\(\$row[\'name\']\) \?><\/td>/', "$1