39728-vm/includes/sale_form.php
2026-04-19 02:30:10 +00:00

181 lines
9.6 KiB
PHP

<?php
require_once __DIR__ . '/app.php';
$user = require_roles(['owner', 'manager', 'cashier']);
$pageTitle = $saleMode === 'normal' ? tr('بيع عادي', 'Normal Sale') : tr('نقاط البيع', 'POS Sale');
$activeNav = $saleMode === 'normal' ? 'normal' : 'pos';
$error = '';
$catalog = catalog();
$allowedBranches = $user['role'] === 'owner' ? array_keys(branches()) : [$user['branch_code']];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$branchCode = trim((string) ($_POST['branch_code'] ?? ''));
$customerName = trim((string) ($_POST['customer_name'] ?? ''));
$paymentMethod = trim((string) ($_POST['payment_method'] ?? 'cash'));
$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 cart.');
} 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 cart is invalid after product validation.');
} else {
$cashierName = current_lang() === 'ar' ? $user['name_ar'] : $user['name_en'];
$saleId = create_sale([
'receipt_no' => receipt_code(),
'sale_mode' => $saleMode,
'branch_code' => $branchCode,
'cashier_username' => $user['username'],
'cashier_name' => $cashierName,
'role_name' => $user['role'],
'customer_name' => $customerName !== '' ? $customerName : null,
'payment_method' => $paymentMethod,
'items' => $normalized,
'item_count' => $itemCount,
'subtotal' => $subtotal,
'total_amount' => $subtotal,
'notes' => $notes !== '' ? $notes : null,
]);
set_flash('success', $saleMode === 'normal'
? tr('تم حفظ البيع العادي بنجاح.', 'Normal sale saved successfully.')
: tr('تم حفظ عملية POS بنجاح.', 'POS sale saved successfully.'));
redirect_to('sale.php', ['id' => $saleId]);
}
}
}
require __DIR__ . '/header.php';
?>
<section class="row g-4">
<div class="col-xl-7">
<div class="surface-card h-100">
<div class="d-flex justify-content-between align-items-center mb-3 gap-3 flex-wrap">
<div>
<h3 class="h5 mb-1"><?= h($pageTitle) ?></h3>
<div class="small text-muted"><?= h(tr('أضف المنتجات إلى السلة ثم احفظ العملية.', 'Add products to the cart and save the transaction.')) ?></div>
</div>
<span class="badge text-bg-light border px-3 py-2"><?= h(sale_mode_label($saleMode)) ?></span>
</div>
<?php if ($error !== ''): ?>
<div class="alert alert-warning"><?= h($error) ?></div>
<?php endif; ?>
<form method="post" class="d-grid gap-4" id="sale-form" data-sale-form>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="branch_code"><?= h(tr('الفرع', 'Branch')) ?></label>
<select class="form-select" id="branch_code" name="branch_code" <?= count($allowedBranches) === 1 ? 'aria-readonly="true"' : '' ?>>
<?php foreach ($allowedBranches as $branchCode): ?>
<option value="<?= h($branchCode) ?>"><?= h(branch_label($branchCode)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label" for="payment_method"><?= h(tr('طريقة الدفع', 'Payment method')) ?></label>
<select class="form-select" id="payment_method" name="payment_method">
<option value="cash"><?= h(tr('نقداً', 'Cash')) ?></option>
<option value="card"><?= h(tr('بطاقة', 'Card')) ?></option>
<option value="transfer"><?= h(tr('تحويل', 'Transfer')) ?></option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" for="customer_name"><?= h(tr('اسم العميل', 'Customer name')) ?></label>
<input class="form-control" id="customer_name" name="customer_name" maxlength="120" placeholder="<?= h(tr('اختياري', 'Optional')) ?>">
</div>
<div class="col-md-6">
<label class="form-label" for="notes"><?= h(tr('ملاحظات', 'Notes')) ?></label>
<input class="form-control" id="notes" name="notes" maxlength="500" placeholder="<?= h(tr('طلب خاص أو ملاحظة داخلية', 'Special request or internal note')) ?>">
</div>
</div>
<input type="hidden" name="cart_json" id="cart_json" value="[]">
<div>
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="h6 mb-0"><?= h(tr('الأصناف السريعة', 'Quick products')) ?></h4>
<span class="small text-muted"><?= h(tr('انقر لإضافة المنتج', 'Tap to add product')) ?></span>
</div>
<div class="row g-3">
<?php foreach ($catalog as $product): ?>
<div class="col-sm-6 col-lg-4">
<button class="product-tile w-100 text-start" type="button" data-add-product data-sku="<?= h($product['sku']) ?>" data-name="<?= h(current_lang() === 'ar' ? $product['name_ar'] : $product['name_en']) ?>" data-price="<?= h((string) $product['price']) ?>">
<span class="product-pill"><?= h(current_lang() === 'ar' ? $product['unit_ar'] : $product['unit_en']) ?></span>
<div class="fw-semibold mb-1"><?= h(current_lang() === 'ar' ? $product['name_ar'] : $product['name_en']) ?></div>
<div class="small text-muted mb-2">SKU: <?= h($product['sku']) ?></div>
<div class="fw-semibold"><?= h(currency((float) $product['price'])) ?></div>
</button>
</div>
<?php endforeach; ?>
</div>
</div>
</form>
</div>
</div>
<div class="col-xl-5">
<div class="surface-card h-100 cart-panel">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="h5 mb-0"><?= h(tr('السلة', 'Cart')) ?></h3>
<span class="small text-muted" id="cart-count-label">0 <?= h(tr('قطعة', 'items')) ?></span>
</div>
<div class="empty-state compact mb-3" id="cart-empty-state">
<h4><?= h(tr('السلة فارغة', 'Cart is empty')) ?></h4>
<p class="mb-0"><?= h(tr('اختر المنتجات من القائمة اليسرى لبدء أول فاتورة.', 'Select products from the left to start the first receipt.')) ?></p>
</div>
<div id="cart-lines" class="d-grid gap-2"></div>
<div class="cart-summary mt-3 pt-3 border-top">
<div class="d-flex justify-content-between small text-muted mb-2"><span><?= h(tr('المجموع الفرعي', 'Subtotal')) ?></span><span id="cart-subtotal">0.00</span></div>
<div class="d-flex justify-content-between fw-semibold"><span><?= h(tr('الإجمالي', 'Total')) ?></span><span id="cart-total">0.00</span></div>
</div>
<div class="d-grid gap-2 mt-3">
<button class="btn btn-dark" type="submit" form="sale-form"><?= h(tr('حفظ الفاتورة', 'Save invoice')) ?></button>
<button class="btn btn-outline-secondary" type="button" data-clear-cart><?= h(tr('تفريغ السلة', 'Clear cart')) ?></button>
</div>
<div class="alert alert-light border mt-3 mb-0 small">
<?= h(tr('بعد الحفظ ستنتقل مباشرة إلى صفحة التفاصيل ويمكنك الطباعة من هناك.', 'After saving, you will go straight to the detail page and can print from there.')) ?>
</div>
</div>
</div>
</section>
<script>
window.saleCatalog = <?= json_encode(array_values(array_map(static function (array $item): array {
return [
'sku' => $item['sku'],
'name' => current_lang() === 'ar' ? $item['name_ar'] : $item['name_en'],
'price' => (float) $item['price'],
];
}, $catalog)), JSON_UNESCAPED_UNICODE) ?>;
window.saleLabels = <?= json_encode([
'currency' => tr('ر.ع', 'OMR'),
'empty' => tr('السلة فارغة', 'Cart is empty'),
'remove' => tr('إزالة', 'Remove'),
], JSON_UNESCAPED_UNICODE) ?>;
</script>
<?php require __DIR__ . '/footer.php'; ?>