diff --git a/api/settings.php b/api/settings.php new file mode 100644 index 0000000..3fff4c0 --- /dev/null +++ b/api/settings.php @@ -0,0 +1,56 @@ +prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); + + foreach ($keys as $key) { + if (isset($_POST[$key])) { + $stmt->execute([$key, $_POST[$key]]); + } + } + + // Handle logo upload + $uploadDir = __DIR__ . '/../assets/images/'; + if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0777, true); + } + + if (isset($_FILES['company_logo']) && $_FILES['company_logo']['error'] === UPLOAD_ERR_OK) { + $ext = pathinfo($_FILES['company_logo']['name'], PATHINFO_EXTENSION); + $filename = 'logo_' . time() . '.' . $ext; + if (move_uploaded_file($_FILES['company_logo']['tmp_name'], $uploadDir . $filename)) { + $stmt->execute(['company_logo', 'assets/images/' . $filename]); + } + } + + // Handle favicon upload + if (isset($_FILES['company_favicon']) && $_FILES['company_favicon']['error'] === UPLOAD_ERR_OK) { + $ext = pathinfo($_FILES['company_favicon']['name'], PATHINFO_EXTENSION); + $filename = 'favicon_' . time() . '.' . $ext; + if (move_uploaded_file($_FILES['company_favicon']['tmp_name'], $uploadDir . $filename)) { + $stmt->execute(['company_favicon', 'assets/images/' . $filename]); + } + } + + set_flash('success', tr('تم حفظ الإعدادات بنجاح.', 'Settings saved successfully.')); + + // Redirect back to referring page + $referer = $_SERVER['HTTP_REFERER'] ?? '../index.php'; + header('Location: ' . $referer); + exit; +} diff --git a/cookies.txt b/cookies.txt index 40643ba..24dbe0b 100644 --- a/cookies.txt +++ b/cookies.txt @@ -2,4 +2,4 @@ # 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 +127.0.0.1 FALSE / FALSE 0 PHPSESSID 6qft39lctsp4e64kmen99qtqfo diff --git a/edit_sale.php b/edit_sale.php new file mode 100644 index 0000000..4e6c672 --- /dev/null +++ b/edit_sale.php @@ -0,0 +1,691 @@ + 0) { + $stmt = db()->prepare('SELECT * FROM sales_orders WHERE id = :id'); + $stmt->execute([':id' => $editSaleId]); + $editSale = $stmt->fetch(); +} +if (!$editSale) { + die(tr('الفاتورة غير موجودة.', 'Invoice not found.')); +} +if ($user['role'] !== 'owner' && $editSale['branch_code'] !== $user['branch_code']) { + die(tr('غير مصرح لك.', 'Unauthorized.')); +} + +$pageTitle = tr('تعديل فاتورة', 'Edit Invoice') . ' #' . h($editSale['receipt_no']); +$activeNav = 'sales'; +$error = ''; +$catalog = catalog(); +$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']]; + +try { + $customers = db()->query('SELECT id, name, phone FROM customers ORDER BY name ASC')->fetchAll(); +} catch (Throwable $e) { + $customers = []; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $branchCode = trim((string) ($_POST['branch_code'] ?? '')); + $customerName = trim((string) ($_POST['customer_name'] ?? '')); + $paymentMethod = trim((string) ($_POST['payment_method'] ?? 'cash')); + $saleStatus = trim((string) ($_POST['sale_status'] ?? 'completed')); + $notes = trim((string) ($_POST['notes'] ?? '')); + $cartJson = (string) ($_POST['cart_json'] ?? '[]'); + $items = json_decode($cartJson, true); + + if (!in_array($branchCode, $allowedBranches, true)) { + $error = tr('اختر فرعاً صالحاً لهذه الصلاحية.', 'Choose a valid branch for this role.'); + } elseif (!in_array($paymentMethod, ['cash', 'card', 'transfer'], true)) { + $error = tr('اختر طريقة دفع صحيحة.', 'Choose a valid payment method.'); + } elseif (!is_array($items) || $items === []) { + $error = tr('أضف صنفاً واحداً على الأقل إلى الفاتورة.', 'Add at least one item to the invoice.'); + } else { + $normalized = []; + $subtotal = 0.0; + $itemCount = 0; + foreach ($items as $item) { + $sku = (string) ($item['sku'] ?? ''); + $qty = (int) ($item['qty'] ?? 0); + if (!isset($catalog[$sku]) || $qty < 1) { + continue; + } + $product = $catalog[$sku]; + $price = (float) $product['price']; + $lineTotal = $price * $qty; + $normalized[] = [ + 'sku' => $sku, + 'name_ar' => $product['name_ar'], + 'name_en' => $product['name_en'], + 'qty' => $qty, + 'price' => $price, + 'line_total' => $lineTotal, + ]; + $subtotal += $lineTotal; + $itemCount += $qty; + } + + if ($normalized === []) { + $error = tr('الفاتورة غير صالحة بعد التحقق من الأصناف.', 'The invoice is invalid after product validation.'); + } else { + $cashierName = current_lang() === 'ar' ? $user['name_ar'] : $user['name_en']; + $stmt = db()->prepare('UPDATE sales_orders SET + branch_code = :branch_code, + customer_name = :customer_name, + payment_method = :payment_method, + items_json = :items_json, + item_count = :item_count, + subtotal = :subtotal, + total_amount = :total_amount, + status = :status, + notes = :notes + WHERE id = :id'); + $stmt->execute([ + ':branch_code' => $branchCode, + ':customer_name' => $customerName !== '' ? $customerName : null, + ':payment_method' => $paymentMethod, + ':items_json' => json_encode($normalized, JSON_UNESCAPED_UNICODE), + ':item_count' => $itemCount, + ':subtotal' => $subtotal, + ':total_amount' => $subtotal, + ':status' => $saleStatus, + ':notes' => $notes !== '' ? $notes : null, + ':id' => $editSaleId, + ]); + + set_flash('success', tr('تم تحديث الفاتورة بنجاح.', 'Invoice updated successfully.')); + redirect_to('sale.php', ['id' => $editSaleId]); + } + } +} + +require __DIR__ . '/includes/header.php'; +?> + + + +
+
+

