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', '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[9] = 'c.name AS c_name'; } if (isset($customerColumns['phone'])) { $selectParts[10] = 'c.phone AS c_phone'; } } if (isset($salesColumns['payment_status'])) { $whereSql = " WHERE s.payment_status IN ('unpaid', 'partial')"; } 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, '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'; ?>
| = h(tr('رقم الفاتورة', 'Receipt No')) ?> | = h(tr('العميل', 'Customer')) ?> | = h(tr('الهاتف', 'Phone')) ?> | = h(tr('التاريخ', 'Date')) ?> | = h(tr('الإجمالي', 'Total')) ?> | = h(tr('المدفوع', 'Paid')) ?> | = h(tr('المتبقي', 'Due')) ?> | = h(tr('الحالة', 'Status')) ?> | = h(tr('الإجراء', 'Action')) ?> |
|---|---|---|---|---|---|---|---|---|
| = h(tr('لا توجد فواتير غير مدفوعة أو جزئية.', 'No unpaid or partial invoices.')) ?> | ||||||||
| = h($sale['receipt_no']) ?> | 8) { $displayPhone = substr($displayPhone, 3); } } ?>= h($rawCustomerName) ?> | = h($displayPhone ?: '-') ?> | = h(date('Y-m-d', strtotime((string)$sale['sale_date']))) ?> | = h(currency((float)$sale['total_amount'])) ?> | = h(currency((float)$paymentSummary['paid_amount'])) ?> | = h(currency((float)$paymentSummary['due_amount'])) ?> | = h(payment_status_label($paymentSummary['payment_status'])) ?> | |