39728-vm/debts.php
2026-04-20 17:20:25 +00:00

216 lines
9.4 KiB
PHP

<?php
require_once 'includes/app.php';
$user = require_auth();
$activeNav = 'debts';
$pageTitle = tr('الديون والفواتير الآجلة', 'Debts & Unpaid Bills');
$pdo = db();
$debtsLoadError = '';
$unpaidSales = [];
$debtsByCustomer = [];
// Handle Mark as Paid
if (isset($_GET['mark_paid'])) {
$id = (int)$_GET['mark_paid'];
try {
$pdo->prepare("UPDATE sales_orders SET payment_status = 'paid', status = 'completed' WHERE id = ?")->execute([$id]);
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',
isset($salesColumns['customer_id']) ? 's.customer_id' : 'NULL AS customer_id',
isset($salesColumns['customer_name']) ? 's.customer_name' : 'NULL AS customer_name',
'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[6] = 'c.name AS c_name';
}
if (isset($customerColumns['phone'])) {
$selectParts[7] = 'c.phone AS c_phone';
}
}
if (isset($salesColumns['payment_status'])) {
$whereSql = " WHERE s.payment_status = 'unpaid'";
} elseif (isset($salesColumns['payment_method'])) {
$whereSql = " WHERE s.payment_method = 'pay_later'";
} else {
$whereSql = ' WHERE 1 = 0';
}
$sqlUnpaid = 'SELECT ' . implode(', ', $selectParts)
. ' FROM sales_orders s'
. $joinSql
. $whereSql
. ' ORDER BY s.sale_date DESC';
$stmtUnpaid = $pdo->query($sqlUnpaid);
$unpaidSales = $stmtUnpaid ? $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.'
);
}
// Aggregate by customer
foreach ($unpaidSales as $sale) {
$cId = $sale['customer_id'] ?? 'unknown';
if (!isset($debtsByCustomer[$cId])) {
$debtsByCustomer[$cId] = [
'name' => $sale['c_name'] ?: $sale['customer_name'] ?: tr('عميل غير معروف', 'Unknown Customer'),
'phone' => $sale['c_phone'] ?: '',
'total' => 0.0,
'count' => 0
];
}
$debtsByCustomer[$cId]['total'] += (float)$sale['total_amount'];
$debtsByCustomer[$cId]['count'] += 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="row">
<!-- Debts by Customer -->
<div class="col-lg-4 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(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"><?= h($debt['phone']) ?></div>
<?php endif; ?>
<div class="small text-muted"><?= h($debt['count']) ?> <?= h(tr('فواتير', 'bills')) ?></div>
</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-8 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 Bills')) ?></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('التاريخ', 'Date')) ?></th>
<th><?= h(tr('المبلغ', 'Amount')) ?></th>
<th><?= h(tr('الإجراء', 'Action')) ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($unpaidSales)): ?>
<tr>
<td colspan="5" class="text-center py-4 text-muted"><?= h(tr('لا توجد فواتير غير مدفوعة.', 'No unpaid bills.')) ?></td>
</tr>
<?php else: ?>
<?php foreach ($unpaidSales as $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($sale['c_name'] ?: $sale['customer_name'] ?: '-') ?>
</td>
<td><?= h(date('Y-m-d', strtotime((string)$sale['sale_date']))) ?></td>
<td class="fw-bold text-danger"><?= h(currency((float)$sale['total_amount'])) ?></td>
<td>
<button class="btn btn-sm btn-outline-success rounded-pill px-3" onclick="markPaid(<?= $sale['id'] ?>)">
<i class="bi bi-cash-coin"></i> <?= h(tr('استلام', 'Receive')) ?>
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
function markPaid(id) {
Swal.fire({
title: "<?= h(tr('تأكيد استلام المبلغ؟', 'Confirm payment receipt?')) ?>",
text: "<?= h(tr('سيتم تحويل هذه الفاتورة إلى مدفوعة.', 'This bill will be marked as paid.')) ?>",
icon: "question",
showCancelButton: true,
confirmButtonColor: "#198754",
confirmButtonText: "<?= h(tr('نعم، تم الاستلام', 'Yes, Received')) ?>",
cancelButtonText: "<?= h(tr('إلغاء', 'Cancel')) ?>"
}).then((result) => {
if (result.isConfirmed) {
window.location.href = "debts.php?mark_paid=" + id;
}
});
}
</script>
<?php require_once 'includes/footer.php'; ?>