170 lines
8.0 KiB
PHP
170 lines
8.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/app.php';
|
|
app_bootstrap();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
if (!verify_csrf($_POST['csrf_token'] ?? null)) {
|
|
flash('danger', 'انتهت صلاحية الجلسة. أعد المحاولة.');
|
|
header('Location: sales.php');
|
|
exit;
|
|
}
|
|
|
|
$customerId = (int) ($_POST['customer_id'] ?? 0);
|
|
$productId = (int) ($_POST['product_id'] ?? 0);
|
|
$qty = (float) ($_POST['qty'] ?? 0);
|
|
$notes = trim((string) ($_POST['notes'] ?? ''));
|
|
$result = create_sales_order($customerId, $productId, $qty, $notes);
|
|
flash($result['success'] ? 'success' : 'danger', $result['message']);
|
|
if (!empty($result['success'])) {
|
|
header('Location: order.php?id=' . (int) $result['order_id']);
|
|
exit;
|
|
}
|
|
header('Location: sales.php');
|
|
exit;
|
|
}
|
|
|
|
$catalog = fetch_sales_form_catalog();
|
|
$recentOrders = fetch_recent_orders(10);
|
|
$customerCount = count($catalog);
|
|
$productOptions = 0;
|
|
foreach ($catalog as $entry) {
|
|
$productOptions += count($entry['items']);
|
|
}
|
|
render_header('أوامر البيع', 'sales');
|
|
?>
|
|
<section class="mb-4">
|
|
<div class="d-flex justify-content-between align-items-start gap-3 flex-wrap mb-4">
|
|
<div>
|
|
<span class="section-kicker">Sales workflow</span>
|
|
<h1 class="page-title mb-2">إنشاء أمر بيع مع تسعير خاص وتحديث مخزون</h1>
|
|
<p class="page-lead mb-0">اختر العميل أولاً، وستظهر فقط الأصناف المسموح بها له مع السعر الخاص المخزن في النظام. عند التأكيد يتم حفظ الطلب وخصم المخزون مباشرة.</p>
|
|
</div>
|
|
<div class="d-flex gap-2 flex-wrap">
|
|
<span class="badge text-bg-light border text-dark">عملاء مفعّلون: <?= h((string) $customerCount) ?></span>
|
|
<span class="badge text-bg-light border text-dark">خيارات بيع: <?= h((string) $productOptions) ?></span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="mb-4 mb-lg-5">
|
|
<div class="row g-4 align-items-stretch">
|
|
<div class="col-lg-7">
|
|
<div class="card panel-card h-100">
|
|
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-2">
|
|
<div>
|
|
<span class="section-kicker">Create</span>
|
|
<h2 class="section-title mb-0">أمر بيع جديد</h2>
|
|
</div>
|
|
<span class="text-muted small">الحماية مفعلة: CSRF + prepared statements + output escaping</span>
|
|
</div>
|
|
<form method="post" id="sales-order-form" class="row g-3">
|
|
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="customer_id">العميل</label>
|
|
<select class="form-select" id="customer_id" name="customer_id" required>
|
|
<option value="">اختر العميل</option>
|
|
<?php foreach ($catalog as $customerId => $entry): ?>
|
|
<option value="<?= h((string) $customerId) ?>"><?= h($entry['customer_name']) ?> — <?= h($entry['branch_name']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="product_id">الصنف المسموح</label>
|
|
<select class="form-select" id="product_id" name="product_id" required disabled>
|
|
<option value="">اختر العميل أولاً</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label" for="qty">الكمية</label>
|
|
<input class="form-control" type="number" min="1" step="1" id="qty" name="qty" value="1" required>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<label class="form-label" for="notes">ملاحظات</label>
|
|
<input class="form-control" type="text" id="notes" name="notes" maxlength="255" placeholder="ملاحظات داخلية على الطلب أو التسليم">
|
|
</div>
|
|
<div class="col-12 d-flex justify-content-between align-items-center flex-wrap gap-2 mt-2">
|
|
<div class="text-muted small">سيتم إنشاء أمر بيع مؤكد وحساب الربح المتوقع من تكلفة المنتج الحالية.</div>
|
|
<button class="btn btn-dark" type="submit" id="submit-order-btn">تأكيد أمر البيع</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<div class="card panel-card h-100 summary-card">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div>
|
|
<span class="section-kicker">Live summary</span>
|
|
<h2 class="section-title mb-0">ملخص فوري</h2>
|
|
</div>
|
|
<span class="status-badge neutral">Auto pricing</span>
|
|
</div>
|
|
<div class="summary-grid">
|
|
<div class="summary-row"><span>العميل</span><strong id="summary-customer">—</strong></div>
|
|
<div class="summary-row"><span>الفرع</span><strong id="summary-branch">—</strong></div>
|
|
<div class="summary-row"><span>السعر الخاص</span><strong id="summary-price">—</strong></div>
|
|
<div class="summary-row"><span>المتاح بالمخزون</span><strong id="summary-stock">—</strong></div>
|
|
<div class="summary-row"><span>الربح للوحدة</span><strong id="summary-margin">—</strong></div>
|
|
<div class="summary-row total"><span>قيمة السطر</span><strong id="summary-total">—</strong></div>
|
|
</div>
|
|
<div class="alert alert-light border mt-4 mb-0 small" id="sales-order-hint">
|
|
اختر عميلاً لعرض الأصناف المسموح بها له. إذا كانت الكمية المطلوبة أكبر من المتاح سيظهر تنبيه ويتم تعطيل الإرسال.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="card panel-card">
|
|
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-2">
|
|
<div>
|
|
<span class="section-kicker">Recent orders</span>
|
|
<h2 class="section-title mb-0">قائمة أوامر البيع</h2>
|
|
</div>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table align-middle app-table mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>الرقم</th>
|
|
<th>العميل</th>
|
|
<th>الوقت</th>
|
|
<th>القيمة</th>
|
|
<th>الربح المتوقع</th>
|
|
<th>الإجراء</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!$recentOrders): ?>
|
|
<tr>
|
|
<td colspan="6">
|
|
<div class="empty-state compact">
|
|
<div class="empty-title">ابدأ من هنا</div>
|
|
<div class="empty-copy">أول أمر بيع ستنشئه سيظهر هنا مع تأثيره على المخزون ولوحة التحكم.</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($recentOrders as $order): ?>
|
|
<tr>
|
|
<td class="fw-semibold"><?= h($order['order_number']) ?></td>
|
|
<td>
|
|
<div><?= h($order['customer_name']) ?></div>
|
|
<div class="text-muted small"><?= h($order['branch_name']) ?></div>
|
|
</td>
|
|
<td><?= h(date('Y-m-d H:i', strtotime($order['created_at']))) ?></td>
|
|
<td><?= h(format_money((float) $order['subtotal'])) ?></td>
|
|
<td><?= h(format_money((float) $order['expected_profit'])) ?></td>
|
|
<td><a class="btn btn-sm btn-outline-secondary" href="order.php?id=<?= h((string) $order['id']) ?>">عرض</a></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<script id="catalog-data" type="application/json"><?= h(json_encode($catalog, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) ?></script>
|
|
<?php render_footer(); ?>
|