346 lines
14 KiB
PHP
346 lines
14 KiB
PHP
<?php
|
|
$title = 'customer_statement';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
$customer_id = $_GET['id'] ?? null;
|
|
if (!$customer_id) {
|
|
header('Location: customers.php');
|
|
exit;
|
|
}
|
|
|
|
// Fetch customer details
|
|
$stmt = db()->prepare("SELECT * FROM customers WHERE id = ?");
|
|
$stmt->execute([$customer_id]);
|
|
$customer = $stmt->fetch();
|
|
|
|
if (!$customer) {
|
|
header('Location: customers.php');
|
|
exit;
|
|
}
|
|
|
|
$from_date = $_GET['from_date'] ?? '';
|
|
$to_date = $_GET['to_date'] ?? '';
|
|
|
|
// Base queries
|
|
$orders_sql = "SELECT id, order_number, total_price, created_at FROM orders WHERE customer_id = ?";
|
|
$payments_sql = "SELECT p.id, p.amount, p.payment_method, p.created_at, o.order_number
|
|
FROM payments p
|
|
JOIN orders o ON p.order_id = o.id
|
|
WHERE o.customer_id = ?";
|
|
$params = [$customer_id];
|
|
|
|
if ($from_date) {
|
|
$orders_sql .= " AND DATE(created_at) >= ?";
|
|
$payments_sql .= " AND DATE(p.created_at) >= ?";
|
|
$params[] = $from_date;
|
|
}
|
|
if ($to_date) {
|
|
$orders_sql .= " AND DATE(created_at) <= ?";
|
|
$payments_sql .= " AND DATE(p.created_at) <= ?";
|
|
$params[] = $to_date;
|
|
}
|
|
|
|
$stmt_orders = db()->prepare($orders_sql);
|
|
// We need to be careful with params if both filters are set
|
|
$orders_params = [$customer_id];
|
|
if ($from_date) $orders_params[] = $from_date;
|
|
if ($to_date) $orders_params[] = $to_date;
|
|
$stmt_orders->execute($orders_params);
|
|
$orders = $stmt_orders->fetchAll();
|
|
|
|
$stmt_payments = db()->prepare($payments_sql);
|
|
$payments_params = [$customer_id];
|
|
if ($from_date) $payments_params[] = $from_date;
|
|
if ($to_date) $payments_params[] = $to_date;
|
|
$stmt_payments->execute($payments_params);
|
|
$payments = $stmt_payments->fetchAll();
|
|
|
|
// Combine and sort
|
|
$transactions = [];
|
|
foreach ($orders as $o) {
|
|
$transactions[] = [
|
|
'date' => $o['created_at'],
|
|
'type' => 'order',
|
|
'ref' => $o['order_number'],
|
|
'debit' => $o['total_price'],
|
|
'credit' => 0,
|
|
'description' => __('order') . ' #' . $o['order_number']
|
|
];
|
|
}
|
|
foreach ($payments as $p) {
|
|
$transactions[] = [
|
|
'date' => $p['created_at'],
|
|
'type' => 'payment',
|
|
'ref' => $p['order_number'],
|
|
'debit' => 0,
|
|
'credit' => $p['amount'],
|
|
'description' => __('payment') . ' (' . __($p['payment_method']) . ') - ' . __('order') . ' #' . $p['order_number']
|
|
];
|
|
}
|
|
|
|
usort($transactions, function($a, $b) {
|
|
return strtotime($a['date']) - strtotime($b['date']);
|
|
});
|
|
|
|
$total_debit = 0;
|
|
$total_credit = 0;
|
|
$balance = 0;
|
|
foreach ($transactions as &$t) {
|
|
$total_debit += $t['debit'];
|
|
$total_credit += $t['credit'];
|
|
$balance += ($t['debit'] - $t['credit']);
|
|
$t['running_balance'] = $balance;
|
|
}
|
|
|
|
// Fallback values if database is empty
|
|
$display_company_name = ($lang === 'ar' ? ($company_info['name_ar'] ?: $company_info['name_en']) : $company_info['name_en']) ?: 'Laundry Brand';
|
|
$display_address = ($lang === 'ar' ? ($company_info['address_ar'] ?: $company_info['address_en']) : $company_info['address_en']);
|
|
$display_phone = $company_info['phone'];
|
|
$display_email = $company_info['email'];
|
|
$display_vat = $company_info['vat_no'] ?: $company_info['vat_number'];
|
|
$display_ctr = $company_info['ctr_no'];
|
|
|
|
?>
|
|
|
|
<div class="d-print-none mb-4">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="customers.php"><?= __('customers') ?></a></li>
|
|
<li class="breadcrumb-item active"><?= __('customer_statement') ?></li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="card p-4 border-0 shadow-sm mb-4 d-print-none" style="border-radius: 20px;">
|
|
<form action="" method="GET" class="row g-3 align-items-end">
|
|
<input type="hidden" name="id" value="<?= $customer_id ?>">
|
|
<div class="col-md-4">
|
|
<label class="form-label small fw-bold"><?= __('from_date') ?></label>
|
|
<input type="date" name="from_date" class="form-control" value="<?= $from_date ?>" style="border-radius: 12px;">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label small fw-bold"><?= __('to_date') ?></label>
|
|
<input type="date" name="to_date" class="form-control" value="<?= $to_date ?>" style="border-radius: 12px;">
|
|
</div>
|
|
<div class="col-md-4 d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary px-4 w-100" style="border-radius: 12px;">
|
|
<i class="bi bi-filter me-1"></i> <?= __('filter') ?? 'Filter' ?>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-dark px-4 w-100" style="border-radius: 12px;" onclick="window.print()">
|
|
<i class="bi bi-printer me-1"></i> <?= __('print') ?>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="printableStatement" class="card p-5 border-0 shadow-sm" style="border-radius: 20px;">
|
|
<!-- Formal Header for Printing -->
|
|
<div class="d-none d-print-block mb-5">
|
|
<div class="row align-items-center mb-4">
|
|
<div class="col-7">
|
|
<?php if (!empty($company_info['logo'])): ?>
|
|
<img src="<?= $company_info['logo'] ?>" alt="Logo" style="max-height: 100px;" class="mb-3">
|
|
<?php else: ?>
|
|
<div class="mb-3 d-flex align-items-center text-primary">
|
|
<i class="bi bi-tsunami fs-1 me-2"></i>
|
|
<span class="fs-4 fw-bold">Laundry Management</span>
|
|
</div>
|
|
<?php endif; ?>
|
|
<h2 class="fw-bold mb-1"><?= htmlspecialchars($display_company_name) ?></h2>
|
|
<div class="mb-0 text-muted small">
|
|
<?php if ($display_address): ?>
|
|
<?= htmlspecialchars($display_address) ?><br>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($display_phone): ?>
|
|
<?= __('phone') ?>: <?= htmlspecialchars($display_phone) ?>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($display_email): ?>
|
|
<?= $display_phone ? ' | ' : '' ?><?= __('email') ?>: <?= htmlspecialchars($display_email) ?><br>
|
|
<?php elseif($display_phone): ?>
|
|
<br>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($display_vat): ?>
|
|
<?= __('vat_no') ?>: <?= htmlspecialchars($display_vat) ?>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($display_ctr): ?>
|
|
<?= $display_vat ? ' | ' : '' ?><?= __('ctr_no') ?>: <?= htmlspecialchars($display_ctr) ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-5 text-end">
|
|
<h1 class="fw-bold text-uppercase mb-2" style="color: #0d6efd;"><?= __('statement') ?></h1>
|
|
<div class="mt-3">
|
|
<p class="mb-0 fw-bold"><?= __('date') ?>: <?= date('d/m/Y') ?></p>
|
|
<p class="mb-0 text-muted small"><?= __('cashier') ?>: <?= htmlspecialchars($_SESSION['full_name'] ?? 'System Admin') ?></p>
|
|
<?php if ($from_date || $to_date): ?>
|
|
<p class="mb-0 text-muted small mt-1">
|
|
<?= $from_date ? __('from_date') . ': ' . date('d/m/Y', strtotime($from_date)) : '' ?>
|
|
<?= $to_date ? ' ' . __('to_date') . ': ' . date('d/m/Y', strtotime($to_date)) : '' ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row p-3 bg-light rounded-3 mb-4 mx-0 border">
|
|
<div class="col-12">
|
|
<h6 class="fw-bold text-muted text-uppercase mb-2 small"><?= __('customer_details') ?></h6>
|
|
<h4 class="fw-bold mb-1"><?= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?></h4>
|
|
<p class="mb-0 text-muted small"><?= $customer['phone'] ?> <?= $customer['email'] ? ' | ' . $customer['email'] : '' ?></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Screen Header -->
|
|
<div class="d-print-none mb-4">
|
|
<h4 class="fw-bold mb-1"><?= $lang === 'ar' ? ($customer['name_ar'] ?: $customer['name_en']) : $customer['name_en'] ?></h4>
|
|
<p class="text-muted mb-0"><?= $customer['phone'] ?> <?= $customer['email'] ? ' | ' . $customer['email'] : '' ?></p>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped align-middle mt-4">
|
|
<thead class="table-dark">
|
|
<tr>
|
|
<th><?= __('date') ?></th>
|
|
<th><?= __('description') ?></th>
|
|
<th class="text-center"><?= __('ref') ?? 'Ref' ?></th>
|
|
<th class="text-end"><?= __('debit') ?></th>
|
|
<th class="text-end"><?= __('credit') ?></th>
|
|
<th class="text-end"><?= __('balance') ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($transactions)): ?>
|
|
<tr>
|
|
<td colspan="6" class="text-center py-5 text-muted">
|
|
<?= __('no_transactions_found') ?? 'No transactions found' ?>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($transactions as $t): ?>
|
|
<tr>
|
|
<td class="small"><?= date('d/m/Y H:i', strtotime($t['date'])) ?></td>
|
|
<td><?= $t['description'] ?></td>
|
|
<td class="text-center"><span class="badge bg-light text-dark border"><?= $t['ref'] ?></span></td>
|
|
<td class="text-end"><?= $t['debit'] > 0 ? format_amount($t['debit']) : '-' ?></td>
|
|
<td class="text-end"><?= $t['credit'] > 0 ? format_amount($t['credit']) : '-' ?></td>
|
|
<td class="text-end fw-bold"><?= format_amount($t['running_balance']) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
<tfoot class="table-light fw-bold border-top">
|
|
<tr>
|
|
<td colspan="3" class="text-end"><?= __('total') ?></td>
|
|
<td class="text-end"><?= format_amount($total_debit) ?></td>
|
|
<td class="text-end"><?= format_amount($total_credit) ?></td>
|
|
<td class="text-end text-primary"><?= format_amount($balance) ?></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="row mt-5">
|
|
<div class="col-md-5 ms-auto">
|
|
<div class="card bg-white border" style="border-radius: 15px;">
|
|
<div class="card-body p-4">
|
|
<h5 class="fw-bold mb-4 border-bottom pb-2 small text-uppercase text-muted"><?= __('summary') ?? 'Summary' ?></h5>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span class="text-muted small"><?= __('total_debit') ?>:</span>
|
|
<span class="fw-bold small"><?= format_amount($total_debit) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span class="text-muted small"><?= __('total_credit') ?>:</span>
|
|
<span class="fw-bold small"><?= format_amount($total_credit) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between pt-2 mt-2 border-top">
|
|
<span class="fw-bold fs-6"><?= __('closing_balance') ?>:</span>
|
|
<span class="fw-bold text-primary fs-6"><?= format_amount($balance) ?></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Print Footer -->
|
|
<div class="d-none d-print-block mt-5 pt-4 border-top">
|
|
<div class="row text-center small text-muted">
|
|
<div class="col-4">
|
|
<div class="mb-4">_______________________</div>
|
|
<div><?= __('customer_signature') ?? 'Customer Signature' ?></div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="mb-4"><?= date('d/m/Y H:i') ?></div>
|
|
<div><?= __('print_date') ?? 'Print Date' ?></div>
|
|
</div>
|
|
<div class="col-4">
|
|
<div class="mb-4">_______________________</div>
|
|
<div><?= __('authorized_signature') ?? 'Authorized Signature' ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
@media print {
|
|
@page {
|
|
size: auto;
|
|
margin: 10mm 15mm;
|
|
}
|
|
body {
|
|
background-color: white !important;
|
|
font-size: 11px;
|
|
-webkit-print-color-adjust: exact;
|
|
}
|
|
.main-content {
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
}
|
|
header, .sidebar, .d-print-none, .breadcrumb, nav {
|
|
display: none !important;
|
|
}
|
|
.container-fluid, .row, .col-lg-10 {
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
flex: 0 0 100% !important;
|
|
}
|
|
.card {
|
|
box-shadow: none !important;
|
|
border: none !important;
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
}
|
|
#printableStatement {
|
|
padding: 0 !important;
|
|
}
|
|
table {
|
|
width: 100% !important;
|
|
border-collapse: collapse !important;
|
|
}
|
|
th, td {
|
|
border: 1px solid #dee2e6 !important;
|
|
padding: 6px !important;
|
|
}
|
|
.badge {
|
|
border: none !important;
|
|
padding: 0 !important;
|
|
}
|
|
.bg-light {
|
|
background-color: #f8f9fa !important;
|
|
}
|
|
.table-dark {
|
|
background-color: #212529 !important;
|
|
color: white !important;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|