+ + + +
+ + +
+ + +
+ + +
+
+ +
+
+
+ +
+
+
+ + +
+ + +
+
+ + +
+ + + + + + + + + + + + + + + +
+ + +
+
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ + +
+
+ +
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+ + 0.000 +
+
+ + +
+
+ + 0.000 +
+
+ + +
+
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/includes/app.php b/includes/app.php index 58d9da0..1bc51e7 100644 --- a/includes/app.php +++ b/includes/app.php @@ -9,9 +9,35 @@ require_once __DIR__ . '/../db/config.php'; date_default_timezone_set('UTC'); +function get_settings(): array +{ + static $settings = null; + if ($settings === null) { + $pdo = db(); + try { + $stmt = $pdo->query("SELECT setting_key, setting_value FROM settings"); + $settings = []; + while ($row = $stmt->fetch()) { + $settings[$row['setting_key']] = $row['setting_value']; + } + } catch (Exception $e) { + $settings = []; + } + } + return $settings; +} + +function get_setting(string $key, $default = '') +{ + $settings = get_settings(); + return $settings[$key] ?? $default; +} + + + function app_name(): string { - return 'حلوى الريامي | Al Riyami Sweets'; + return get_setting('company_name_ar', 'حلوى الريامي') . ' | ' . get_setting('company_name_en', 'Al Riyami Sweets'); } function current_lang(): string @@ -195,7 +221,7 @@ function catalog(): array { try { $db = db(); - $stmt = $db->query("SELECT * FROM items"); + $stmt = $db->query("SELECT items.*, units.name_ar as u_name_ar, units.name_en as u_name_en FROM items LEFT JOIN units ON items.unit_id = units.id"); $items = $stmt->fetchAll(PDO::FETCH_ASSOC); $catalog = []; foreach ($items as $item) { @@ -209,8 +235,9 @@ function catalog(): array "category_id" => $item["category_id"], "supplier_id" => $item["supplier_id"], "image_url" => $item["image_url"], - "unit_ar" => "قطعة", - "unit_en" => "pcs" + "unit_id" => $item["unit_id"], + "unit_ar" => $item["u_name_ar"] ?? "قطعة", + "unit_en" => $item["u_name_en"] ?? "pcs" ]; } return $catalog; diff --git a/includes/footer.php b/includes/footer.php index abaaa98..69a9e57 100644 --- a/includes/footer.php +++ b/includes/footer.php @@ -9,6 +9,7 @@ $isPublic = !isset($user) || !$user; + @@ -47,8 +52,13 @@ $isPublic = !isset($user) || !$user;
@@ -244,7 +248,7 @@ $registerNo = 'REG-01';
- +
diff --git a/sale.php b/sale.php index 2d4b1c1..26c0780 100644 --- a/sale.php +++ b/sale.php @@ -15,11 +15,11 @@ if ($id > 0) { } // Company Info for Invoice -$companyName = tr('متجر فلات لوجيك', 'Flatlogic Store'); -$companyAddress = tr('شارع الملك فهد، الرياض، المملكة العربية السعودية', 'King Fahd Road, Riyadh, KSA'); -$companyVat = '300123456789012'; +$companyName = current_lang() === 'ar' ? get_setting('company_name_ar', 'حلوى الريامي') : get_setting('company_name_en', 'Al Riyami Sweets'); +$companyAddress = get_setting('company_address', ''); +$companyVat = get_setting('company_vat_number', '300123456789012'); $companyEmail = 'info@flatlogic.com'; -$companyPhone = '920000000'; +$companyPhone = ''; require __DIR__ . '/includes/header.php'; ?> @@ -319,9 +319,14 @@ require __DIR__ . '/includes/header.php'; - +
+ + + + +
@@ -419,7 +424,7 @@ require __DIR__ . '/includes/header.php'; - + diff --git a/sales.php b/sales.php index dcbf98a..2a0c8cd 100644 --- a/sales.php +++ b/sales.php @@ -165,9 +165,9 @@ require __DIR__ . '/includes/header.php'; - + diff --git a/stock.php b/stock.php index da94736..0ed808f 100644 --- a/stock.php +++ b/stock.php @@ -16,9 +16,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $name = $_POST['name'] ?? ''; $price = (float)($_POST['price'] ?? 0); $base_stock = (int)($_POST['base_stock'] ?? 0); - $vat = (float)($_POST['vat'] ?? 5); + $vat = (float)($_POST['vat'] ?? get_setting('vat_percentage', 5)); $category_id = !empty($_POST['category_id']) ? (int)$_POST['category_id'] : null; $supplier_id = !empty($_POST['supplier_id']) ? (int)$_POST['supplier_id'] : null; + $unit_id = !empty($_POST['unit_id']) ? (int)$_POST['unit_id'] : null; if (!$sku || !$name) { echo json_encode(['success' => false, 'error' => 'Missing SKU or Name']); @@ -49,8 +50,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { exit; } - $sql = "UPDATE items SET sku=?, name=?, price=?, base_stock=?, vat=?, category_id=?, supplier_id=? " . ($image_url ? ", image_url=?" : "") . " WHERE sku=?"; - $params = [$sku, $name, $price, $base_stock, $vat, $category_id, $supplier_id]; + $sql = "UPDATE items SET sku=?, name=?, price=?, base_stock=?, vat=?, category_id=?, supplier_id=?, unit_id=? " . ($image_url ? ", image_url=?" : "") . " WHERE sku=?"; + $params = [$sku, $name, $price, $base_stock, $vat, $category_id, $supplier_id, $unit_id]; if ($image_url) { $params[] = $image_url; } @@ -62,8 +63,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { echo json_encode(['success' => false, 'error' => 'SKU already exists']); exit; } - $stmt = $pdo->prepare("INSERT INTO items (sku, name, price, base_stock, vat, category_id, supplier_id, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$sku, $name, $price, $base_stock, $vat, $category_id, $supplier_id, $image_url]); + $stmt = $pdo->prepare("INSERT INTO items (sku, name, price, base_stock, vat, category_id, supplier_id, unit_id, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$sku, $name, $price, $base_stock, $vat, $category_id, $supplier_id, $unit_id, $image_url]); } echo json_encode(['success' => true]); @@ -105,6 +106,7 @@ try { $pdo = db(); $categories = $pdo->query('SELECT id, name_ar, name_en FROM categories ORDER BY name_ar ASC')->fetchAll(); $suppliers = $pdo->query('SELECT id, name FROM suppliers ORDER BY name ASC')->fetchAll(); + $units = $pdo->query('SELECT id, name_ar, name_en FROM units ORDER BY name_ar ASC')->fetchAll(); } catch (Throwable $e) { // Ignore if not present } @@ -235,7 +237,7 @@ require __DIR__ . '/includes/header.php'; - + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
ID
+ + +
+
+ + 1): ?> + + +
+ + + + + + + + + + + + +