482 lines
23 KiB
PHP
482 lines
23 KiB
PHP
<?php
|
|
require_once 'includes/app.php';
|
|
$user = require_permission('debts', 'show');
|
|
|
|
$activeNav = 'debts';
|
|
$pageTitle = tr('الديون والفواتير الآجلة', 'Debts & Unpaid Bills');
|
|
$pdo = db();
|
|
$debtsLoadError = '';
|
|
$unpaidSales = [];
|
|
$debtsByCustomer = [];
|
|
$customerNameFilter = trim((string) ($_GET['customer_name'] ?? ''));
|
|
$phoneFilter = trim((string) ($_GET['phone'] ?? ''));
|
|
$dateFrom = trim((string) ($_GET['date_from'] ?? ''));
|
|
$dateTo = trim((string) ($_GET['date_to'] ?? ''));
|
|
$hasFilters = $customerNameFilter !== '' || $phoneFilter !== '' || $dateFrom !== '' || $dateTo !== '';
|
|
|
|
// Handle legacy mark-as-paid shortcut
|
|
if (isset($_GET['mark_paid'])) {
|
|
$id = (int) $_GET['mark_paid'];
|
|
try {
|
|
$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);
|
|
}
|
|
}
|
|
set_flash('success', tr('تم استلام المبلغ بنجاح.', 'Payment received successfully.'));
|
|
} catch (Throwable $e) {
|
|
set_flash('danger', tr('خطأ أثناء التحديث.', 'Error updating.'));
|
|
}
|
|
redirect_to('debts.php');
|
|
}
|
|
|
|
try {
|
|
$salesColumns = [];
|
|
foreach ($pdo->query('SHOW COLUMNS FROM sales_orders')->fetchAll(PDO::FETCH_ASSOC) as $column) {
|
|
$salesColumns[$column['Field']] = true;
|
|
}
|
|
|
|
$hasCustomersTable = false;
|
|
$customerColumns = [];
|
|
$customersTable = $pdo->query("SHOW TABLES LIKE 'customers'");
|
|
if ($customersTable && $customersTable->fetchColumn()) {
|
|
$hasCustomersTable = true;
|
|
foreach ($pdo->query('SHOW COLUMNS FROM customers')->fetchAll(PDO::FETCH_ASSOC) as $column) {
|
|
$customerColumns[$column['Field']] = true;
|
|
}
|
|
}
|
|
|
|
$selectParts = [
|
|
's.id',
|
|
's.receipt_no',
|
|
's.sale_date',
|
|
's.total_amount',
|
|
's.payment_status',
|
|
'COALESCE(s.paid_amount, 0) AS paid_amount',
|
|
'COALESCE(s.due_amount, s.total_amount) AS due_amount',
|
|
isset($salesColumns['customer_id']) ? 's.customer_id' : 'NULL AS customer_id',
|
|
isset($salesColumns['customer_name']) ? 's.customer_name' : 'NULL AS customer_name',
|
|
isset($salesColumns['status']) ? "COALESCE(s.status, 'completed') AS status" : "'completed' AS status",
|
|
'NULL AS c_name',
|
|
'NULL AS c_phone',
|
|
];
|
|
|
|
$joinSql = '';
|
|
if ($hasCustomersTable && isset($salesColumns['customer_id']) && isset($customerColumns['id'])) {
|
|
$joinSql = ' LEFT JOIN customers c ON s.customer_id = c.id ';
|
|
if (isset($customerColumns['name'])) {
|
|
$selectParts[10] = 'c.name AS c_name';
|
|
}
|
|
if (isset($customerColumns['phone'])) {
|
|
$selectParts[11] = 'c.phone AS c_phone';
|
|
}
|
|
}
|
|
|
|
$params = [];
|
|
$whereParts = [];
|
|
if (isset($salesColumns['payment_status'])) {
|
|
$whereParts[] = "s.payment_status IN ('unpaid', 'partial')";
|
|
} elseif (isset($salesColumns['payment_method'])) {
|
|
$whereParts[] = "s.payment_method = 'pay_later'";
|
|
} else {
|
|
$whereParts[] = '1 = 0';
|
|
}
|
|
|
|
if ($customerNameFilter !== '') {
|
|
$nameConditions = [];
|
|
if ($hasCustomersTable && isset($customerColumns['name'])) {
|
|
$nameConditions[] = 'c.name LIKE :customer_name_customer';
|
|
$params[':customer_name_customer'] = '%' . $customerNameFilter . '%';
|
|
}
|
|
if (isset($salesColumns['customer_name'])) {
|
|
$nameConditions[] = 's.customer_name LIKE :customer_name_sale';
|
|
$params[':customer_name_sale'] = '%' . $customerNameFilter . '%';
|
|
}
|
|
if ($nameConditions !== []) {
|
|
$whereParts[] = '(' . implode(' OR ', $nameConditions) . ')';
|
|
}
|
|
}
|
|
|
|
if ($phoneFilter !== '') {
|
|
$rawDigits = phone_digits($phoneFilter);
|
|
$normalizedPhone = normalize_oman_phone($phoneFilter);
|
|
$phoneVariants = [];
|
|
if ($rawDigits !== '') {
|
|
$phoneVariants[] = $rawDigits;
|
|
}
|
|
if ($normalizedPhone !== '') {
|
|
$phoneVariants[] = $normalizedPhone;
|
|
$phoneVariants[] = '0' . $normalizedPhone;
|
|
$phoneVariants[] = '968' . $normalizedPhone;
|
|
$phoneVariants[] = '00968' . $normalizedPhone;
|
|
}
|
|
$phoneVariants = array_values(array_unique(array_filter($phoneVariants, static fn($value) => $value !== '')));
|
|
|
|
$phoneColumns = [];
|
|
if ($hasCustomersTable && isset($customerColumns['phone'])) {
|
|
$phoneColumns[] = "REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(c.phone, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '')";
|
|
}
|
|
if (isset($salesColumns['customer_name'])) {
|
|
$phoneColumns[] = "REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(s.customer_name, ''), ' ', ''), '+', ''), '-', ''), '(', ''), ')', '')";
|
|
}
|
|
|
|
if ($phoneColumns !== [] && $phoneVariants !== []) {
|
|
$phoneConditions = [];
|
|
foreach ($phoneColumns as $columnIndex => $columnExpression) {
|
|
foreach ($phoneVariants as $variantIndex => $variant) {
|
|
$paramKey = ':phone_' . $columnIndex . '_' . $variantIndex;
|
|
$phoneConditions[] = $columnExpression . ' LIKE ' . $paramKey;
|
|
$params[$paramKey] = '%' . $variant . '%';
|
|
}
|
|
}
|
|
$whereParts[] = '(' . implode(' OR ', $phoneConditions) . ')';
|
|
}
|
|
}
|
|
|
|
if ($dateFrom !== '') {
|
|
$whereParts[] = 'DATE(s.sale_date) >= :date_from';
|
|
$params[':date_from'] = $dateFrom;
|
|
}
|
|
if ($dateTo !== '') {
|
|
$whereParts[] = 'DATE(s.sale_date) <= :date_to';
|
|
$params[':date_to'] = $dateTo;
|
|
}
|
|
|
|
$whereSql = ' WHERE ' . implode(' AND ', $whereParts);
|
|
$sqlUnpaid = 'SELECT ' . implode(', ', $selectParts)
|
|
. ' FROM sales_orders s'
|
|
. $joinSql
|
|
. $whereSql
|
|
. ' ORDER BY s.sale_date DESC';
|
|
$stmtUnpaid = $pdo->prepare($sqlUnpaid);
|
|
foreach ($params as $key => $value) {
|
|
$stmtUnpaid->bindValue($key, $value);
|
|
}
|
|
$stmtUnpaid->execute();
|
|
$unpaidSales = $stmtUnpaid->fetchAll(PDO::FETCH_ASSOC);
|
|
} catch (Throwable $e) {
|
|
$debtsLoadError = tr(
|
|
'تعذر تحميل صفحة الديون بسبب اختلاف في هيكل قاعدة البيانات. احفظ التعديلات ثم أنشئ نسخة جديدة وأعد التحديث.',
|
|
'The debts page could not load because the deployed database schema is older than the current code. Save these changes, create a new version, then refresh the page.'
|
|
);
|
|
}
|
|
|
|
$extractCustomerContact = static function (array $sale): array {
|
|
$sourceName = trim((string) ($sale['customer_name'] ?? ''));
|
|
$displayName = trim((string) ($sale['c_name'] ?? ''));
|
|
if ($displayName === '') {
|
|
$displayName = $sourceName;
|
|
}
|
|
|
|
$displayPhone = trim((string) ($sale['c_phone'] ?? ''));
|
|
if ($displayPhone === '' && str_contains($sourceName, ' - ')) {
|
|
$parts = explode(' - ', $sourceName);
|
|
$lastPart = trim((string) end($parts));
|
|
if (preg_match('/^[0-9+\s]+$/', $lastPart)) {
|
|
$displayPhone = $lastPart;
|
|
array_pop($parts);
|
|
if ($displayName === '' || $displayName === $sourceName) {
|
|
$displayName = trim(implode(' - ', $parts));
|
|
}
|
|
}
|
|
}
|
|
|
|
$displayPhone = phone_display($displayPhone);
|
|
if ($displayName === '') {
|
|
$displayName = tr('عميل غير معروف', 'Unknown Customer');
|
|
}
|
|
|
|
return [
|
|
'name' => $displayName,
|
|
'phone' => $displayPhone,
|
|
];
|
|
};
|
|
|
|
// Aggregate by customer
|
|
foreach ($unpaidSales as $sale) {
|
|
$customerContact = $extractCustomerContact($sale);
|
|
$cId = $sale['customer_id'] ?? 'unknown';
|
|
if (!isset($debtsByCustomer[$cId])) {
|
|
$debtsByCustomer[$cId] = [
|
|
'name' => $customerContact['name'],
|
|
'phone' => $customerContact['phone'],
|
|
'total' => 0.0,
|
|
'open_invoices' => 0,
|
|
'partial_invoices' => 0,
|
|
];
|
|
}
|
|
$saleSummary = sale_payment_summary($sale);
|
|
$debtsByCustomer[$cId]['total'] += (float) $saleSummary['due_amount'];
|
|
$debtsByCustomer[$cId]['open_invoices'] += 1;
|
|
if ($saleSummary['payment_status'] === 'partial') {
|
|
$debtsByCustomer[$cId]['partial_invoices'] += 1;
|
|
}
|
|
}
|
|
|
|
// Sort by highest debt
|
|
uasort($debtsByCustomer, fn($a, $b) => $b['total'] <=> $a['total']);
|
|
|
|
require_once 'includes/header.php';
|
|
?>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="h3 mb-0 text-gray-800"><?= h($pageTitle) ?></h1>
|
|
</div>
|
|
|
|
<?php if ($debtsLoadError !== ''): ?>
|
|
<div class="alert alert-warning" role="alert">
|
|
<?= h($debtsLoadError) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card shadow-sm border-0 mb-4">
|
|
<div class="card-body">
|
|
<form method="GET" action="debts.php" class="row g-3 align-items-end">
|
|
<input type="hidden" name="lang" value="<?= h(current_lang()) ?>">
|
|
<div class="col-12 col-md-6 col-xl-3">
|
|
<label class="form-label mb-1" for="debts-customer-name"><?= h(tr('اسم العميل', 'Customer name')) ?></label>
|
|
<input
|
|
id="debts-customer-name"
|
|
type="text"
|
|
name="customer_name"
|
|
class="form-control"
|
|
value="<?= h($customerNameFilter) ?>"
|
|
placeholder="<?= h(tr('ابحث باسم العميل', 'Search by customer name')) ?>"
|
|
>
|
|
</div>
|
|
<div class="col-12 col-md-6 col-xl-3">
|
|
<label class="form-label mb-1" for="debts-phone"><?= h(tr('رقم الهاتف', 'Phone number')) ?></label>
|
|
<input
|
|
id="debts-phone"
|
|
type="text"
|
|
name="phone"
|
|
class="form-control"
|
|
value="<?= h($phoneFilter) ?>"
|
|
placeholder="<?= h(tr('ابحث برقم الهاتف', 'Search by phone number')) ?>"
|
|
dir="ltr"
|
|
>
|
|
</div>
|
|
<div class="col-12 col-md-6 col-xl-2">
|
|
<label class="form-label mb-1" for="debts-date-from"><?= h(tr('من تاريخ', 'From date')) ?></label>
|
|
<input id="debts-date-from" type="date" name="date_from" class="form-control" value="<?= h($dateFrom) ?>">
|
|
</div>
|
|
<div class="col-12 col-md-6 col-xl-2">
|
|
<label class="form-label mb-1" for="debts-date-to"><?= h(tr('إلى تاريخ', 'To date')) ?></label>
|
|
<input id="debts-date-to" type="date" name="date_to" class="form-control" value="<?= h($dateTo) ?>">
|
|
</div>
|
|
<div class="col-12 col-xl-2 d-flex gap-2">
|
|
<button type="submit" class="btn btn-dark flex-fill">
|
|
<i class="bi bi-funnel me-1"></i><?= h(tr('تطبيق', 'Apply')) ?>
|
|
</button>
|
|
<a class="btn btn-outline-secondary flex-fill" href="<?= h(url_for('debts.php')) ?>">
|
|
<?= h(tr('إعادة ضبط', 'Reset')) ?>
|
|
</a>
|
|
</div>
|
|
<?php if ($hasFilters): ?>
|
|
<div class="col-12">
|
|
<div class="small text-muted">
|
|
<i class="bi bi-info-circle me-1"></i><?= h(tr('يتم الآن عرض الديون المطابقة للفلاتر المحددة فقط.', 'Showing only debts that match the selected filters.')) ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Debts by Customer -->
|
|
<div class="col-lg-3 mb-4">
|
|
<div class="card shadow-sm border-0 h-100">
|
|
<div class="card-header bg-white border-bottom-0 pt-4 pb-0">
|
|
<h6 class="m-0 font-weight-bold text-primary"><i class="bi bi-people"></i> <?= h(tr('الديون حسب العميل', 'Debts by Customer')) ?></h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<?php if (empty($debtsByCustomer)): ?>
|
|
<div class="text-center text-muted py-4"><?= h($hasFilters ? tr('لا توجد ديون مطابقة للفلاتر المحددة.', 'No debts match the selected filters.') : tr('لا توجد ديون مسجلة.', 'No debts recorded.')) ?></div>
|
|
<?php else: ?>
|
|
<ul class="list-group list-group-flush">
|
|
<?php foreach ($debtsByCustomer as $debt): ?>
|
|
<li class="list-group-item d-flex justify-content-between align-items-center px-0">
|
|
<div>
|
|
<strong><?= h($debt['name']) ?></strong>
|
|
<?php if ($debt['phone']): ?>
|
|
<div class="small text-muted" dir="ltr"><?= h($debt['phone']) ?></div>
|
|
<?php endif; ?>
|
|
<div class="small text-muted"><?= h($debt['open_invoices']) ?> <?= h(tr('فواتير مفتوحة', 'open invoices')) ?></div>
|
|
<?php if ($debt['partial_invoices'] > 0): ?>
|
|
<div class="small text-warning"><?= h($debt['partial_invoices']) ?> <?= h(tr('منها دفعات جزئية', 'partially paid')) ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<span class="badge bg-danger rounded-pill fs-6"><?= h(currency($debt['total'])) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Unpaid Invoices -->
|
|
<div class="col-lg-9 mb-4">
|
|
<div class="card shadow-sm border-0 h-100">
|
|
<div class="card-header bg-white border-bottom-0 pt-4 pb-0">
|
|
<h6 class="m-0 font-weight-bold text-primary"><i class="bi bi-receipt"></i> <?= h(tr('الفواتير غير المدفوعة والجزئية', 'Unpaid & Partial Invoices')) ?></h6>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th><?= h(tr('رقم الفاتورة', 'Receipt No')) ?></th>
|
|
<th><?= h(tr('العميل', 'Customer')) ?></th>
|
|
<th><?= h(tr('الهاتف', 'Phone')) ?></th>
|
|
<th><?= h(tr('التاريخ', 'Date')) ?></th>
|
|
<th><?= h(tr('الإجمالي', 'Total')) ?></th>
|
|
<th><?= h(tr('المدفوع', 'Paid')) ?></th>
|
|
<th><?= h(tr('المتبقي', 'Due')) ?></th>
|
|
<th><?= h(tr('الحالة', 'Status')) ?></th>
|
|
<th><?= h(tr('الإجراء', 'Action')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($unpaidSales)): ?>
|
|
<tr>
|
|
<td colspan="9" class="text-center py-4 text-muted"><?= h($hasFilters ? tr('لا توجد فواتير مطابقة للفلاتر المحددة.', 'No invoices match the selected filters.') : tr('لا توجد فواتير غير مدفوعة أو جزئية.', 'No unpaid or partial invoices.')) ?></td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($unpaidSales as $sale): ?>
|
|
<?php
|
|
$paymentSummary = sale_payment_summary($sale);
|
|
$customerContact = $extractCustomerContact($sale);
|
|
?>
|
|
<tr>
|
|
<td>
|
|
<a href="<?= h(url_for('sale.php', ['id' => $sale['id']])) ?>" class="fw-bold text-decoration-none">
|
|
<?= h($sale['receipt_no']) ?>
|
|
</a>
|
|
</td>
|
|
<td><?= h($customerContact['name']) ?></td>
|
|
<td dir="ltr"><?= h($customerContact['phone'] !== '' ? $customerContact['phone'] : '-') ?></td>
|
|
<td><?= h(date('Y-m-d', strtotime((string) $sale['sale_date']))) ?></td>
|
|
<td class="fw-semibold"><?= h(currency((float) $sale['total_amount'])) ?></td>
|
|
<td class="text-primary"><?= h(currency((float) $paymentSummary['paid_amount'])) ?></td>
|
|
<td class="fw-bold text-danger"><?= h(currency((float) $paymentSummary['due_amount'])) ?></td>
|
|
<td>
|
|
<span class="badge <?= h(payment_status_badge_class($paymentSummary['payment_status'])) ?>"><?= h(payment_status_label($paymentSummary['payment_status'])) ?></span>
|
|
</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-success rounded-pill px-3" 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' ?>)">
|
|
<i class="bi bi-cash-coin"></i> <?= h(tr('استلام دفعة', 'Receive Payment')) ?>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<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.')) ?>' });
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<?php require_once 'includes/footer.php'; ?>
|