195 lines
7.8 KiB
PHP
195 lines
7.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/app.php';
|
|
require_permission('products');
|
|
|
|
$errors = [];
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
verify_csrf();
|
|
|
|
$name = trim((string)($_POST['name'] ?? ''));
|
|
$sku = trim((string)($_POST['sku'] ?? ''));
|
|
$unit = trim((string)($_POST['unit'] ?? ''));
|
|
$category = trim((string)($_POST['category'] ?? ''));
|
|
$stockQty = trim((string)($_POST['stock_qty'] ?? ''));
|
|
$reorder = trim((string)($_POST['reorder_level'] ?? ''));
|
|
$salePrice = trim((string)($_POST['sale_price'] ?? ''));
|
|
$notes = trim((string)($_POST['notes'] ?? ''));
|
|
|
|
if ($name === '' || $sku === '' || $unit === '') {
|
|
$errors[] = 'الاسم وSKU والوحدة حقول مطلوبة.';
|
|
}
|
|
if (!is_numeric($stockQty) || !is_numeric($reorder) || !is_numeric($salePrice)) {
|
|
$errors[] = 'أدخل أرقامًا صحيحة للمخزون وحد الطلب والسعر.';
|
|
}
|
|
|
|
if (!$errors) {
|
|
create_record('product', $name, $sku, [
|
|
'sku' => $sku,
|
|
'unit' => $unit,
|
|
'category' => $category,
|
|
'stock_qty' => (float)$stockQty,
|
|
'reorder_level' => (float)$reorder,
|
|
'sale_price' => (float)$salePrice,
|
|
'notes' => $notes,
|
|
]);
|
|
set_flash('success', 'تمت إضافة الصنف بنجاح.');
|
|
redirect('products.php');
|
|
}
|
|
}
|
|
|
|
$products = fetch_records('product');
|
|
$detail = isset($_GET['id']) ? fetch_record('product', (int)$_GET['id']) : null;
|
|
render_header('الأصناف والمخزون', 'إدارة الأصناف الجاهزة للبيع ومتابعة المخزون الحالي وحدود إعادة الطلب.', 'products');
|
|
?>
|
|
<div class="row g-4">
|
|
<div class="col-lg-5">
|
|
<div class="panel-card">
|
|
<div class="section-header compact">
|
|
<div>
|
|
<h1 class="section-title mb-1">إضافة صنف</h1>
|
|
<p class="section-copy">هذا السجل يستخدم لاحقًا في المبيعات والمشتريات والتصنيع.</p>
|
|
</div>
|
|
</div>
|
|
<?php if ($errors): ?>
|
|
<div class="alert alert-danger py-2">
|
|
<?php foreach ($errors as $error): ?>
|
|
<div><?= e($error) ?></div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<form method="post" class="vstack gap-3">
|
|
<input type="hidden" name="csrf_token" value="<?= e(csrf_token()) ?>">
|
|
<div>
|
|
<label class="form-label">اسم الصنف</label>
|
|
<input type="text" class="form-control" name="name" required>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label">SKU</label>
|
|
<input type="text" class="form-control" name="sku" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">الوحدة</label>
|
|
<input type="text" class="form-control" name="unit" placeholder="عبوة" required>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label">الفئة</label>
|
|
<select class="form-select" name="category">
|
|
<option>منتج نهائي</option>
|
|
<option>مواد خام</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">المخزون الحالي</label>
|
|
<input type="number" step="0.01" class="form-control" name="stock_qty" required>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label">حد إعادة الطلب</label>
|
|
<input type="number" step="0.01" class="form-control" name="reorder_level" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">سعر البيع</label>
|
|
<input type="number" step="0.01" class="form-control" name="sale_price" required>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="form-label">ملاحظات</label>
|
|
<textarea class="form-control" name="notes" rows="3"></textarea>
|
|
</div>
|
|
<button class="btn btn-dark" type="submit">حفظ الصنف</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-7">
|
|
<div class="panel-card mb-4">
|
|
<div class="section-header">
|
|
<div>
|
|
<h2 class="section-title">جدول الأصناف</h2>
|
|
<p class="section-copy">يعرض الكمية الحالية، التنبيه، والسعر الأساسي.</p>
|
|
</div>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table align-middle app-table">
|
|
<thead>
|
|
<tr>
|
|
<th>الصنف</th>
|
|
<th>الفئة</th>
|
|
<th>المخزون</th>
|
|
<th>السعر</th>
|
|
<th>تفاصيل</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($products as $product): $payload = $product['payload_data']; $low = (float)($payload['stock_qty'] ?? 0) <= (float)($payload['reorder_level'] ?? 0); ?>
|
|
<tr>
|
|
<td>
|
|
<div class="fw-semibold"><?= e($product['title']) ?></div>
|
|
<div class="small text-secondary"><?= e($payload['sku'] ?? $product['code']) ?></div>
|
|
</td>
|
|
<td><?= e($payload['category'] ?? '') ?></td>
|
|
<td>
|
|
<?= e((string)($payload['stock_qty'] ?? 0)) ?>
|
|
<?php if ($low): ?><span class="badge text-bg-light border ms-2">منخفض</span><?php endif; ?>
|
|
</td>
|
|
<td><?= e(format_money((float)($payload['sale_price'] ?? 0))) ?></td>
|
|
<td><a class="btn btn-sm btn-outline-secondary" href="products.php?id=<?= (int)$product['id'] ?>">عرض</a></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="panel-card">
|
|
<div class="section-header compact">
|
|
<div>
|
|
<h2 class="section-title">تفاصيل الصنف</h2>
|
|
</div>
|
|
</div>
|
|
<?php if ($detail): $payload = $detail['payload_data']; ?>
|
|
<div class="detail-grid">
|
|
<div class="detail-block">
|
|
<span class="detail-label">اسم الصنف</span>
|
|
<strong><?= e($detail['title']) ?></strong>
|
|
</div>
|
|
<div class="detail-block">
|
|
<span class="detail-label">SKU</span>
|
|
<strong><?= e($payload['sku'] ?? $detail['code']) ?></strong>
|
|
</div>
|
|
<div class="detail-block">
|
|
<span class="detail-label">المخزون الحالي</span>
|
|
<strong><?= e((string)($payload['stock_qty'] ?? 0)) . ' ' . e($payload['unit'] ?? '') ?></strong>
|
|
</div>
|
|
<div class="detail-block">
|
|
<span class="detail-label">حد إعادة الطلب</span>
|
|
<strong><?= e((string)($payload['reorder_level'] ?? 0)) ?></strong>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<div class="subtle-card h-100">
|
|
<div class="detail-label mb-2">الفئة</div>
|
|
<div><?= e($payload['category'] ?? '') ?></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="subtle-card h-100">
|
|
<div class="detail-label mb-2">سعر البيع</div>
|
|
<div><?= e(format_money((float)($payload['sale_price'] ?? 0))) ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 text-secondary small"><?= e($payload['notes'] ?? '') ?></div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">اختر صنفًا من الجدول لعرض تفاصيله.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php render_footer(); ?>
|