217 lines
9.0 KiB
PHP
217 lines
9.0 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
// Sessions setup (Must match index.php)
|
|
$sessions_dir = __DIR__ . '/sessions';
|
|
if (is_dir($sessions_dir) && is_writable($sessions_dir)) {
|
|
session_save_path($sessions_dir);
|
|
}
|
|
|
|
// Enhanced session security and iframe compatibility (Must match index.php)
|
|
if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) {
|
|
session_set_cookie_params([
|
|
'lifetime' => 0,
|
|
'path' => '/',
|
|
'secure' => true,
|
|
'httponly' => true,
|
|
'samesite' => 'None',
|
|
]);
|
|
}
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
if (!isset($_SESSION['user_id'])) {
|
|
http_response_code(403);
|
|
echo "Unauthorized";
|
|
exit;
|
|
}
|
|
|
|
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
|
if (!$id) {
|
|
echo '<div class="modal-header"><h5 class="modal-title">Error</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body text-danger">Invalid Session ID</div>';
|
|
exit;
|
|
}
|
|
|
|
// Fetch session details
|
|
$stmt = db()->prepare("SELECT s.*, r.name as register_name, u.username
|
|
FROM register_sessions s
|
|
LEFT JOIN cash_registers r ON s.register_id = r.id
|
|
LEFT JOIN users u ON s.user_id = u.id
|
|
WHERE s.id = ?");
|
|
$stmt->execute([$id]);
|
|
$s = $stmt->fetch();
|
|
|
|
if (!$s) {
|
|
echo '<div class="modal-header"><h5 class="modal-title">Error</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body text-danger">Session not found</div>';
|
|
exit;
|
|
}
|
|
|
|
?>
|
|
<style>
|
|
@media print {
|
|
body * {
|
|
visibility: hidden;
|
|
}
|
|
#universalSessionReportModal, #universalSessionReportModal * {
|
|
visibility: visible;
|
|
}
|
|
#universalSessionReportModal {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
.modal-backdrop { display: none !important; }
|
|
.modal-footer { display: none !important; } /* Hide buttons on print */
|
|
.btn-close { display: none !important; }
|
|
}
|
|
</style>
|
|
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Session Cashflow Report (#<?= $s['id'] ?>)</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body text-start">
|
|
<div class="form-grid-3">
|
|
<div class="col-md-6">
|
|
<p class="mb-1 text-muted small">Register</p>
|
|
<h6><?= htmlspecialchars($s['register_name'] ?? 'Unknown') ?></h6>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p class="mb-1 text-muted small">Cashier</p>
|
|
<h6><?= htmlspecialchars($s['username'] ?? 'Unknown') ?></h6>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p class="mb-1 text-muted small">Opened At</p>
|
|
<h6><?= $s['opened_at'] ?></h6>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p class="mb-1 text-muted small">Closed At</p>
|
|
<h6><?= $s['closed_at'] ?? 'Still Open' ?></h6>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<?php
|
|
// Breakdown of sales by payment method (Unified)
|
|
$breakdown = db()->prepare("SELECT payment_method, SUM(amount) as total FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.register_session_id = ? AND i.status = 'paid' AND i.is_pos = 1 GROUP BY payment_method");
|
|
$breakdown->execute([$s['id']]);
|
|
$methods = $breakdown->fetchAll();
|
|
|
|
$cash_sales = 0;
|
|
$card_sales = 0;
|
|
$credit_sales = 0;
|
|
$bank_transfer_sales = 0;
|
|
|
|
foreach ($methods as $m) {
|
|
$method = strtolower($m['payment_method']);
|
|
if ($method === 'cash') $cash_sales = $m['total'];
|
|
elseif ($method === 'card' || strpos($method, 'card') !== false) $card_sales = $m['total'];
|
|
elseif ($method === 'credit') $credit_sales = $m['total'];
|
|
elseif (strpos($method, 'transfer') !== false || strpos($method, 'bank') !== false) $bank_transfer_sales = $m['total'];
|
|
else $cash_sales += $m['total'];
|
|
}
|
|
$total_sales = $cash_sales + $card_sales + $credit_sales + $bank_transfer_sales;
|
|
$expected_cash_total = (float)$s['opening_balance'] + $cash_sales;
|
|
$total_all = (float)$s['opening_balance'] + $total_sales;
|
|
?>
|
|
|
|
<div class="card border-0 bg-light mb-4">
|
|
<div class="card-body">
|
|
<h6 class="fw-bold text-uppercase small mb-3">Sales Summary</h6>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Opening Balance:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$s['opening_balance'], 3) ?></span>
|
|
</div>
|
|
<?php
|
|
// Additional totals (Unified)
|
|
$extra_stmt = db()->prepare("SELECT SUM(vat_amount) as total_tax, SUM(discount_amount) as total_discount, SUM(total_with_vat) as total_net FROM invoices WHERE register_session_id = ? AND status = 'paid' AND is_pos = 1");
|
|
$extra_stmt->execute([$s['id']]);
|
|
$extra = $extra_stmt->fetch();
|
|
?>
|
|
<div class="d-flex justify-content-between mb-2 small text-muted">
|
|
<span>Tax Amount:</span>
|
|
<span>OMR <?= number_format((float)($extra['total_tax'] ?? 0), 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2 small text-muted">
|
|
<span>Discount:</span>
|
|
<span>OMR <?= number_format((float)($extra['total_discount'] ?? 0), 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Cash Sale:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$cash_sales, 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Credit Card:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$card_sales, 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Credit:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$credit_sales, 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Bank Transfer:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$bank_transfer_sales, 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2 border-top pt-2 mt-2 h6 text-primary">
|
|
<span>Total Sale:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$total_sales, 3) ?></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card border-0 bg-primary bg-opacity-10 mb-4">
|
|
<div class="card-body">
|
|
<h6 class="fw-bold text-uppercase small mb-3 text-primary">Cash Reconciliation</h6>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Opening Balance:</span>
|
|
<span>OMR <?= number_format((float)$s['opening_balance'], 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>(+) Cash Sale:</span>
|
|
<span>OMR <?= number_format($cash_sales, 3) ?></span>
|
|
</div>
|
|
<div class="d-flex justify-content-between mb-2 border-top pt-2 mt-2 h6">
|
|
<span>Expected Cash:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$expected_cash_total, 3) ?></span>
|
|
</div>
|
|
|
|
<?php if ($s['status'] === 'closed'): ?>
|
|
<div class="d-flex justify-content-between mb-2">
|
|
<span>Actual Cash:</span>
|
|
<span>OMR <?= number_format((float)$s['cash_in_hand'], 3) ?></span>
|
|
</div>
|
|
<?php
|
|
$shortage = (float)$s['cash_in_hand'] - $expected_cash_total;
|
|
$shortage_class = $shortage < 0 ? 'text-danger' : 'text-success';
|
|
?>
|
|
<div class="d-flex justify-content-between mb-0 h5 mt-2 <?= $shortage_class ?>">
|
|
<span>Balance:</span>
|
|
<span class="fw-bold">OMR <?= number_format((float)$shortage, 3) ?></span>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transaction Details REMOVED per user request -->
|
|
|
|
<hr>
|
|
<div class="row g-2 small text-muted">
|
|
<div class="col-6">Expected Cash: OMR <?= number_format((float)$expected_cash_total, 3) ?></div>
|
|
<div class="col-6 text-end">Actual Cash: OMR <?= number_format((float)($s['cash_in_hand'] ?? 0), 3) ?></div>
|
|
</div>
|
|
|
|
<?php if ($s['notes']): ?>
|
|
<hr>
|
|
<p class="mb-1 text-muted small">Notes:</p>
|
|
<p class="mb-0 small bg-light p-2 rounded"><?= nl2br(htmlspecialchars($s['notes'])) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" onclick="window.print()">Print Report</button>
|
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
|
</div>
|