0) { $redirect = 'products.php?edit=' . $productId; } } elseif ($action === 'adjust_stock') { $productId = (int) ($_POST['product_id'] ?? 0); $result = adjust_product_stock( $productId, (string) ($_POST['direction'] ?? ''), (float) ($_POST['qty'] ?? 0), (string) ($_POST['reason'] ?? ''), (string) ($_POST['notes'] ?? '') ); if (!$result['success'] && $productId > 0) { $redirect = 'products.php?adjust=' . $productId; } } else { $result = ['success' => false, 'message' => 'الإجراء المطلوب غير معروف.']; } flash($result['success'] ? 'success' : 'danger', $result['message']); header('Location: ' . $redirect); exit; } $editId = (int) ($_GET['edit'] ?? 0); $adjustId = (int) ($_GET['adjust'] ?? 0); $editingProduct = $editId > 0 ? fetch_product_by_id($editId) : null; $products = fetch_products(); $productOptions = fetch_product_options(); $movements = fetch_inventory_movements(12); $finished = 0; $raw = 0; $low = 0; $totalStock = 0.0; foreach ($products as $product) { $qty = (float) $product['stock_qty']; $totalStock += $qty; if ($product['category'] === 'finished') { $finished++; } else { $raw++; } if ($qty <= 40) { $low++; } } $productForm = [ 'sku' => $editingProduct['sku'] ?? '', 'name' => $editingProduct['name'] ?? '', 'category' => $editingProduct['category'] ?? 'finished', 'unit' => $editingProduct['unit'] ?? '', 'stock_qty' => '', 'cost_price' => isset($editingProduct['cost_price']) ? format_qty((float) $editingProduct['cost_price']) : '', 'sale_price' => isset($editingProduct['sale_price']) ? format_qty((float) $editingProduct['sale_price']) : '', ]; function movement_type_label(string $type): array { return match ($type) { 'opening' => ['label' => 'رصيد افتتاحي', 'class' => 'neutral'], 'sale' => ['label' => 'بيع', 'class' => 'warning'], 'adjustment_in' => ['label' => 'إضافة يدوية', 'class' => 'success'], 'adjustment_out' => ['label' => 'خصم يدوي', 'class' => 'pending'], default => ['label' => $type, 'class' => 'neutral'], }; } render_header('الأصناف والمخزون', 'products'); ?>
Products & Inventory

إدارة الأصناف وضبط المخزون

أصبحت الشاشة الآن تشغيلية: إضافة صنف جديد، تعديل بياناته، وضبط المخزون يدويًا مع سجل حركات واضح. كما أن أوامر البيع تسجل الآن حركة خصم تلقائية داخل نفس السجل.

إجمالي المخزون: منتجات نهائية: خامات: منخفضة:

إلغاء التعديل يمكنك إنشاء خامة أو منتج نهائي مع رصيد افتتاحي
— غيّره من بطاقة ضبط المخزون
التسعير الخاص للعملاء يبقى في شاشة العملاء، بينما هذه البطاقة تدير Master data للصنف نفسه.
Stock adjustment

ضبط المخزون يدويًا

Audit trail
كل تعديل يسجل قبل/بعد في جدول الحركات، لذلك ستتمكن لاحقًا من ربطه بالمشتريات والتصنيع بسهولة.
Product master

كل الأصناف

تعديل البيانات الأساسية من هنا، وضبط الكميات من البطاقة الجانبية
SKU الصنف الفئة المتاح تكلفة بيع افتراضي الحالة
0 ? format_money((float) $product['sale_price']) : '—') ?> منخفض مستقر
Inventory journal

آخر حركات المخزون

يشمل الرصيد الافتتاحي، التعديلات اليدوية، وخصومات البيع الجديدة
الوقت الصنف النوع التغيير قبل ← بعد مرجع / ملاحظات
لا توجد حركات حتى الآن
أضف صنفًا برصيد افتتاحي أو نفّذ ضبط مخزون أو أمر بيع لتظهر هنا أول حركة.
= 0 ? '+' : '') . format_qty($delta)) ?>