modifying sessions print

This commit is contained in:
Flatlogic Bot 2026-03-19 09:27:04 +00:00
parent 659dabb8bd
commit e6e204908d
4 changed files with 13925 additions and 259 deletions

217
ajax_session_report.php Normal file
View File

@ -0,0 +1,217 @@
<?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>

319
index.php
View File

@ -2497,18 +2497,8 @@ if (isset($_POST['add_hr_department'])) {
}
}
if (isset($_POST['close_register'])) {
$session_id = $_SESSION['register_session_id'] ?? null;
$closing_balance = (float)$_POST['closing_balance'];
$notes = $_POST['notes'] ?? '';
if ($session_id) {
$stmt = db()->prepare("UPDATE register_sessions SET closing_balance = ?, closed_at = NOW(), status = 'closed', notes = ? WHERE id = ?");
$stmt->execute([$closing_balance, $notes, $session_id]);
unset($_SESSION['register_session_id']);
redirectWithMessage("Register closed successfully!", "index.php?page=pos");
}
}
// Removed conflicting close_register handler
if (isset($_POST['delete_backup'])) {
if (can('users_view')) {
@ -2608,16 +2598,20 @@ if (isset($_POST['add_hr_department'])) {
$session_id = (int)$_POST['session_id'];
$cash_in_hand = (float)$_POST['cash_in_hand'];
$notes = $_POST['notes'] ?? '';
$redirect_to = $_POST['redirect_to'] ?? 'dashboard';
// Calculate expected closing balance
// Opening + Sum of POS Transactions (Cash) - Any cash outflows (if any)
$session = db()->prepare("SELECT opening_balance FROM register_sessions WHERE id = ?");
$session->execute([$session_id]);
$opening = (float)$session->fetchColumn();
$sales = db()->prepare("SELECT SUM(p.amount) 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 AND p.payment_method = 'cash'");
$sales->execute([$session_id]);
$cash_sales = (float)$sales->fetchColumn();
// Unified calculation logic (POS Transactions + Invoices)
// Note: POS transactions are saved in invoices table with is_pos=1
$sales_sql = "SELECT SUM(p.amount) 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 AND LOWER(p.payment_method) = 'cash'";
$sales_stmt = db()->prepare($sales_sql);
$sales_stmt->execute([$session_id]);
$cash_sales = (float)$sales_stmt->fetchColumn();
$expected = $opening + $cash_sales;
@ -2626,7 +2620,14 @@ if (isset($_POST['add_hr_department'])) {
unset($_SESSION['register_session_id']);
$message = "Register closed successfully!";
header("Location: index.php?page=dashboard");
if ($redirect_to === 'dashboard') {
// For POS users, we want dashboard
header("Location: index.php?page=dashboard");
} else {
// For Admin, we stay on sessions page
redirectWithMessage($message, "index.php?page=" . urlencode($redirect_to));
}
exit;
}
@ -5201,7 +5202,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<?= number_format((float)$item['stock_quantity'], 3) ?>
</span>
</td>
<td class="fw-bold text-danger"><?= number_format($shortage, 3) ?></td>
<td class="fw-bold text-danger"><?= number_format((float)$shortage, 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@ -6368,6 +6369,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<form method="POST">
<div class="modal-body">
<input type="hidden" name="close_register" value="1">
<input type="hidden" name="redirect_to" value="dashboard">
<input type="hidden" name="session_id" value="<?= $_SESSION['register_session_id'] ?? '' ?>">
<div class="mb-3">
<label class="form-label">Cash in Hand (Counted)</label>
@ -9357,11 +9359,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
SUM(CASE WHEN LOWER(payment_method) LIKE '%transfer%' OR LOWER(payment_method) LIKE '%bank%' THEN amount ELSE 0 END) as transfer_total,
SUM(amount) as total_sales
FROM (
SELECT p.payment_method, p.amount FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed'
UNION ALL
SELECT p.payment_method, p.amount 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
) as combined_payments");
$stats_stmt->execute([$s['id'], $s['id']]);
$stats_stmt->execute([$s['id']]);
$st = $stats_stmt->fetch();
$c_total = (float)($st['cash_total'] ?? 0);
$cd_total = (float)($st['card_total'] ?? 0);
@ -9389,7 +9389,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</td>
<td class="text-end">
<button class="btn btn-sm btn-light rounded-circle" data-bs-toggle="modal" data-bs-target="#sessionReportModal<?= $s['id'] ?>"><i class="bi bi-file-earmark-text text-primary"></i></button>
<button class="btn btn-sm btn-light rounded-circle" onclick="loadSessionReport(<?= $s['id'] ?>)"><i class="bi bi-file-earmark-text text-primary"></i></button>
</td>
</tr>
<?php endforeach; ?>
@ -9401,236 +9401,39 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div>
<!-- Modals outside loop for better structure -->
<?php foreach ($data['sessions'] as $s): ?>
<!-- Session Report Modal -->
<div class="modal fade" id="sessionReportModal<?= $s['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<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']) ?></h6>
</div>
<div class="col-md-6">
<p class="mb-1 text-muted small">Cashier</p>
<h6><?= htmlspecialchars($s['username']) ?></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 (
SELECT p.payment_method, p.amount FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed'
UNION ALL
SELECT p.payment_method, p.amount 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
) as combined_payments GROUP BY payment_method");
$breakdown->execute([$s['id'], $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_net) as total_net FROM (
SELECT tax_amount as vat_amount, discount_amount, net_amount as total_net FROM pos_transactions WHERE register_session_id = ? AND status = 'completed'
UNION ALL
SELECT vat_amount, discount_amount, total_with_vat as total_net FROM invoices WHERE register_session_id = ? AND status = 'paid' AND is_pos = 1
) as combined_totals");
$extra_stmt->execute([$s['id'], $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($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($card_sales, 3) ?></span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>Credit:</span>
<span class="fw-bold">OMR <?= number_format($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($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($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($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($shortage, 3) ?></span>
</div>
<?php endif; ?>
<!-- Session Report Modal (Universal) -->
<div class="modal fade" id="universalSessionReportModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div id="sessionReportContent">
<div class="modal-body text-center p-5">
<div class="spinner-border text-primary"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4">
<h6 class="fw-bold small text-uppercase mb-2">Transaction Details</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered small">
<thead class="bg-light">
<tr>
<th>Time</th>
<th>Order #</th>
<th data-en="Customer" data-ar="العميل">Customer</th>
<th>Items</th>
<th>Method</th>
<th class="text-end" data-en="Amount" data-ar="المبلغ">Amount</th>
</tr>
</thead>
<tbody>
<?php
$txs_stmt = db()->prepare("SELECT i.*, c.name as customer_name, GROUP_CONCAT(p.payment_method SEPARATOR ', ') as methods FROM invoices i LEFT JOIN payments p ON i.id = p.invoice_id LEFT JOIN customers c ON i.customer_id = c.id WHERE i.register_session_id = ? AND i.status = 'paid' AND i.is_pos = 1 GROUP BY i.id ORDER BY i.created_at DESC");
$txs_stmt->execute([$s['id']]);
$txs = $txs_stmt->fetchAll();
foreach ($txs as $tx):
?>
<tr>
<td><?= date('H:i', strtotime($tx['created_at'])) ?></td>
<td><?= htmlspecialchars($tx['transaction_no']) ?></td>
<td><?= htmlspecialchars($tx['customer_name'] ?: 'Walk-in') ?></td>
<td>
<?php
$items_stmt = db()->prepare("SELECT si.name_en, ii.quantity FROM invoice_items ii JOIN stock_items si ON ii.item_id = si.id WHERE ii.invoice_id = ?");
$items_stmt->execute([$tx['id']]);
$items = $items_stmt->fetchAll();
foreach ($items as $item) {
echo "<small class='d-block'>" . htmlspecialchars($item['name_en']) . " x " . (float)$item['quantity'] . "</small>";
}
?>
</td>
<td class="text-capitalize small"><?= htmlspecialchars($tx['methods'] ?: '---') ?></td>
<td class="text-end"><?= number_format($tx['total_with_vat'], 3) ?></td>
</tr>
<?php endforeach; ?>
<?php
$txs_stmt = db()->prepare("SELECT t.*, c.name as customer_name, GROUP_CONCAT(p.payment_method SEPARATOR ', ') as methods FROM pos_transactions t LEFT JOIN pos_payments p ON t.id = p.transaction_id LEFT JOIN customers c ON t.customer_id = c.id WHERE t.register_session_id = ? AND t.status = 'completed' GROUP BY t.id ORDER BY t.created_at DESC");
$txs_stmt->execute([$s['id']]);
$txs = $txs_stmt->fetchAll();
foreach ($txs as $tx):
?>
<tr>
<td><?= date('H:i', strtotime($tx['created_at'])) ?></td>
<td><?= htmlspecialchars($tx['transaction_no']) ?></td>
<td><?= htmlspecialchars($tx['customer_name'] ?: 'Walk-in') ?></td>
<td>
<?php
$items_stmt = db()->prepare("SELECT i.name_en, ti.quantity FROM pos_items ti JOIN stock_items i ON ti.item_id = i.id WHERE ti.transaction_id = ?");
$items_stmt->execute([$tx['id']]);
$items = $items_stmt->fetchAll();
foreach ($items as $item) {
echo "<small class='d-block'>" . htmlspecialchars($item['name_en']) . " x " . (float)$item['quantity'] . "</small>";
}
?>
</td>
<td class="text-capitalize small"><?= htmlspecialchars($tx['methods'] ?: '---') ?></td>
<td class="text-end"><?= number_format($tx['net_amount'], 3) ?></td>
</tr>
<?php endforeach; if(empty($txs)): ?>
<tr><td colspan="5" class="text-center text-muted">No transactions</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<hr>
<div class="row g-2 small text-muted">
<div class="col-6">Expected Cash: OMR <?= number_format($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-secondary" 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>
</div>
</div>
</div>
<?php endforeach; ?>
<script>
function loadSessionReport(id) {
var modalEl = document.getElementById('universalSessionReportModal');
var modal = bootstrap.Modal.getOrCreateInstance(modalEl);
// Reset content
document.getElementById('sessionReportContent').innerHTML = '<div class="modal-body text-center p-5"><div class="spinner-border text-primary"></div></div>';
modal.show();
fetch('ajax_session_report.php?id=' + id)
.then(response => response.text())
.then(html => {
document.getElementById('sessionReportContent').innerHTML = html;
})
.catch(err => {
document.getElementById('sessionReportContent').innerHTML = '<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">Failed to load report.</div>';
});
}
</script>
<!-- Open Register Modal -->
<div class="modal fade" id="openRegisterModal" tabindex="-1">
@ -9677,18 +9480,15 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<form method="POST">
<div class="modal-body">
<input type="hidden" name="session_id" value="<?= $session['id'] ?>">
<input type="hidden" name="redirect_to" value="register_sessions">
<div class="alert alert-warning py-2 small border-0 shadow-sm">
<i class="bi bi-exclamation-triangle me-2"></i> Before closing, please count all cash in your register.
</div>
<?php
// Unified breakdown for closing
$curBreakdown = db()->prepare("SELECT payment_method, SUM(amount) as total FROM (
SELECT p.payment_method, p.amount FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed'
UNION ALL
SELECT p.payment_method, p.amount 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
) as combined GROUP BY payment_method");
$curBreakdown->execute([$session['id'], $session['id']]);
$curBreakdown = 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");
$curBreakdown->execute([$session['id']]);
$curMethods = $curBreakdown->fetchAll();
$cash_sales = 0;
@ -9762,7 +9562,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</thead>
<tbody>
<?php
$txs_stmt = db()->prepare("SELECT t.*, c.name as customer_name, GROUP_CONCAT(p.payment_method SEPARATOR ', ') as methods FROM pos_transactions t LEFT JOIN pos_payments p ON t.id = p.transaction_id LEFT JOIN customers c ON t.customer_id = c.id WHERE t.register_session_id = ? AND t.status = 'completed' GROUP BY t.id ORDER BY t.created_at DESC");
// Fetch from invoices
$txs_stmt = db()->prepare("SELECT i.*, c.name as customer_name, GROUP_CONCAT(p.payment_method SEPARATOR ', ') as methods FROM invoices i LEFT JOIN payments p ON i.id = p.invoice_id LEFT JOIN customers c ON i.customer_id = c.id WHERE i.register_session_id = ? AND i.status = 'paid' AND i.is_pos = 1 GROUP BY i.id ORDER BY i.created_at DESC");
$txs_stmt->execute([$session['id']]);
$txs = $txs_stmt->fetchAll();
foreach ($txs as $tx):
@ -9772,7 +9573,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<td><?= htmlspecialchars($tx['transaction_no']) ?></td>
<td><?= htmlspecialchars($tx['customer_name'] ?: 'Walk-in') ?></td>
<td class="text-capitalize small"><?= htmlspecialchars($tx['methods'] ?: '---') ?></td>
<td class="text-end"><?= number_format($tx['net_amount'], 3) ?></td>
<td class="text-end"><?= number_format($tx['total_with_vat'], 3) ?></td>
</tr>
<?php endforeach; if(empty($txs)): ?>
<tr><td colspan="5" class="text-center text-muted">No transactions</td></tr>

13632
index.php.bak.20260319 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -100,3 +100,19 @@
2026-03-19 01:58:33 - POST: {"id":"117","name_en":"LAMING RED KIDNEY BEANS 425","name_ar":"\u0641\u0627\u0635\u0648\u0644\u064a\u0627 \u062d\u0645\u0631\u0627\u0621 \u0643\u064a\u062f\u0646\u064a \u0644\u0627\u0645\u064a\u0646\u062c 425","sku":"000023071605","category_id":"","unit_id":"","supplier_id":"","sale_price":"0.25","purchase_price":"0.2","stock_quantity":"0","min_stock_level":"0","vat_rate":"5","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
2026-03-19 01:58:51 - POST: {"action":"translate","text":"LAMING PINEAPPLE 454G","target":"ar"}
2026-03-19 01:59:00 - POST: {"id":"116","name_en":"LAMING PINEAPPLE 454G","name_ar":"\u0623\u0646\u0627\u0646\u0627\u0633 \u0644\u0627\u0645\u064a\u0646\u063a 454 \u062c\u0631\u0627\u0645","sku":"000023071599","category_id":"","unit_id":"","supplier_id":"","sale_price":"0.4","purchase_price":"0.346","stock_quantity":"55","min_stock_level":"0","vat_rate":"5","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
2026-03-19 06:12:40 - POST: {"close_register":"1","session_id":"11","cash_in_hand":"10","notes":""}
2026-03-19 06:27:02 - POST: {"open_register":"1","register_id":"3","opening_balance":"0"}
2026-03-19 06:27:40 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":25.4}]","total_amount":"25.4","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":18,\"qty\":1,\"price\":0.6,\"vat_rate\":0,\"vat_amount\":0},{\"id\":17,\"qty\":2,\"price\":0.4,\"vat_rate\":0,\"vat_amount\":0},{\"id\":16,\"qty\":1,\"price\":1.5,\"vat_rate\":0,\"vat_amount\":0},{\"id\":22,\"qty\":5,\"price\":1,\"vat_rate\":0,\"vat_amount\":0},{\"id\":23,\"qty\":1,\"price\":1.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":21,\"qty\":3,\"price\":1.6,\"vat_rate\":0,\"vat_amount\":0},{\"id\":20,\"qty\":1,\"price\":0.9,\"vat_rate\":0,\"vat_amount\":0},{\"id\":14,\"qty\":1,\"price\":0.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":8,\"qty\":1,\"price\":1.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":9,\"qty\":1,\"price\":0.15,\"vat_rate\":0,\"vat_amount\":0},{\"id\":15,\"qty\":1,\"price\":2.55,\"vat_rate\":0,\"vat_amount\":0},{\"id\":29,\"qty\":1,\"price\":2.5,\"vat_rate\":0,\"vat_amount\":0},{\"id\":53,\"qty\":1,\"price\":0.15,\"vat_rate\":0,\"vat_amount\":0},{\"id\":33,\"qty\":1,\"price\":1.3,\"vat_rate\":0,\"vat_amount\":0},{\"id\":70,\"qty\":1,\"price\":2.55,\"vat_rate\":0,\"vat_amount\":0}]"}
2026-03-19 06:30:20 - POST: {"close_register":"1","redirect_to":"dashboard","session_id":"12","cash_in_hand":"33","notes":""}
2026-03-19 06:38:24 - POST: {"close_register":"1","redirect_to":"dashboard","session_id":"12","cash_in_hand":"33","notes":""}
2026-03-19 06:40:40 - POST: {"open_register":"1","register_id":"3","opening_balance":"3"}
2026-03-19 06:40:49 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.2}]","total_amount":"0.2","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":13,\"qty\":1,\"price\":0.2,\"vat_rate\":0,\"vat_amount\":0}]"}
2026-03-19 06:41:01 - POST: {"close_register":"1","redirect_to":"dashboard","session_id":"13","cash_in_hand":"3","notes":""}
2026-03-19 07:58:11 - POST: {"open_register":"1","register_id":"3","opening_balance":"32"}
2026-03-19 07:58:27 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":11.25}]","total_amount":"11.249999999999998","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":8,\"qty\":1,\"price\":1.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":15,\"qty\":1,\"price\":2.55,\"vat_rate\":0,\"vat_amount\":0},{\"id\":21,\"qty\":2,\"price\":1.6,\"vat_rate\":0,\"vat_amount\":0},{\"id\":22,\"qty\":2,\"price\":1,\"vat_rate\":0,\"vat_amount\":0},{\"id\":30,\"qty\":1,\"price\":1.1,\"vat_rate\":0,\"vat_amount\":0},{\"id\":23,\"qty\":1,\"price\":1.2,\"vat_rate\":0,\"vat_amount\":0}]"}
2026-03-19 07:59:22 - POST: {"close_register":"1","redirect_to":"dashboard","session_id":"14","cash_in_hand":"20","notes":""}
2026-03-19 09:22:52 - POST: {"action":"save_theme","theme":"ocean"}
2026-03-19 09:22:56 - POST: {"action":"save_theme","theme":"dark"}
2026-03-19 09:22:58 - POST: {"action":"save_theme","theme":"default"}
2026-03-19 09:23:00 - POST: {"action":"save_theme","theme":"dracula"}
2026-03-19 09:23:02 - POST: {"action":"save_theme","theme":"sunset"}