1018 lines
46 KiB
PHP
1018 lines
46 KiB
PHP
<?php
|
|
require_once __DIR__ . '/app.php';
|
|
$user = require_roles(['owner', 'manager', 'cashier']);
|
|
$orderType = isset($orderType) && $orderType === 'eid' ? 'eid' : 'standard';
|
|
$isEidOrder = $orderType === 'eid';
|
|
$pageTitle = $pageTitle ?? ($isEidOrder
|
|
? tr('إنشاء طلب عيد', 'Create Eid Order')
|
|
: ($saleMode === 'normal' ? tr('إنشاء فاتورة ضريبية', 'Create Tax Invoice') : tr('نقاط البيع', 'POS Sale')));
|
|
$activeNav = $activeNav ?? ($isEidOrder ? 'eid_orders' : ($saleMode === 'normal' ? 'normal' : 'pos'));
|
|
$backUrl = $backUrl ?? ($isEidOrder ? url_for('eid_orders.php') : url_for('sales.php'));
|
|
$backLabel = $backLabel ?? ($isEidOrder ? tr('عودة لطلبات العيد', 'Back to Eid Orders') : tr('عودة للمبيعات', 'Back to Sales'));
|
|
$saveLabel = $saveLabel ?? ($isEidOrder ? tr('حفظ طلب العيد', 'Save Eid Order') : tr('حفظ الفاتورة', 'Save Invoice'));
|
|
$saveOnlyLabel = $saveOnlyLabel ?? tr('حفظ فقط', 'Save only');
|
|
$savePrintLabel = $savePrintLabel ?? tr('حفظ مع الطباعة', 'Save with print');
|
|
$error = '';
|
|
$paymentAmountInput = (string) ($_POST['payment_amount'] ?? '');
|
|
$catalog = catalog();
|
|
$globalVatPercent = max(0, (float) get_setting('vat_percentage', 5));
|
|
$allowedBranches = get_user_branches($user);
|
|
$deliveryOptions = eid_delivery_status_options();
|
|
$selectedDeliveryStatus = trim((string) ($_POST['delivery_status'] ?? ($isEidOrder ? 'pending' : '')));
|
|
$deliveryDateInput = trim((string) ($_POST['delivery_date'] ?? ''));
|
|
$saleStatusInput = trim((string) ($_POST['sale_status'] ?? ($isEidOrder ? 'order' : 'completed')));
|
|
$notesInput = trim((string) ($_POST['notes'] ?? ''));
|
|
$notesLabel = $isEidOrder
|
|
? tr('ملاحظة داخلية للفاتورة', 'Internal invoice notice')
|
|
: tr('ملاحظات (اختياري)', 'Notes (Optional)');
|
|
$notesPlaceholder = $isEidOrder
|
|
? tr('مثال: بدون مكسرات، تغليف خاص، اتصال قبل التسليم...', 'Example: no nuts, special packing, call before delivery...')
|
|
: tr('أي ملاحظات إضافية...', 'Any additional notes...');
|
|
$notesHelper = $isEidOrder
|
|
? tr('هذه الملاحظة داخلية وتبقى في النظام فقط، ولن تظهر في الإيصال المطبوع.', 'This note is internal, stays in the system only, and will not appear on the printed receipt.')
|
|
: tr('سيتم حفظ هذه الملاحظات مع الفاتورة داخل النظام.', 'These notes will be saved with the invoice inside the system.');
|
|
$itemNotePlaceholder = $isEidOrder
|
|
? tr('مثال: بدون سكر، تغليف هدية، لون معين، كتابة اسم...', 'Example: no sugar, gift wrap, specific color, write a name...')
|
|
: tr('ملاحظة داخلية لهذا الصنف...', 'Internal note for this item...');
|
|
$itemNoteHelper = $isEidOrder
|
|
? tr('ملاحظة داخلية لهذا الصنف فقط — لا تُطبع في الإيصال.', 'Internal for this item only — not printed on the receipt.')
|
|
: tr('ملاحظة محفوظة لهذا الصنف داخل النظام.', 'This note is saved for this item inside the system.');
|
|
|
|
try {
|
|
$customers = db()->query('SELECT id, name, phone FROM customers ORDER BY name ASC')->fetchAll();
|
|
} catch (Throwable $e) {
|
|
$customers = [];
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$submitAction = trim((string) ($_POST['submit_action'] ?? 'save'));
|
|
if (!in_array($submitAction, ['save', 'save_print'], true)) {
|
|
$submitAction = 'save';
|
|
}
|
|
|
|
$branchCode = trim((string) ($_POST['branch_code'] ?? ''));
|
|
$customerId = isset($_POST['customer_id']) && $_POST['customer_id'] !== '' ? (int)$_POST['customer_id'] : null;
|
|
$customerName = trim((string) ($_POST['customer_name'] ?? ''));
|
|
$paymentMethod = trim((string) ($_POST['payment_method'] ?? 'cash'));
|
|
$paymentAmountInput = trim((string) ($_POST['payment_amount'] ?? ''));
|
|
$saleStatus = trim((string) ($_POST['sale_status'] ?? ($isEidOrder ? 'order' : 'completed')));
|
|
$saleStatusInput = $saleStatus;
|
|
$notes = trim((string) ($_POST['notes'] ?? ''));
|
|
$notesInput = $notes;
|
|
$deliveryStatus = trim((string) ($_POST['delivery_status'] ?? ($isEidOrder ? 'pending' : '')));
|
|
$selectedDeliveryStatus = $deliveryStatus;
|
|
$deliveryDate = trim((string) ($_POST['delivery_date'] ?? ''));
|
|
$deliveryDateInput = $deliveryDate;
|
|
$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', 'pay_later'], true)) {
|
|
$error = tr('اختر طريقة دفع صحيحة.', 'Choose a valid payment method.');
|
|
} elseif ($saleStatus === 'order' && !$customerId) {
|
|
$error = tr('يجب اختيار عميل للطلب المسبق.', 'You must select a customer for a pre-order.');
|
|
} elseif ($isEidOrder && !isset($deliveryOptions[$deliveryStatus])) {
|
|
$error = tr('اختر حالة تجهيز صحيحة لطلب العيد.', 'Choose a valid prep status for the Eid order.');
|
|
} elseif ($isEidOrder && ($deliveryDate === '' || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $deliveryDate))) {
|
|
$error = tr('حدد تاريخ تسليم صحيح لطلب العيد.', 'Choose a valid delivery date for the Eid order.');
|
|
} elseif (!is_array($items) || $items === []) {
|
|
$error = tr('أضف صنفاً واحداً على الأقل إلى الفاتورة.', 'Add at least one item to the invoice.');
|
|
} else {
|
|
$normalized = [];
|
|
$subtotal = 0.0;
|
|
$totalVat = 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];
|
|
$editedName = trim((string) ($item['name'] ?? ''));
|
|
$finalName = $editedName !== ''
|
|
? $editedName
|
|
: trim((string) ($product['name_' . current_lang()] ?? ''));
|
|
if ($finalName === '') {
|
|
$finalName = trim((string) ($product['name_ar'] ?? ''));
|
|
}
|
|
if ($finalName === '') {
|
|
$finalName = trim((string) ($product['name_en'] ?? ''));
|
|
}
|
|
if ($finalName === '') {
|
|
$finalName = $sku;
|
|
}
|
|
|
|
$itemNote = trim((string) ($item['item_note'] ?? ''));
|
|
|
|
$price = isset($item['price']) && is_numeric($item['price'])
|
|
? max(0, (float) $item['price'])
|
|
: (float) $product['price'];
|
|
$lineTotal = $price * $qty;
|
|
|
|
$vatPercent = $globalVatPercent;
|
|
$itemVat = $lineTotal * ($vatPercent / 100);
|
|
$totalVat += $itemVat;
|
|
|
|
$normalized[] = [
|
|
'sku' => $sku,
|
|
'name_ar' => $finalName,
|
|
'name_en' => $finalName,
|
|
'qty' => $qty,
|
|
'price' => $price,
|
|
'item_note' => $itemNote,
|
|
'line_total' => $lineTotal,
|
|
'vat_percent' => $vatPercent,
|
|
'vat_amount' => $itemVat
|
|
];
|
|
$subtotal += $lineTotal;
|
|
$itemCount += $qty;
|
|
}
|
|
|
|
if ($normalized === []) {
|
|
$error = tr('الفاتورة غير صالحة بعد التحقق من الأصناف.', 'The invoice is invalid after product validation.');
|
|
} else {
|
|
$totalAmount = $subtotal + $totalVat;
|
|
if ($paymentAmountInput !== '' && !is_numeric($paymentAmountInput)) {
|
|
$error = tr('أدخل مبلغاً مدفوعاً صحيحاً.', 'Enter a valid paid amount.');
|
|
} else {
|
|
$paymentMeta = sale_payment_breakdown($totalAmount, $paymentMethod, $paymentAmountInput);
|
|
if ($paymentMeta['due_amount'] > 0.0005 && !$customerId) {
|
|
$error = tr('يجب اختيار عميل مسجل عند وجود مبلغ متبقٍ أو دفعة جزئية.', 'Select a registered customer when there is a remaining balance or partial payment.');
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($error === '') {
|
|
$cashierName = current_lang() === 'ar' ? $user['name_ar'] : $user['name_en'];
|
|
$saleId = create_sale([
|
|
'sale_mode' => $saleMode,
|
|
'branch_code' => $branchCode,
|
|
'cashier_username' => $user['username'],
|
|
'cashier_name' => $cashierName,
|
|
'role_name' => $user['role'],
|
|
'customer_id' => $customerId,
|
|
'customer_name' => $customerName !== '' ? $customerName : null,
|
|
'payment_method' => $paymentMethod,
|
|
'payment_status' => $paymentMeta['payment_status'],
|
|
'paid_amount' => $paymentMeta['paid_amount'],
|
|
'due_amount' => $paymentMeta['due_amount'],
|
|
'items' => $normalized,
|
|
'item_count' => $itemCount,
|
|
'subtotal' => $subtotal,
|
|
'vat_amount' => $totalVat,
|
|
'total_amount' => $totalAmount,
|
|
'status' => $saleStatus,
|
|
'order_type' => $orderType,
|
|
'delivery_status' => $isEidOrder ? $deliveryStatus : null,
|
|
'delivery_date' => $isEidOrder ? $deliveryDate : null,
|
|
'notes' => $notes !== '' ? $notes : null,
|
|
]);
|
|
|
|
wablas_notify_sale_invoice($saleId);
|
|
|
|
set_flash('success', $isEidOrder
|
|
? tr('تم حفظ طلب العيد بنجاح.', 'Eid order saved successfully.')
|
|
: ($saleMode === 'normal'
|
|
? tr('تم حفظ الفاتورة بنجاح.', 'Invoice saved successfully.')
|
|
: tr('تم حفظ عملية POS بنجاح.', 'POS sale saved successfully.')));
|
|
if ($submitAction === 'save') {
|
|
if ($isEidOrder) {
|
|
redirect_to('eid_sale.php');
|
|
}
|
|
if ($saleMode === 'normal') {
|
|
redirect_to('normal_sale.php');
|
|
}
|
|
redirect_to('pos.php');
|
|
}
|
|
|
|
$redirectParams = ['id' => $saleId, 'print' => 1];
|
|
if ($isEidOrder) {
|
|
redirect_to('print_receipt.php', $redirectParams);
|
|
}
|
|
redirect_to('sale.php', $redirectParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
require __DIR__ . '/header.php';
|
|
?>
|
|
|
|
<style>
|
|
.smart-form-card {
|
|
background: #fff;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
|
|
border: 1px solid #edf2f9;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.smart-form-header {
|
|
padding: 1.5rem 2rem;
|
|
border-bottom: 1px solid #edf2f9;
|
|
background-color: #fcfdfd;
|
|
border-radius: 12px 12px 0 0;
|
|
}
|
|
.smart-form-body {
|
|
padding: 2rem;
|
|
}
|
|
.section-title {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin-bottom: 1.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
.form-label {
|
|
font-weight: 500;
|
|
color: #495057;
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
.custom-input {
|
|
border: 1px solid #ced4da;
|
|
border-radius: 8px;
|
|
padding: 0.6rem 1rem;
|
|
font-size: 0.95rem;
|
|
transition: all 0.2s ease-in-out;
|
|
}
|
|
.custom-input:focus {
|
|
border-color: #3b82f6;
|
|
box-shadow: 0 0 0 0.25rem rgba(59, 130, 246, 0.25);
|
|
}
|
|
.search-wrapper {
|
|
position: relative;
|
|
max-width: 600px;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.search-icon {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 1rem;
|
|
transform: translateY(-50%);
|
|
color: #6c757d;
|
|
}
|
|
[dir="rtl"] .search-icon {
|
|
left: auto;
|
|
right: 1rem;
|
|
}
|
|
.search-input {
|
|
padding-left: 2.5rem;
|
|
}
|
|
[dir="rtl"] .search-input {
|
|
padding-left: 1rem;
|
|
padding-right: 2.5rem;
|
|
}
|
|
.item-search-dropdown {
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
right: 0;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
z-index: 1000;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
display: none;
|
|
border: 1px solid #edf2f9;
|
|
margin-top: 0.5rem;
|
|
}
|
|
.item-search-dropdown.show { display: block; }
|
|
.search-item-row {
|
|
padding: 0.75rem 1rem;
|
|
cursor: pointer;
|
|
border-bottom: 1px solid #edf2f9;
|
|
transition: background 0.15s;
|
|
}
|
|
.search-item-row:hover { background: #f8f9fa; }
|
|
.search-item-row:last-child { border-bottom: none; }
|
|
|
|
.table-modern {
|
|
width: 100%;
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
border: 1px solid #edf2f9;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
.table-modern th {
|
|
background: #f8f9fa;
|
|
padding: 1rem;
|
|
font-weight: 600;
|
|
color: #495057;
|
|
border-bottom: 1px solid #edf2f9;
|
|
font-size: 0.9rem;
|
|
}
|
|
.table-modern td {
|
|
padding: 1rem;
|
|
vertical-align: middle;
|
|
border-bottom: 1px solid #edf2f9;
|
|
}
|
|
.table-modern tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
.qty-control {
|
|
width: 80px;
|
|
text-align: center;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 6px;
|
|
padding: 0.4rem;
|
|
}
|
|
.btn-remove {
|
|
color: #dc3545;
|
|
background: rgba(220, 53, 69, 0.1);
|
|
border: none;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 6px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: all 0.2s;
|
|
}
|
|
.btn-remove:hover {
|
|
background: #dc3545;
|
|
color: #fff;
|
|
}
|
|
|
|
.totals-box {
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
border: 1px solid #edf2f9;
|
|
}
|
|
.totals-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 0.75rem;
|
|
color: #495057;
|
|
}
|
|
.totals-row.grand-total {
|
|
margin-top: 1rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid #dee2e6;
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: #212529;
|
|
margin-bottom: 0;
|
|
}
|
|
.inline-notice-box {
|
|
margin-top: 1rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px dashed #d9e3f0;
|
|
}
|
|
.inline-notice-box .form-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
.inline-notice-box .notice-icon {
|
|
width: 1.9rem;
|
|
height: 1.9rem;
|
|
border-radius: 999px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #92400e;
|
|
background: rgba(245, 158, 11, 0.14);
|
|
flex-shrink: 0;
|
|
}
|
|
.inline-notice-box textarea {
|
|
background: #fff;
|
|
resize: vertical;
|
|
}
|
|
.line-input {
|
|
min-width: 0;
|
|
}
|
|
.line-price-input {
|
|
min-width: 96px;
|
|
}
|
|
</style>
|
|
|
|
<div class="container-fluid py-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h3 class="fw-bold mb-0 text-dark"><?= h($pageTitle) ?></h3>
|
|
<a href="<?= h($backUrl) ?>" class="btn btn-outline-secondary btn-sm">
|
|
<i class="bi bi-arrow-left"></i> <?= h($backLabel) ?>
|
|
</a>
|
|
</div>
|
|
|
|
<?php if ($error !== ''): ?>
|
|
<div class="alert alert-danger rounded-3 shadow-sm mb-4"><i class="bi bi-exclamation-triangle-fill me-2"></i><?= h($error) ?></div>
|
|
<?php endif; ?>
|
|
|
|
<form method="post" id="smart-sale-form">
|
|
<input type="hidden" name="cart_json" id="cart_json" value="[]">
|
|
<input type="hidden" name="order_type" value="<?= h($orderType) ?>">
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<!-- Items Section -->
|
|
<div class="smart-form-card">
|
|
<div class="smart-form-header">
|
|
<div class="section-title mb-0">
|
|
<i class="bi bi-cart-plus text-primary"></i> <?= h(tr('عناصر الفاتورة', 'Invoice Items')) ?>
|
|
</div>
|
|
</div>
|
|
<div class="smart-form-body">
|
|
|
|
<!-- Search Bar -->
|
|
<div class="search-wrapper">
|
|
<i class="bi bi-search search-icon"></i>
|
|
<input type="text" id="itemSearchInput" class="form-control custom-input search-input form-control-lg" placeholder="<?= h(tr('ابحث بالاسم أو الباركود...', 'Search by name or barcode...')) ?>" autocomplete="off">
|
|
<div id="itemDropdown" class="item-search-dropdown"></div>
|
|
</div>
|
|
|
|
<!-- Table -->
|
|
<div class="table-responsive">
|
|
<table class="table-modern" id="invoiceTable">
|
|
<thead>
|
|
<tr>
|
|
<th width="45%"><?= h(tr('المنتج', 'Product')) ?></th>
|
|
<th width="15%" class="text-center"><?= h(tr('السعر', 'Price')) ?></th>
|
|
<th width="15%" class="text-center"><?= h(tr('الكمية', 'Qty')) ?></th>
|
|
<th width="20%" class="text-center"><?= h(tr('الإجمالي', 'Total')) ?></th>
|
|
<th width="5%"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="invoiceLines">
|
|
<tr id="emptyInvoiceRow">
|
|
<td colspan="5" class="text-center py-5 text-muted">
|
|
<i class="bi bi-inbox fs-1 d-block mb-2 text-light"></i>
|
|
<?= h(tr('لم يتم إضافة أي منتجات بعد.', 'No products added yet.')) ?>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<!-- Settings Section -->
|
|
<div class="smart-form-card">
|
|
<div class="smart-form-header">
|
|
<div class="section-title mb-0">
|
|
<i class="bi bi-receipt text-primary"></i> <?= h(tr('تفاصيل الفاتورة', 'Invoice Details')) ?>
|
|
</div>
|
|
</div>
|
|
<div class="smart-form-body">
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
|
<select class="form-select custom-input" name="branch_code" <?= count($allowedBranches) === 1 ? 'readonly' : '' ?>>
|
|
<?php foreach ($allowedBranches as $branchCode): ?>
|
|
<option value="<?= h($branchCode) ?>"><?= h(branch_label($branchCode)) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3 position-relative">
|
|
<label class="form-label"><?= h(tr('العميل', 'Customer')) ?></label>
|
|
<div class="input-group">
|
|
<input type="hidden" id="formCustomerId" name="customer_id">
|
|
<input type="text" id="formCustomer" name="customer_name" class="form-control custom-input" style="border-right-width: 1px;" placeholder="<?= h(tr('بحث (اسم أو هاتف)', 'Search (Name or Phone)')) ?>" autocomplete="off">
|
|
<button class="btn btn-outline-primary px-3" style="border-radius: 0 8px 8px 0;" type="button" onclick="openNewCustomerModal()" title="<?= h(tr('إضافة عميل', 'Add Customer')) ?>">
|
|
<i class="bi bi-person-plus-fill"></i>
|
|
</button>
|
|
</div>
|
|
<div id="formCustomerDropdown" class="item-search-dropdown w-100" style="top: 100%;"></div>
|
|
</div>
|
|
<?php if ($isEidOrder): ?>
|
|
<div class="alert alert-warning border-0 bg-warning-subtle text-dark small mb-3">
|
|
<i class="bi bi-stars me-1"></i><?= h(tr('سيتم حفظ هذه الفاتورة داخل وحدة طلبات العيد مع تاريخ التسليم وحالة التجهيز.', 'This invoice will be saved inside the Eid Orders module with delivery date and prep status.')) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('نوع العملية', 'Entry Type')) ?></label>
|
|
<select class="form-select custom-input" name="sale_status">
|
|
<?php if ($isEidOrder): ?>
|
|
<option value="order" <?= $saleStatusInput === 'order' ? 'selected' : '' ?>><?= h(tr('طلب عيد قيد التجهيز', 'Eid order in preparation')) ?></option>
|
|
<option value="completed" <?= $saleStatusInput === 'completed' ? 'selected' : '' ?>><?= h(tr('تم التسليم / مكتمل', 'Delivered / Completed')) ?></option>
|
|
<?php else: ?>
|
|
<option value="completed" <?= $saleStatusInput === 'completed' ? 'selected' : '' ?>><?= h(tr('فاتورة بيع (تم الدفع)', 'Sale Bill (Paid)')) ?></option>
|
|
<option value="order" <?= $saleStatusInput === 'order' ? 'selected' : '' ?>><?= h(tr('طلب مسبق (دفع لاحق)', 'Order (Pay Later)')) ?></option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<?php if ($isEidOrder): ?>
|
|
<div class="mb-3">
|
|
<label class="form-label" for="delivery_date"><?= h(tr('تاريخ التسليم', 'Delivery date')) ?></label>
|
|
<input type="date" class="form-control custom-input" id="delivery_date" name="delivery_date" value="<?= h($deliveryDateInput) ?>" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label" for="delivery_status"><?= h(tr('حالة التجهيز', 'Prep status')) ?></label>
|
|
<select class="form-select custom-input" id="delivery_status" name="delivery_status">
|
|
<?php foreach ($deliveryOptions as $value => $label): ?>
|
|
<option value="<?= h($value) ?>" <?= $selectedDeliveryStatus === $value ? 'selected' : '' ?>><?= h($label) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="mb-3">
|
|
<label class="form-label"><?= h(tr('طريقة الدفع', 'Payment Method')) ?></label>
|
|
<select class="form-select custom-input" name="payment_method">
|
|
<option value="cash" <?= ($paymentMethod ?? 'cash') === 'cash' ? 'selected' : '' ?>><?= h(tr('نقداً', 'Cash')) ?></option>
|
|
<option value="card" <?= ($paymentMethod ?? '') === 'card' ? 'selected' : '' ?>><?= h(tr('بطاقة ائتمان', 'Credit Card')) ?></option>
|
|
<option value="transfer" <?= ($paymentMethod ?? '') === 'transfer' ? 'selected' : '' ?>><?= h(tr('تحويل بنكي', 'Bank Transfer')) ?></option>
|
|
<option value="pay_later" <?= ($paymentMethod ?? '') === 'pay_later' ? 'selected' : '' ?>><?= h(tr('آجل (Pay Later)', 'Pay Later')) ?></option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label" for="payment_amount"><?= h(tr('المبلغ المدفوع الآن', 'Paid Now')) ?></label>
|
|
<input type="number" class="form-control custom-input" id="payment_amount" name="payment_amount" min="0" step="0.001" value="<?= h($paymentAmountInput) ?>" placeholder="0.000">
|
|
<div class="row g-2 mt-2" aria-live="polite">
|
|
<div class="col-6">
|
|
<div class="border rounded-3 px-3 py-2 bg-light-subtle h-100">
|
|
<div class="small text-muted mb-1"><?= h(tr('المدفوع بعد الحفظ', 'Paid after save')) ?></div>
|
|
<div class="fw-semibold text-success" id="displayPaidAmountLive">0.000 <?= h(tr('ر.ع', 'OMR')) ?></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="border rounded-3 px-3 py-2 bg-light-subtle h-100">
|
|
<div class="small text-muted mb-1"><?= h(tr('المتبقي بعد الحفظ', 'Remaining after save')) ?></div>
|
|
<div class="fw-semibold text-primary" id="displayDueAmountLive">0.000 <?= h(tr('ر.ع', 'OMR')) ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-text" id="paymentAmountHint"><?= h(tr('يمكنك تعديل المبلغ المدفوع يدوياً وسيتم تتبع الباقي تلقائياً.', 'You can edit the paid amount manually and the remaining balance will be tracked automatically.')) ?></div>
|
|
</div>
|
|
<!-- Summary -->
|
|
<div class="totals-box mb-4">
|
|
<div class="totals-row">
|
|
<span><?= h(tr('المجموع الفرعي', 'Subtotal')) ?></span>
|
|
<span id="displaySubtotal" class="fw-medium">0.000</span>
|
|
</div>
|
|
<div class="totals-row">
|
|
<span><?= h(tr('الضريبة (' . number_format($globalVatPercent, 2) . '%)', 'VAT (' . number_format($globalVatPercent, 2) . '%)')) ?></span>
|
|
<span id="displayVat" class="text-muted">0.000</span>
|
|
</div>
|
|
<div class="totals-row grand-total">
|
|
<span><?= h(tr('الإجمالي', 'Total')) ?></span>
|
|
<span id="displayTotal" class="text-primary">0.000 <?= h(tr('ر.ع', 'OMR')) ?></span>
|
|
</div>
|
|
<div class="inline-notice-box">
|
|
<label class="form-label" for="invoice_notes">
|
|
<span class="notice-icon"><i class="bi bi-journal-text"></i></span>
|
|
<span><?= h($notesLabel) ?></span>
|
|
</label>
|
|
<textarea class="form-control custom-input" id="invoice_notes" name="notes" rows="<?= $isEidOrder ? '3' : '2' ?>" placeholder="<?= h($notesPlaceholder) ?>"><?= h($notesInput) ?></textarea>
|
|
<div class="form-text mt-2"><?= h($notesHelper) ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" name="submit_action" value="save" class="btn btn-primary w-100 py-2 fs-5 rounded-3 shadow-sm">
|
|
<i class="bi bi-check-circle me-1"></i> <?= h($saveOnlyLabel) ?>
|
|
</button>
|
|
<button type="submit" name="submit_action" value="save_print" class="btn btn-outline-dark w-100 py-2 fs-5 rounded-3 shadow-sm">
|
|
<i class="bi bi-printer me-1"></i> <?= h($savePrintLabel) ?>
|
|
</button>
|
|
</div>
|
|
<div class="form-text mt-2"><?= h(tr('اختر إذا كنت تريد الحفظ فقط أو الحفظ وفتح نافذة الطباعة مباشرة.', 'Choose whether to save only or save and open the print dialog immediately.')) ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- New Customer Modal -->
|
|
<div class="modal fade" id="newCustomerModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered modal-sm">
|
|
<div class="modal-content border-0 shadow-lg" style="border-radius: 16px;">
|
|
<div class="modal-header border-0 pb-0">
|
|
<h5 class="modal-title fw-bold"><?= h(tr('إضافة عميل', 'Add Customer')) ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted small mb-1"><?= h(tr('الاسم', 'Name')) ?> <span class="text-danger">*</span></label>
|
|
<input type="text" id="ncName" class="form-control rounded-3">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted small mb-1"><?= h(tr('رقم الهاتف', 'Phone')) ?></label>
|
|
<div class="input-group" dir="ltr">
|
|
<span class="input-group-text">968</span>
|
|
<input type="text" id="ncPhone" class="form-control rounded-end-3" inputmode="numeric" maxlength="8" pattern="\d{8}" placeholder="91234567">
|
|
</div>
|
|
</div>
|
|
<div class="d-grid mt-4">
|
|
<button class="btn btn-primary rounded-pill fw-semibold shadow-sm" onclick="saveNewCustomer()"><?= h(tr('حفظ العميل', 'Save Customer')) ?></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<script>
|
|
const catalogData = <?= json_encode($catalog, JSON_UNESCAPED_UNICODE) ?>;
|
|
const catalogArray = Object.values(catalogData);
|
|
const partialPaymentText = '<?= h(tr('متبقٍ بعد الحفظ:', 'Due after save:')) ?>';
|
|
const showItemNotes = <?= $isEidOrder ? 'true' : 'false' ?>;
|
|
const itemNotePlaceholder = <?= json_encode($itemNotePlaceholder, JSON_UNESCAPED_UNICODE) ?>;
|
|
const itemNoteHelper = <?= json_encode($itemNoteHelper, JSON_UNESCAPED_UNICODE) ?>;
|
|
let invoiceItems = {};
|
|
let currentInvoiceTotal = 0;
|
|
|
|
const searchInput = document.getElementById('itemSearchInput');
|
|
const dropdown = document.getElementById('itemDropdown');
|
|
const tbody = document.getElementById('invoiceLines');
|
|
const emptyRow = document.getElementById('emptyInvoiceRow');
|
|
const cartJson = document.getElementById('cart_json');
|
|
const currencySuffix = ' <?= h(tr('ر.ع', 'OMR')) ?>';
|
|
|
|
// Customers Logic
|
|
let customersData = <?= json_encode($customers, JSON_UNESCAPED_UNICODE) ?>;
|
|
const custInput = document.getElementById('formCustomer');
|
|
const custDropdown = document.getElementById('formCustomerDropdown');
|
|
|
|
custInput.addEventListener('input', function() {
|
|
const q = this.value.toLowerCase().trim();
|
|
custDropdown.innerHTML = '';
|
|
if (q.length < 2) {
|
|
document.getElementById('formCustomerId').value = '';
|
|
custDropdown.classList.remove('show');
|
|
return;
|
|
}
|
|
|
|
const matches = customersData.filter(c =>
|
|
c.name.toLowerCase().includes(q) ||
|
|
(c.phone && c.phone.toLowerCase().includes(q))
|
|
).slice(0, 5);
|
|
|
|
if (matches.length > 0) {
|
|
matches.forEach(c => {
|
|
const div = document.createElement('div');
|
|
div.className = 'search-item-row';
|
|
div.innerHTML = `<strong>${c.name}</strong> ${c.phone ? '<small class="text-muted ms-2">968 '+c.phone+'</small>' : ''}`;
|
|
div.onclick = function() {
|
|
custInput.value = c.name + (c.phone ? ' - 968 ' + c.phone : '');
|
|
document.getElementById('formCustomerId').value = c.id; custDropdown.classList.remove('show');
|
|
};
|
|
custDropdown.appendChild(div);
|
|
});
|
|
custDropdown.classList.add('show');
|
|
} else {
|
|
document.getElementById('formCustomerId').value = '';
|
|
custDropdown.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function(e) {
|
|
if (!custInput.contains(e.target) && !custDropdown.contains(e.target)) {
|
|
custDropdown.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
let newCustomerModalObj = null;
|
|
function openNewCustomerModal() {
|
|
if (!newCustomerModalObj) {
|
|
newCustomerModalObj = new bootstrap.Modal(document.getElementById('newCustomerModal'));
|
|
}
|
|
document.getElementById('ncName').value = '';
|
|
document.getElementById('ncPhone').value = '';
|
|
newCustomerModalObj.show();
|
|
}
|
|
|
|
async function saveNewCustomer() {
|
|
const name = document.getElementById('ncName').value.trim();
|
|
const phone = document.getElementById('ncPhone').value.trim();
|
|
if (!name) {
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('الاسم مطلوب', 'Name is required')) ?>'});
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('name', name);
|
|
formData.append('phone', phone);
|
|
|
|
try {
|
|
const res = await fetch('api/customers.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
customersData.push(data.customer);
|
|
custInput.value = data.customer.name + (data.customer.phone ? ' - 968 ' + data.customer.phone : '');
|
|
document.getElementById('formCustomerId').value = data.customer.id;
|
|
newCustomerModalObj.hide();
|
|
Swal.fire({
|
|
icon: 'success',
|
|
text: '<?= h(tr('تم إضافة العميل', 'Customer added')) ?>',
|
|
position: 'center',
|
|
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>',
|
|
confirmButtonColor: '#0d6efd'
|
|
});
|
|
} else {
|
|
Swal.fire({icon: 'warning', text: data.error});
|
|
}
|
|
} catch(err) {
|
|
Swal.fire({icon: 'warning', text: 'Error saving customer'});
|
|
}
|
|
}
|
|
|
|
|
|
// Search logic
|
|
searchInput.addEventListener('input', function() {
|
|
const q = this.value.toLowerCase().trim();
|
|
dropdown.innerHTML = '';
|
|
|
|
if (q === '') {
|
|
dropdown.classList.remove('show');
|
|
return;
|
|
}
|
|
|
|
const matches = catalogArray.filter(item => {
|
|
const nameAr = (item.name_ar || '').toLowerCase();
|
|
const nameEn = (item.name_en || '').toLowerCase();
|
|
const sku = (item.sku || '').toLowerCase();
|
|
return nameAr.includes(q) || nameEn.includes(q) || sku.includes(q);
|
|
}).slice(0, 6);
|
|
|
|
if (matches.length > 0) {
|
|
matches.forEach(item => {
|
|
const div = document.createElement('div');
|
|
div.className = 'search-item-row d-flex justify-content-between align-items-center';
|
|
const name = '<?= current_lang() ?>' === 'ar' ? item.name_ar : item.name_en;
|
|
div.innerHTML = `
|
|
<div>
|
|
<div class="fw-medium text-dark">${name}</div>
|
|
<div class="text-muted small">SKU: ${item.sku}</div>
|
|
</div>
|
|
<div class="fw-semibold text-primary">${parseFloat(item.price).toFixed(3)}</div>
|
|
`;
|
|
div.onclick = () => {
|
|
addItemToInvoice(item.sku);
|
|
searchInput.value = '';
|
|
dropdown.classList.remove('show');
|
|
searchInput.focus();
|
|
};
|
|
dropdown.appendChild(div);
|
|
});
|
|
dropdown.classList.add('show');
|
|
} else {
|
|
dropdown.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
// Barcode scanner integration on enter
|
|
searchInput.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
const q = this.value.trim();
|
|
if(q === '') return;
|
|
|
|
const match = catalogArray.find(item => item.sku === q);
|
|
if (match) {
|
|
addItemToInvoice(match.sku);
|
|
searchInput.value = '';
|
|
dropdown.classList.remove('show');
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function(e) {
|
|
if (!searchInput.contains(e.target) && !dropdown.contains(e.target)) {
|
|
dropdown.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
function addItemToInvoice(sku) {
|
|
if (invoiceItems[sku]) {
|
|
invoiceItems[sku].qty += 1;
|
|
} else {
|
|
const item = catalogData[sku];
|
|
invoiceItems[sku] = {
|
|
sku: sku,
|
|
name: '<?= current_lang() ?>' === 'ar' ? item.name_ar : item.name_en,
|
|
price: parseFloat(item.price),
|
|
qty: 1,
|
|
item_note: ''
|
|
};
|
|
}
|
|
renderInvoice();
|
|
}
|
|
|
|
function changeItemName(sku, newName) {
|
|
if (!invoiceItems[sku]) {
|
|
return;
|
|
}
|
|
const fallbackName = '<?= current_lang() ?>' === 'ar'
|
|
? (catalogData[sku].name_ar || catalogData[sku].name_en || sku)
|
|
: (catalogData[sku].name_en || catalogData[sku].name_ar || sku);
|
|
const nextName = String(newName || '').trim();
|
|
invoiceItems[sku].name = nextName !== '' ? nextName : fallbackName;
|
|
renderInvoice();
|
|
}
|
|
|
|
function changeItemPrice(sku, newPrice) {
|
|
if (!invoiceItems[sku]) {
|
|
return;
|
|
}
|
|
const parsed = parseFloat(newPrice);
|
|
invoiceItems[sku].price = Number.isFinite(parsed) && parsed >= 0
|
|
? Math.round(parsed * 1000) / 1000
|
|
: (parseFloat(catalogData[sku].price) || 0);
|
|
renderInvoice();
|
|
}
|
|
|
|
function changeItemNoteValue(sku, newNote) {
|
|
if (!invoiceItems[sku]) {
|
|
return;
|
|
}
|
|
invoiceItems[sku].item_note = String(newNote ?? '');
|
|
cartJson.value = JSON.stringify(Object.keys(invoiceItems).map(currentSku => {
|
|
const currentItem = invoiceItems[currentSku];
|
|
return {
|
|
sku: currentItem.sku,
|
|
name: currentItem.name,
|
|
price: currentItem.price,
|
|
qty: currentItem.qty,
|
|
item_note: String(currentItem.item_note ?? '')
|
|
};
|
|
}));
|
|
}
|
|
|
|
function changeQty(sku, newQty) {
|
|
const qty = parseInt(newQty);
|
|
if (isNaN(qty) || qty < 1) {
|
|
delete invoiceItems[sku];
|
|
} else {
|
|
invoiceItems[sku].qty = qty;
|
|
}
|
|
renderInvoice();
|
|
}
|
|
|
|
function removeItem(sku) {
|
|
delete invoiceItems[sku];
|
|
renderInvoice();
|
|
}
|
|
|
|
function escapeHtml(value) {
|
|
return String(value ?? '').replace(/[&<>"']/g, function(char) {
|
|
return ({'&': '&', '<': '<', '>': '>', '"': '"', "'": '''})[char] || char;
|
|
});
|
|
}
|
|
|
|
function renderInvoice() {
|
|
const skus = Object.keys(invoiceItems);
|
|
if (skus.length === 0) {
|
|
tbody.innerHTML = '';
|
|
tbody.appendChild(emptyRow);
|
|
updateTotals(0, 0);
|
|
cartJson.value = '[]';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = '';
|
|
let totalAmount = 0;
|
|
let totalVat = 0;
|
|
const cartData = [];
|
|
|
|
skus.forEach(sku => {
|
|
const item = invoiceItems[sku];
|
|
const lineTotal = item.qty * item.price;
|
|
|
|
const vatPercent = <?= json_encode((float) $globalVatPercent) ?>;
|
|
const itemVat = lineTotal * (vatPercent / 100);
|
|
totalVat += itemVat;
|
|
|
|
totalAmount += lineTotal;
|
|
cartData.push({ sku: item.sku, name: item.name, price: item.price, qty: item.qty, item_note: String(item.item_note || '') });
|
|
|
|
const safeSku = escapeHtml(item.sku);
|
|
const safeName = escapeHtml(item.name);
|
|
const safeItemNote = escapeHtml(item.item_note || '');
|
|
const itemNoteHtml = showItemNotes ? `
|
|
<input type="text" class="form-control form-control-sm line-input mt-2" value="${safeItemNote}" oninput="changeItemNoteValue('${sku}', this.value)" placeholder="${escapeHtml(itemNotePlaceholder)}">
|
|
<div class="text-muted small mt-1">${escapeHtml(itemNoteHelper)}</div>
|
|
` : '';
|
|
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>
|
|
<input type="text" class="form-control form-control-sm line-input fw-medium mb-2" value="${safeName}" onchange="changeItemName('${sku}', this.value)" onkeyup="if(event.key==='Enter') changeItemName('${sku}', this.value)">
|
|
${itemNoteHtml}
|
|
<div class="text-muted small mt-2">SKU: ${safeSku}</div>
|
|
</td>
|
|
<td class="text-center align-middle">
|
|
<input type="number" class="form-control form-control-sm text-center line-input line-price-input mx-auto" min="0" step="0.001" value="${item.price.toFixed(3)}" onchange="changeItemPrice('${sku}', this.value)" onkeyup="if(event.key==='Enter') changeItemPrice('${sku}', this.value)">
|
|
</td>
|
|
<td class="text-center align-middle">
|
|
<input type="number" class="qty-control mx-auto fw-medium" min="1" value="${item.qty}" onchange="changeQty('${sku}', this.value)" onkeyup="if(event.key==='Enter') changeQty('${sku}', this.value)">
|
|
</td>
|
|
<td class="text-center fw-semibold text-dark align-middle">${lineTotal.toFixed(3)}</td>
|
|
<td class="text-center align-middle">
|
|
<button type="button" class="btn-remove mx-auto" onclick="removeItem('${sku}')" title="<?= h(tr('إزالة', 'Remove')) ?>">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
|
|
updateTotals(totalAmount, totalVat);
|
|
cartJson.value = JSON.stringify(cartData);
|
|
}
|
|
|
|
function formatMoney(value) {
|
|
return value.toFixed(3) + currencySuffix;
|
|
}
|
|
|
|
function updatePaymentAmountHint() {
|
|
const paymentAmountField = document.getElementById('payment_amount');
|
|
const paymentAmountHint = document.getElementById('paymentAmountHint');
|
|
const displayPaidAmountLive = document.getElementById('displayPaidAmountLive');
|
|
const displayDueAmountLive = document.getElementById('displayDueAmountLive');
|
|
if (!paymentAmountField || !paymentAmountHint) {
|
|
return;
|
|
}
|
|
const entered = Math.max(0, parseFloat(paymentAmountField.value || '0') || 0);
|
|
const paid = Math.min(entered, currentInvoiceTotal);
|
|
const due = Math.max(0, currentInvoiceTotal - paid);
|
|
paymentAmountHint.innerText = partialPaymentText + ' ' + formatMoney(due);
|
|
if (displayPaidAmountLive) {
|
|
displayPaidAmountLive.innerText = formatMoney(paid);
|
|
}
|
|
if (displayDueAmountLive) {
|
|
displayDueAmountLive.innerText = formatMoney(due);
|
|
}
|
|
}
|
|
|
|
function syncPaymentAmount(force = false) {
|
|
const paymentMethodField = document.querySelector('select[name="payment_method"]');
|
|
const paymentAmountField = document.getElementById('payment_amount');
|
|
if (!paymentMethodField || !paymentAmountField) {
|
|
return;
|
|
}
|
|
const isManual = paymentAmountField.dataset.manual === '1';
|
|
if (force || !isManual) {
|
|
const defaultAmount = paymentMethodField.value === 'pay_later' ? 0 : currentInvoiceTotal;
|
|
paymentAmountField.value = defaultAmount.toFixed(3);
|
|
paymentAmountField.dataset.manual = '0';
|
|
}
|
|
updatePaymentAmountHint();
|
|
}
|
|
|
|
function updateTotals(total, vat) {
|
|
const subtotal = total;
|
|
const finalTotal = subtotal + vat;
|
|
currentInvoiceTotal = finalTotal;
|
|
document.getElementById('displaySubtotal').innerText = subtotal.toFixed(3);
|
|
document.getElementById('displayVat').innerText = vat.toFixed(3);
|
|
document.getElementById('displayTotal').innerText = finalTotal.toFixed(3) + currencySuffix;
|
|
syncPaymentAmount();
|
|
}
|
|
|
|
const paymentMethodField = document.querySelector('select[name="payment_method"]');
|
|
const paymentAmountField = document.getElementById('payment_amount');
|
|
if (paymentMethodField && paymentAmountField) {
|
|
if (paymentAmountField.value !== '') {
|
|
paymentAmountField.dataset.manual = '1';
|
|
updatePaymentAmountHint();
|
|
}
|
|
paymentMethodField.addEventListener('change', () => syncPaymentAmount());
|
|
paymentAmountField.addEventListener('input', () => {
|
|
paymentAmountField.dataset.manual = '1';
|
|
updatePaymentAmountHint();
|
|
});
|
|
}
|
|
|
|
// Intercept form submission to check if items exist
|
|
const isEidOrderForm = <?= $isEidOrder ? 'true' : 'false' ?>;
|
|
document.getElementById('smart-sale-form').addEventListener('submit', function(e) {
|
|
const paymentMethod = document.querySelector('select[name="payment_method"]').value;
|
|
const saleStatus = document.querySelector('select[name="sale_status"]').value;
|
|
const customerId = document.getElementById('formCustomerId').value;
|
|
const paymentAmount = Math.max(0, parseFloat(document.getElementById('payment_amount').value || '0') || 0);
|
|
const deliveryDateField = document.getElementById('delivery_date');
|
|
if (Object.keys(invoiceItems).length === 0) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('الرجاء إضافة أصناف للفاتورة أولاً.', 'Please add items to the invoice first.')) ?>'});
|
|
} else if (saleStatus === 'order' && !customerId) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('يجب اختيار عميل للطلب المسبق.', 'You must select a customer for a pre-order.')) ?>'});
|
|
} else if (isEidOrderForm && (!deliveryDateField || !deliveryDateField.value)) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('حدد تاريخ التسليم لطلب العيد.', 'Please choose a delivery date for the Eid order.')) ?>'});
|
|
} else if (paymentAmount > currentInvoiceTotal + 0.0005) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('المبلغ المدفوع لا يمكن أن يتجاوز إجمالي الفاتورة.', 'Paid amount cannot exceed the invoice total.')) ?>'});
|
|
} else if (paymentMethod === 'pay_later' && !customerId && paymentAmount < currentInvoiceTotal) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('يجب اختيار عميل مسجل للدفع الآجل.', 'You must select a registered customer for pay later.')) ?>'});
|
|
} else if (paymentAmount < currentInvoiceTotal && !customerId) {
|
|
e.preventDefault();
|
|
Swal.fire({icon: 'warning', text: '<?= h(tr('يجب اختيار عميل مسجل عند وجود مبلغ متبقٍ.', 'Select a registered customer when there is a remaining balance.')) ?>'});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<?php require __DIR__ . '/footer.php'; ?>
|