(int)$customer['id'], 'customer_name' => $customer['title'], 'branch' => $branch, 'product_id' => (int)$product['id'], 'product_name' => $product['title'], 'sku' => $productPayload['sku'] ?? $product['code'], 'unit' => $productPayload['unit'] ?? 'وحدة', 'qty' => $qty, 'unit_price' => $unitPrice, 'subtotal' => $subtotal, 'vat' => $vat, 'grand_total' => $grand, 'notes' => $notes, 'document_type' => $documentType, 'document_label' => sales_document_label($documentType), 'created_date' => date('Y-m-d H:i'), 'created_by' => current_user()['username'] ?? 'system', 'source_document_id' => (int)($source['id'] ?? 0), 'source_document_code' => $source['code'] ?? null, 'source_document_type' => $source['record_type'] ?? null, 'source_document_label' => $source ? sales_document_label((string)$source['record_type']) : null, 'inventory_effect' => $documentType === 'sales_order' ? 'deducted' : 'none', ]; } $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $action = (string)($_POST['form_action'] ?? 'create_document'); if ($action === 'create_document') { $documentType = (string)($_POST['document_type'] ?? 'sales_order'); $customerId = (int)($_POST['customer_id'] ?? 0); $branch = trim((string)($_POST['branch'] ?? '')); $productId = (int)($_POST['product_id'] ?? 0); $qty = (float)($_POST['qty'] ?? 0); $notes = trim((string)($_POST['notes'] ?? '')); if (!in_array($documentType, ['sales_quote', 'sales_order'], true)) { $errors[] = 'نوع المستند غير صحيح.'; } $customer = fetch_record('customer', $customerId); $product = fetch_record('product', $productId); validate_sales_input($customer, $product, $branch, $qty, $errors); if (!$errors && $customer && $product) { db()->beginTransaction(); try { $payload = build_sales_payload($customer, $product, $branch, $qty, $notes, $documentType); $status = $documentType === 'sales_quote' ? 'draft' : 'confirmed'; $documentId = create_record( $documentType, sales_document_label($documentType) . ' ' . $customer['title'], next_code(sales_document_prefix($documentType), $documentType), $payload, $status ); if ($documentType === 'sales_order') { $document = fetch_sales_document_by_id($documentId); if ($document) { $stock = adjust_product_stock($product, -$qty, 'sales_confirm', $document['code'], 'sales_order', $documentId, 'بيع للعميل ' . $customer['title']); $payload = $document['payload_data']; $payload['stock_after'] = $stock['after']; $payload['inventory_effect'] = 'deducted'; update_record_payload($documentId, $payload, 'confirmed'); } } db()->commit(); set_flash('success', $documentType === 'sales_quote' ? 'تم إنشاء عرض السعر بنجاح.' : 'تم إنشاء أمر البيع وتحديث المخزون بنجاح.'); redirect('sales_orders.php?id=' . $documentId); } catch (Throwable $e) { db()->rollBack(); $errors[] = $e instanceof RuntimeException ? 'المخزون غير كافٍ لتأكيد أمر البيع.' : 'تعذر حفظ المستند، حاول مرة أخرى.'; } } } if ($action === 'convert_document') { $sourceId = (int)($_POST['source_id'] ?? 0); $targetType = (string)($_POST['target_type'] ?? ''); $source = fetch_sales_document_by_id($sourceId); if (!$source) { $errors[] = 'المستند المصدر غير موجود.'; } elseif (!in_array($targetType, sales_document_conversion_targets((string)$source['record_type']), true)) { $errors[] = 'التحويل المطلوب غير مسموح لهذه المرحلة.'; } elseif (sales_document_child_exists($sourceId, $targetType)) { $errors[] = 'تم إنشاء هذا المستند مسبقًا من نفس المصدر.'; } if (!$errors && $source) { $payload = $source['payload_data']; $customer = fetch_record('customer', (int)($payload['customer_id'] ?? 0)); $product = fetch_record('product', (int)($payload['product_id'] ?? 0)); $branch = (string)($payload['branch'] ?? ''); $qty = (float)($payload['qty'] ?? 0); $notes = trim((string)($payload['notes'] ?? '')); validate_sales_input($customer, $product, $branch, $qty, $errors); if (!$errors && $customer && $product) { db()->beginTransaction(); try { $newPayload = build_sales_payload($customer, $product, $branch, $qty, $notes, $targetType, $source); if ($targetType === 'delivery_note') { $newPayload['delivered_at'] = date('Y-m-d H:i'); } if ($targetType === 'sales_invoice') { $newPayload['invoiced_at'] = date('Y-m-d H:i'); $newPayload['payment_status'] = 'unpaid'; } $newId = create_record( $targetType, sales_document_label($targetType) . ' ' . $customer['title'], next_code(sales_document_prefix($targetType), $targetType), $newPayload, 'confirmed' ); if ($targetType === 'sales_order') { $document = fetch_sales_document_by_id($newId); if ($document) { $stock = adjust_product_stock($product, -$qty, 'sales_convert', $document['code'], 'sales_order', $newId, 'تحويل من عرض سعر إلى أمر بيع للعميل ' . $customer['title']); $newPayload = $document['payload_data']; $newPayload['stock_after'] = $stock['after']; $newPayload['inventory_effect'] = 'deducted'; update_record_payload($newId, $newPayload, 'confirmed'); } } db()->commit(); set_flash('success', 'تم إنشاء ' . sales_document_label($targetType) . ' بنجاح.'); redirect('sales_orders.php?id=' . $newId); } catch (Throwable $e) { db()->rollBack(); $errors[] = $e instanceof RuntimeException ? 'المخزون غير كافٍ لإتمام التحويل.' : 'تعذر تنفيذ التحويل، حاول مرة أخرى.'; } } } } } $customers = customer_dataset(); $products = product_dataset(); $documents = fetch_sales_documents(); $detail = isset($_GET['id']) ? fetch_sales_document_by_id((int)$_GET['id']) : null; $detailChildren = $detail ? sales_document_children((int)$detail['id']) : []; $summaryCounts = []; foreach (sales_document_record_types() as $type) { $summaryCounts[$type] = record_count($type); } render_header('المبيعات والوثائق', 'إدارة عروض الأسعار وأوامر البيع وأوامر التسليم والفواتير وربطها في مسار واحد قابل للطباعة.', 'orders'); ?>
ابدأ بعرض سعر أو أنشئ أمر بيع مباشر. عند تأكيد أمر البيع يتم خصم المخزون تلقائيًا.
المسار الآن يدعم: عرض سعر → أمر بيع → أمر تسليم / فاتورة.
| الرقم | النوع | العميل | الصنف | الإجمالي | المصدر | الطباعة |
|---|---|---|---|---|---|---|
| = e($document['code']) ?> = e(order_status_label((string)$document['status'])) ?> |
= e(sales_document_label((string)$document['record_type'])) ?> | = e($payload['customer_name'] ?? '') ?> = e($payload['branch'] ?? '') ?> |
= e($payload['product_name'] ?? '') ?> = e((string)($payload['qty'] ?? 0)) ?> = e($payload['unit'] ?? '') ?> |
= e(format_money((float)($payload['grand_total'] ?? 0))) ?> | = e($payload['source_document_code'] ?? '—') ?> | طباعة |