39728-vm/sales.php
2026-05-05 04:18:09 +00:00

524 lines
27 KiB
PHP

<?php
require_once __DIR__ . '/includes/app.php';
$user = require_permission('sales', 'show');
$mode = isset($_GET['mode']) && in_array($_GET['mode'], ['pos', 'normal'], true) ? $_GET['mode'] : null;
$branch = isset($_GET['branch']) && array_key_exists($_GET['branch'], branches()) ? $_GET['branch'] : null;
$search = trim((string) ($_GET['q'] ?? ''));
$statusFilter = trim((string) ($_GET['status'] ?? ''));
$paymentStatus = trim((string) ($_GET['payment_status'] ?? ''));
$deliveryOptions = eid_delivery_status_options();
$deliveryStatus = trim((string) ($_GET['delivery_status'] ?? ''));
$dateFrom = trim((string) ($_GET['date_from'] ?? ''));
$dateTo = trim((string) ($_GET['date_to'] ?? ''));
$legacyPaymentStatuses = ['paid', 'partial', 'unpaid'];
if ($paymentStatus === '' && in_array($statusFilter, $legacyPaymentStatuses, true)) {
$paymentStatus = $statusFilter;
$statusFilter = '';
}
if (!in_array($statusFilter, ['', 'order', 'completed'], true)) {
$statusFilter = '';
}
if (!in_array($paymentStatus, array_merge([''], $legacyPaymentStatuses), true)) {
$paymentStatus = '';
}
if ($deliveryStatus !== '' && !array_key_exists($deliveryStatus, $deliveryOptions)) {
$deliveryStatus = '';
}
$allowedBranches = $user && $user['role'] !== 'owner' ? get_user_branches($user) : array_keys(branches());
$activeNav = $statusFilter === 'order' ? 'sales_orders' : 'sales';
$pageTitle = $statusFilter === 'order' ? tr('الطلبات', 'Orders') : tr('المبيعات', 'Sales Ledger');
$canDeleteSales = $user['role'] === 'owner' || has_permission('sales', 'del');
if (isset($_GET['mark_paid']) && is_numeric($_GET['mark_paid'])) {
try {
$id = (int) $_GET['mark_paid'];
$sale = fetch_sale($id);
if ($sale) {
$summary = sale_payment_summary($sale);
if ($summary['due_amount'] > 0.0005) {
apply_sale_payment($id, $summary['due_amount'], true);
}
}
} catch (Throwable $e) {}
$redirect = $_GET['redirect'] ?? 'sales.php';
header('Location: ' . $redirect);
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_sale') {
if (!$canDeleteSales) {
set_flash('danger', tr('ليس لديك صلاحية حذف الفواتير.', 'You do not have permission to delete invoices.'));
redirect_to('sales.php', $_GET);
}
$id = (int) ($_POST['id'] ?? 0);
try {
ensure_sales_table();
$sale = fetch_sale($id);
if (!$sale) {
set_flash('warning', tr('الفاتورة غير موجودة.', 'Invoice was not found.'));
} elseif ($user['role'] !== 'owner' && !in_array((string) ($sale['branch_code'] ?? ''), $allowedBranches, true)) {
set_flash('danger', tr('لا يمكنك حذف هذه الفاتورة.', 'You cannot delete this invoice.'));
} else {
$stmt = db()->prepare('DELETE FROM sales_orders WHERE id = :id');
$stmt->execute([':id' => $id]);
set_flash('success', tr('تم حذف الفاتورة نهائياً.', 'Invoice deleted permanently.'));
}
} catch (Throwable $e) {
set_flash('danger', tr('تعذر حذف الفاتورة.', 'Failed to delete invoice.'));
}
redirect_to('sales.php', $_GET);
}
$dbError = null;
$sales = [];
$totalPages = 1;
$page = max(1, (int)($_GET['p'] ?? 1));
$limit = 10;
$offset = ($page - 1) * $limit;
try {
ensure_sales_table();
$params = [];
$where = ' WHERE 1=1 ';
if ($mode) {
$where .= ' AND sale_mode = :sale_mode ';
$params[':sale_mode'] = $mode;
}
if ($branch) {
$where .= ' AND branch_code = :branch_code ';
$params[':branch_code'] = $branch;
}
if ($user && $user['role'] !== 'owner') {
$ubranches = get_user_branches($user);
if (empty($ubranches)) {
$where .= ' AND 1=0 ';
} else {
$namedParams = [];
foreach ($ubranches as $i => $ub) {
$key = ':v_branch_' . $i;
$namedParams[] = $key;
$params[$key] = $ub;
}
$where .= ' AND branch_code IN (' . implode(', ', $namedParams) . ') ';
}
}
if ($search !== '') {
$where .= ' AND (receipt_no LIKE :search OR cashier_name LIKE :search OR customer_name LIKE :search)';
$params[':search'] = "%$search%";
}
if ($paymentStatus !== '') {
$where .= ' AND payment_status = :payment_status ';
$params[':payment_status'] = $paymentStatus;
}
if ($deliveryStatus !== '') {
$where .= ' AND delivery_status = :delivery_status ';
$params[':delivery_status'] = $deliveryStatus;
}
if ($dateFrom !== '') {
$where .= ' AND DATE(sale_date) >= :date_from ';
$params[':date_from'] = $dateFrom;
}
if ($dateTo !== '') {
$where .= ' AND DATE(sale_date) <= :date_to ';
$params[':date_to'] = $dateTo;
}
if ($statusFilter === 'order') {
$where .= " AND status = 'order' ";
} elseif ($statusFilter === 'completed') {
$where .= " AND COALESCE(status, 'completed') = 'completed' ";
} else {
$where .= " AND COALESCE(status, 'completed') <> 'order' ";
}
// Pagination counts
$countSql = 'SELECT COUNT(*) FROM sales_orders' . $where;
$countStmt = db()->prepare($countSql);
foreach ($params as $key => $value) {
$countStmt->bindValue($key, $value);
}
$countStmt->execute();
$total = $countStmt->fetchColumn();
$totalPages = max(1, ceil($total / $limit));
// Fetch Data
$sql = 'SELECT * FROM sales_orders' . $where . ' ORDER BY sale_date DESC LIMIT :limit OFFSET :offset';
$stmt = db()->prepare($sql);
foreach ($params as $key => $value) {
$stmt->bindValue($key, $value);
}
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$sales = $stmt->fetchAll();
} catch (Throwable $e) {
$dbError = $e->getMessage();
}
$queryState = static function (array $extra = []) use ($search, $branch, $mode, $statusFilter, $paymentStatus, $deliveryStatus, $dateFrom, $dateTo): array {
return array_filter(array_merge([
'q' => $search,
'branch' => $branch,
'mode' => $mode,
'status' => $statusFilter,
'payment_status' => $paymentStatus,
'delivery_status' => $deliveryStatus,
'date_from' => $dateFrom,
'date_to' => $dateTo,
], $extra), static fn ($value) => $value !== null && $value !== '');
};
$hasAdvancedFilters = $mode !== null || $paymentStatus !== '' || $branch !== null || $deliveryStatus !== '' || $dateFrom !== '' || $dateTo !== '' || $statusFilter !== '';
require __DIR__ . '/includes/header.php';
?>
<section class="mb-4">
<div class="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-3">
<div>
<h3 class="h5 mb-1"><i class="bi bi-journal-text me-2"></i><?= h($statusFilter === 'order' ? tr('قائمة الطلبات', 'Orders list') : tr('سجل الفواتير', 'Invoice ledger')) ?></h3>
<div class="small text-muted"><?= h($statusFilter === 'order' ? tr('هذه القائمة تعرض طلبات البيع العادي المحفوظة بحالة طلب.', 'This list shows normal sales saved with order status.') : tr('ابحث بصرياً في أحدث المبيعات مع صلاحيات حسب الدور والفرع.', 'Scan the latest sales with role and branch scoping.')) ?></div>
</div>
<div class="d-flex gap-2 flex-wrap">
<a class="btn btn-sm <?= $mode === null ? 'btn-dark' : 'btn-outline-secondary' ?>" href="<?= h(url_for('sales.php', $queryState(['mode' => null, 'p' => null]))) ?>"><?= h(tr('الكل', 'All')) ?></a>
<a class="btn btn-sm <?= $mode === 'pos' ? 'btn-dark' : 'btn-outline-secondary' ?>" href="<?= h(url_for('sales.php', $queryState(['mode' => 'pos', 'p' => null]))) ?>">POS</a>
<a class="btn btn-sm <?= $mode === 'normal' ? 'btn-dark' : 'btn-outline-secondary' ?>" href="<?= h(url_for('sales.php', $queryState(['mode' => 'normal', 'p' => null]))) ?>"><?= h(tr('فاتورة', 'Invoice')) ?></a>
</div>
</div>
<form class="mb-4" method="GET" action="sales.php">
<div class="d-flex justify-content-end align-items-center mb-3">
<details class="eid-advanced-toggle" <?= $hasAdvancedFilters ? 'open' : '' ?>>
<summary class="btn btn-sm btn-outline-secondary">
<i class="bi bi-sliders me-1"></i><?= h(tr('فلاتر إضافية', 'More filters')) ?>
</summary>
<div class="eid-advanced-panel">
<div class="row g-2">
<div class="col-12 col-md-4">
<label class="form-label mb-1" for="sales-mode"><?= h(tr('القناة', 'Channel')) ?></label>
<select id="sales-mode" class="form-select form-select-sm" name="mode">
<option value=""><?= h(tr('الكل', 'All')) ?></option>
<option value="normal" <?= $mode === 'normal' ? 'selected' : '' ?>><?= h(tr('فاتورة', 'Invoice')) ?></option>
<option value="pos" <?= $mode === 'pos' ? 'selected' : '' ?>>POS</option>
</select>
</div>
<div class="col-12 col-md-4">
<label class="form-label mb-1" for="sales-payment-status"><?= h(tr('حالة الدفع', 'Payment')) ?></label>
<select id="sales-payment-status" class="form-select form-select-sm" name="payment_status">
<option value=""><?= h(tr('كل الحالات', 'All statuses')) ?></option>
<option value="paid" <?= $paymentStatus === 'paid' ? 'selected' : '' ?>><?= h(tr('مدفوع', 'Paid')) ?></option>
<option value="partial" <?= $paymentStatus === 'partial' ? 'selected' : '' ?>><?= h(tr('جزئي', 'Partial')) ?></option>
<option value="unpaid" <?= $paymentStatus === 'unpaid' ? 'selected' : '' ?>><?= h(tr('غير مدفوع', 'Unpaid')) ?></option>
</select>
</div>
<div class="col-12 col-md-4">
<label class="form-label mb-1" for="sales-status"><?= h(tr('نوع السجل', 'Record type')) ?></label>
<select id="sales-status" class="form-select form-select-sm" name="status">
<option value=""><?= h(tr('العرض الافتراضي', 'Default view')) ?></option>
<option value="completed" <?= $statusFilter === 'completed' ? 'selected' : '' ?>><?= h(tr('كل الفواتير المكتملة', 'Completed invoices')) ?></option>
<option value="order" <?= $statusFilter === 'order' ? 'selected' : '' ?>><?= h(tr('طلبات الحجز', 'Order reservations')) ?></option>
</select>
</div>
</div>
</div>
</details>
</div>
<div class="row g-3 align-items-end">
<div class="col-12 col-md-3">
<label class="form-label mb-1" for="sales-search"><?= h(tr('بحث سريع', 'Quick search')) ?></label>
<input id="sales-search" type="text" class="form-control form-control-sm" name="q" value="<?= h($search) ?>" placeholder="<?= h(tr('بحث بالإيصال، الكاشير، العميل أو الهاتف...', 'Search receipt, cashier, customer or phone...')) ?>">
</div>
<div class="col-12 col-md-2">
<label class="form-label mb-1" for="sales-branch"><?= h(tr('الفرع', 'Branch')) ?></label>
<select id="sales-branch" class="form-select form-select-sm" name="branch">
<option value=""><?= h(tr('كل الفروع', 'All branches')) ?></option>
<?php foreach (branches() as $branchCode => $branchLabel): ?>
<?php if ($user['role'] !== 'owner' && !in_array($branchCode, $allowedBranches, true)) { continue; } ?>
<option value="<?= h($branchCode) ?>" <?= $branch === $branchCode ? 'selected' : '' ?>><?= h(branch_label($branchCode)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-md-2">
<label class="form-label mb-1" for="sales-delivery-status"><?= h(tr('التجهيز', 'Prep')) ?></label>
<select id="sales-delivery-status" class="form-select form-select-sm" name="delivery_status">
<option value=""><?= h(tr('كل الحالات', 'All statuses')) ?></option>
<?php foreach ($deliveryOptions as $value => $label): ?>
<option value="<?= h($value) ?>" <?= $deliveryStatus === $value ? 'selected' : '' ?>><?= h($label) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-12 col-md-3">
<label class="form-label mb-1">
<?= h($statusFilter === 'order' ? tr('فترة الطلب', 'Order window') : tr('فترة البيع', 'Sale window')) ?>
</label>
<div class="d-flex gap-2">
<input id="sales-date-from" type="date" class="form-control form-control-sm" name="date_from" value="<?= h($dateFrom) ?>" aria-label="<?= h(tr('من تاريخ', 'From date')) ?>">
<input id="sales-date-to" type="date" class="form-control form-control-sm" name="date_to" value="<?= h($dateTo) ?>" aria-label="<?= h(tr('إلى تاريخ', 'To date')) ?>">
</div>
</div>
<div class="col-12 col-md-2 d-flex gap-2">
<button type="submit" class="btn btn-sm btn-dark w-50"><i class="bi bi-funnel me-1"></i><?= h(tr('تطبيق', 'Apply')) ?></button>
<a class="btn btn-sm btn-outline-secondary w-50" href="<?= h(url_for('sales.php', ['status' => $statusFilter])) ?>"><?= h(tr('إعادة ضبط', 'Reset')) ?></a>
</div>
</div>
</form>
<?php if ($dbError): ?>
<div class="alert alert-warning"><?= h($dbError) ?></div>
<?php elseif (!$sales): ?>
<div class="empty-state">
<h4><?= h(tr('لا توجد نتائج', 'No sales found')) ?></h4>
<p><?= h(tr('جرّب إنشاء فاتورة جديدة من صفحة البيع.', 'Try creating a new invoice from the sale page.')) ?></p>
<div class="d-flex gap-2 justify-content-center flex-wrap">
<a class="btn btn-dark" href="<?= h(url_for('pos.php')) ?>">POS</a>
<a class="btn btn-outline-secondary" href="<?= h(url_for('normal_sale.php')) ?>"><?= h(tr('فاتورة', 'Invoice')) ?></a>
</div>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0 text-center">
<thead class="table-light">
<tr>
<th><?= h(tr('الإيصال', 'Receipt')) ?></th>
<th><?= h(tr('الفرع', 'Branch')) ?></th>
<th><?= h(tr('النوع', 'Type')) ?></th>
<th><?= h(tr('الكاشير', 'Cashier')) ?></th>
<th><?= h(tr('العميل', 'Customer')) ?></th>
<th><?= h(tr('الهاتف', 'Phone')) ?></th>
<th><?= h(tr('المجموع', 'Subtotal')) ?></th>
<th><?= h(tr('الضريبة', 'VAT')) ?></th>
<th><?= h(tr('الإجمالي', 'Total')) ?></th>
<th><?= h(tr('المدفوع', 'Paid')) ?></th>
<th><?= h(tr('المتبقي', 'Due')) ?></th>
<th><?= h(tr('الحالة', 'Status')) ?></th>
<th><?= h(tr('التاريخ', 'Date')) ?></th>
<th><?= h(tr('إجراءات', 'Actions')) ?></th>
</tr>
</thead>
<tbody class="border-top-0">
<?php foreach ($sales as $sale): ?>
<?php $paymentSummary = sale_payment_summary($sale); ?>
<tr>
<td>
<div class="fw-semibold"><?= h($sale['receipt_no']) ?></div>
<div class="small text-muted"><?= h((string) $sale['item_count']) ?> <?= h(tr('قطعة', 'items')) ?></div>
</td>
<td><?= h(branch_label((string) $sale['branch_code'])) ?></td>
<td><span class="badge text-bg-light border"><?= h(sale_mode_label((string) $sale['sale_mode'])) ?></span></td>
<td><?= h((string) $sale['cashier_name']) ?></td>
<?php
$rawCustomerName = (string) ($sale['customer_name'] ?: '-');
$displayPhone = '';
if (str_contains($rawCustomerName, ' - ')) {
$parts = explode(' - ', $rawCustomerName);
$lastPart = trim(end($parts));
if (preg_match('/^[0-9+\s]+$/', $lastPart)) {
$displayPhone = $lastPart;
array_pop($parts);
$rawCustomerName = trim(implode(' - ', $parts));
}
}
$displayPhone = ltrim(preg_replace('/[^0-9]/', '', $displayPhone), '0');
if ($displayPhone !== '') {
if (str_starts_with($displayPhone, '968') && strlen($displayPhone) > 8) {
$displayPhone = substr($displayPhone, 3);
}
}
?>
<td><?= h($rawCustomerName) ?></td>
<td dir="ltr"><?= h($displayPhone ?: '-') ?></td>
<td class="text-muted"><?= h(currency((float) $sale['total_amount'] - (float) ($sale['vat_amount'] ?? 0))) ?></td>
<td class="text-muted text-danger"><?= h(currency((float) $sale['vat_amount'])) ?></td>
<td class="fw-bold text-success"><?= h(currency((float) $sale['total_amount'])) ?></td>
<td class="fw-semibold text-primary"><?= h(currency((float) $paymentSummary['paid_amount'])) ?></td>
<td class="fw-semibold <?= $paymentSummary['due_amount'] > 0 ? 'text-danger' : 'text-muted' ?>"><?= h(currency((float) $paymentSummary['due_amount'])) ?></td>
<td>
<span class="badge <?= h(payment_status_badge_class($paymentSummary['payment_status'])) ?> px-3 py-2 rounded-pill">
<?php if ($paymentSummary['payment_status'] === 'partial'): ?>
<i class="bi bi-pie-chart"></i>
<?php elseif ($paymentSummary['payment_status'] === 'unpaid'): ?>
<i class="bi bi-clock-history"></i>
<?php else: ?>
<i class="bi bi-check-circle"></i>
<?php endif; ?>
<?= h(payment_status_label($paymentSummary['payment_status'])) ?>
</span>
<?php if (($sale['status'] ?? 'completed') === 'order'): ?>
<small class="d-block text-muted mt-1"><?= h(tr('طلب حجز', 'Order')) ?></small>
<?php elseif (($sale['payment_method'] ?? '') === 'pay_later'): ?>
<small class="d-block text-muted mt-1"><?= h(tr('دفع آجل', 'Pay Later')) ?></small>
<?php endif; ?>
</td>
<td><?= h(date('Y-m-d H:i', strtotime((string) $sale['sale_date']))) ?></td>
<td class="text-nowrap">
<div class="d-inline-flex align-items-center flex-nowrap gap-1">
<?php if ($paymentSummary['due_amount'] > 0.0005): ?>
<button class="btn btn-sm btn-outline-success rounded-circle shadow-sm" style="width: 30px; height: 30px; padding: 0; line-height: 28px;" onclick="receivePayment(<?= (int) $sale['id'] ?>, <?= json_encode((float) $sale['total_amount']) ?>, <?= json_encode((float) $paymentSummary['paid_amount']) ?>, <?= json_encode((float) $paymentSummary['due_amount']) ?>, <?= ($sale['status'] ?? 'completed') === 'order' ? 'true' : 'false' ?>)" title="<?= h(tr('استلام دفعة', 'Receive Payment')) ?>">
<i class="bi bi-cash-coin"></i>
</button>
<?php endif; ?>
<a class="btn btn-sm btn-light text-primary border rounded-circle shadow-sm" style="width: 30px; height: 30px; padding: 0; line-height: 28px; text-align: center;" href="<?= h(url_for('sale.php', ['id' => $sale['id']])) ?>" title="<?= h(tr('تفاصيل', 'Detail')) ?>">
<i class="bi bi-eye"></i>
</a>
<a class="btn btn-sm btn-outline-secondary rounded-circle shadow-sm" style="width: 30px; height: 30px; padding: 0; line-height: 28px; text-align: center;" href="<?= h(url_for('edit_sale.php', ['id' => $sale['id']])) ?>" title="<?= h(tr('تعديل', 'Edit')) ?>">
<i class="bi bi-pencil"></i>
</a>
<?php if ($canDeleteSales): ?>
<form method="post" action="" class="d-inline-block">
<input type="hidden" name="action" value="delete_sale">
<input type="hidden" name="id" value="<?= h($sale['id']) ?>">
<button type="button" class="btn btn-sm btn-outline-danger rounded-circle shadow-sm" style="width: 30px; height: 30px; padding: 0; line-height: 28px;" onclick="confirmDeleteSale(this.form)" title="<?= h(tr('حذف', 'Delete')) ?>">
<i class="bi bi-trash"></i>
</button>
</form>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($totalPages > 1): ?>
<nav class="mt-4">
<ul class="pagination justify-content-center mb-0">
<?php for($i=1; $i<=$totalPages; $i++): ?>
<li class="page-item <?= $i === $page ? 'active' : '' ?>">
<a class="page-link" href="<?= h(url_for('sales.php', $queryState(['p' => $i]))) ?>"><?= $i ?></a>
</li>
<?php endfor; ?>
</ul>
</nav>
<?php endif; ?>
<?php endif; ?>
</section>
<script>
function formatPaymentPopupAmount(value) {
return Number(value || 0).toFixed(3);
}
async function receivePayment(id, totalAmount, paidAmount, dueAmount, completeOrder = false) {
const popupHtml = `
<div class="text-start">
<div class="row g-2 mb-3">
<div class="col-4">
<div class="border rounded-3 p-2 h-100 bg-light">
<div class="small text-muted"><?= h(tr('إجمالي الفاتورة', 'Total amount')) ?></div>
<div class="fw-bold text-dark">${formatPaymentPopupAmount(totalAmount)}</div>
</div>
</div>
<div class="col-4">
<div class="border rounded-3 p-2 h-100 bg-light">
<div class="small text-muted"><?= h(tr('المدفوع سابقاً', 'Already paid')) ?></div>
<div class="fw-bold text-primary">${formatPaymentPopupAmount(paidAmount)}</div>
</div>
</div>
<div class="col-4">
<div class="border rounded-3 p-2 h-100 bg-light">
<div class="small text-muted"><?= h(tr('المتبقي الحالي', 'Current remaining')) ?></div>
<div class="fw-bold text-danger">${formatPaymentPopupAmount(dueAmount)}</div>
</div>
</div>
</div>
<label for="swal-payment-amount" class="form-label fw-semibold mb-2"><?= h(tr('المبلغ المطلوب دفعه الآن', 'Amount to pay now')) ?></label>
<input id="swal-payment-amount" type="number" class="swal2-input mt-0" min="0.001" step="0.001" max="${formatPaymentPopupAmount(dueAmount)}" value="${formatPaymentPopupAmount(dueAmount)}">
<div class="d-flex justify-content-between align-items-center rounded-3 border px-3 py-2 bg-light mt-3">
<span class="small text-muted"><?= h(tr('المتبقي بعد الدفعة', 'Remaining after payment')) ?></span>
<strong id="swal-payment-remaining" class="text-success">0.000</strong>
</div>
</div>`;
const { isConfirmed, value: paymentAmount } = await Swal.fire({
title: '<?= h(tr('استلام دفعة', 'Receive Payment')) ?>',
html: popupHtml,
showCancelButton: true,
confirmButtonColor: '#198754',
confirmButtonText: '<?= h(tr('حفظ الدفعة', 'Save Payment')) ?>',
cancelButtonText: '<?= h(tr('إلغاء', 'Cancel')) ?>',
focusConfirm: false,
didOpen: () => {
const input = document.getElementById('swal-payment-amount');
const remainingEl = document.getElementById('swal-payment-remaining');
const updateRemaining = () => {
const amount = parseFloat(input.value || '0');
const safeAmount = Number.isFinite(amount) ? amount : 0;
const remaining = Math.max(dueAmount - safeAmount, 0);
remainingEl.textContent = formatPaymentPopupAmount(remaining);
remainingEl.className = remaining > 0.0005 ? 'text-danger' : 'text-success';
};
input.addEventListener('input', updateRemaining);
input.focus();
input.select();
updateRemaining();
},
preConfirm: () => {
const input = document.getElementById('swal-payment-amount');
const amount = parseFloat(input.value || '0');
if (!amount || amount <= 0) {
Swal.showValidationMessage('<?= h(tr('أدخل مبلغاً صحيحاً.', 'Enter a valid amount.')) ?>');
return false;
}
if (amount - dueAmount > 0.0005) {
Swal.showValidationMessage('<?= h(tr('المبلغ لا يمكن أن يتجاوز المتبقي.', 'Amount cannot exceed the due balance.')) ?>');
return false;
}
return formatPaymentPopupAmount(amount);
}
});
if (!isConfirmed || !paymentAmount) {
return;
}
const formData = new FormData();
formData.append('sale_id', String(id));
formData.append('payment_amount', String(paymentAmount));
if (completeOrder) {
formData.append('complete_order', '1');
}
const response = await fetch('api/sales_payment.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
await Swal.fire({ icon: 'success', text: data.message, confirmButtonText: 'OK' });
window.location.reload();
} else {
Swal.fire({ icon: 'error', text: data.error || '<?= h(tr('تعذر تسجيل الدفعة.', 'Could not record the payment.')) ?>' });
}
}
function mockEdit() {
Swal.fire({
title: '<?= h(tr('تعديل (غير متاح)', 'Edit (Disabled)')) ?>',
text: '<?= h(tr('تعديل الفواتير غير متاح لأسباب محاسبية.', 'Invoice editing is disabled for accounting reasons.')) ?>',
icon: 'info',
confirmButtonText: '<?= h(tr('حسناً', 'OK')) ?>'
});
}
function confirmDeleteSale(form) {
Swal.fire({
title: '<?= h(tr('هل أنت متأكد من حذف الفاتورة؟', 'Are you sure you want to delete this invoice?')) ?>',
text: '<?= h(tr('سيتم حذف الفاتورة نهائياً من النظام. استخدم هذا الخيار فقط عند الضرورة.', 'This will permanently delete the invoice from the system. Use this only when necessary.')) ?>',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#dc3545',
cancelButtonColor: '#6c757d',
confirmButtonText: '<?= h(tr('نعم، احذف', 'Yes, delete it!')) ?>',
cancelButtonText: '<?= h(tr('إلغاء', 'Cancel')) ?>'
}).then((result) => {
if (result.isConfirmed) {
form.submit();
}
});
}
</script>
<?php require __DIR__ . '/includes/footer.php'; ?>