open sessionss to cashier

This commit is contained in:
Flatlogic Bot 2026-02-18 18:08:18 +00:00
parent 91e9a72157
commit e84ed5d57e
48 changed files with 293 additions and 25 deletions

View File

@ -1,3 +1,32 @@
<?php
require_once 'db/config.php';
$settings = [];
try {
$rows = db()->query("SELECT * FROM settings")->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $r) {
$settings[$r['key']] = $r['value'];
}
} catch (Exception $e) {
// Fallback if DB fails
}
$title = $settings['customer_display_greeting_title'] ?? 'Welcome';
$subtitle = $settings['customer_display_greeting_text'] ?? 'We are ready to serve you.';
$slides = [];
if (!empty($settings['display_slide_1'])) $slides[] = $settings['display_slide_1'];
if (!empty($settings['display_slide_2'])) $slides[] = $settings['display_slide_2'];
if (!empty($settings['display_slide_3'])) $slides[] = $settings['display_slide_3'];
// Fallbacks
if (empty($slides)) {
$slides = [
'https://images.unsplash.com/photo-1441986300917-64674bd600d8?q=80&w=1920&auto=format&fit=crop',
'https://images.unsplash.com/photo-1472851294608-415170d4e897?q=80&w=1920&auto=format&fit=crop',
'https://images.unsplash.com/photo-1556742049-0cfed4f7a07d?q=80&w=1920&auto=format&fit=crop',
'https://images.unsplash.com/photo-1528698827591-e19ccd7bc23d?q=80&w=1920&auto=format&fit=crop'
];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
@ -34,6 +63,7 @@
flex: 1;
display: flex;
overflow: hidden;
}
.items-section {
flex: 2;
@ -102,19 +132,74 @@
line-height: 1.2;
}
.welcome-screen {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
color: var(--text-muted);
color: white;
overflow: hidden;
background: #212529;
}
.slideshow-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.slideshow-bg::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5); /* Overlay */
z-index: 2;
}
.slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
opacity: 0;
transition: opacity 2s ease-in-out;
transform: scale(1.1); /* Subtle zoom effect start */
transition: opacity 2s ease-in-out, transform 10s ease;
}
.slide.active {
opacity: 1;
transform: scale(1);
z-index: 1;
}
.welcome-content {
position: relative;
z-index: 10;
padding: 3rem;
max-width: 800px;
animation: fadeIn 1s ease-out;
}
.welcome-logo {
max-height: 15vh;
margin-bottom: 2rem;
filter: drop-shadow(0 4px 10px rgba(0,0,0,0.3));
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.welcome-icon {
font-size: 15vmin;
margin-bottom: 1rem;
color: var(--border);
opacity: 0.5;
color: rgba(255,255,255,0.8);
text-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
/* Custom scrollbar */
::-webkit-scrollbar {
@ -177,11 +262,23 @@
</div>
<div id="welcomeScreen" class="welcome-screen">
<div class="welcome-icon">
<i class="bi bi-shop"></i>
<div class="slideshow-bg" id="slideshow">
<?php foreach ($slides as $i => $url): ?>
<div class="slide <?= $i === 0 ? 'active' : '' ?>" style="background-image: url('<?= htmlspecialchars($url) ?>');"></div>
<?php endforeach; ?>
</div>
<div class="welcome-content">
<?php if (!empty($settings['company_logo']) && file_exists($settings['company_logo'])): ?>
<img src="<?= htmlspecialchars($settings['company_logo']) ?>?v=<?= time() ?>" alt="Store Logo" class="welcome-logo">
<?php elseif (file_exists('uploads/logo.png')): ?>
<img src="uploads/logo.png?v=<?= time() ?>" alt="Store Logo" class="welcome-logo">
<?php else: ?>
<div class="welcome-icon"><i class="bi bi-shop"></i></div>
<?php endif; ?>
<h1 class="display-3 fw-bold mb-3 text-white"><?= htmlspecialchars($title) ?></h1>
<p class="lead fs-3 text-white-50"><?= htmlspecialchars($subtitle) ?></p>
</div>
<h1 class="display-4 fw-bold" style="color: var(--text)">Welcome</h1>
<p class="lead">Next customer, please.</p>
</div>
<script>
@ -336,6 +433,17 @@
window.moveTo(0, 0);
window.resizeTo(screen.availWidth, screen.availHeight);
} catch(e) {}
// Start slideshow
const slides = document.querySelectorAll('.slide');
let currentSlide = 0;
if (slides.length > 0) {
setInterval(() => {
slides[currentSlide].classList.remove('active');
currentSlide = (currentSlide + 1) % slides.length;
slides[currentSlide].classList.add('active');
}, 6000);
}
});
</script>
</body>

165
index.php
View File

@ -776,7 +776,7 @@ if (isset($_POST['add_hr_department'])) {
}
// Handle file uploads
$files = ['company_logo', 'favicon', 'manager_signature'];
$files = ['company_logo', 'favicon', 'manager_signature', 'display_slide_1', 'display_slide_2', 'display_slide_3'];
foreach ($files as $file_key) {
if (isset($_FILES[$file_key]) && $_FILES[$file_key]['error'] === 0) {
$ext = pathinfo($_FILES[$file_key]['name'], PATHINFO_EXTENSION);
@ -945,6 +945,7 @@ $page_permissions = [
'role_groups' => 'users_view',
'users' => 'users_view',
'scale_devices' => 'users_view',
'customer_display_settings' => 'settings_view',
'backups' => 'users_view',
'logs' => 'users_view',
'cash_registers' => 'users_view',
@ -1783,11 +1784,11 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<!-- Administrations Section -->
<?php if (can('users_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['role_groups', 'users']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#admin-collapse">
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['role_groups', 'users', 'cash_registers', 'register_sessions', 'scale_devices', 'backups', 'customer_display_settings']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#admin-collapse">
<span><i class="fas fa-user-gear group-icon"></i><span data-en="Administrations" data-ar="الإدارة">Administrations</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['role_groups', 'users']) ? 'show' : '' ?>" id="admin-collapse">
<div class="collapse <?= in_array($page, ['role_groups', 'users', 'cash_registers', 'register_sessions', 'scale_devices', 'backups', 'customer_display_settings']) ? 'show' : '' ?>" id="admin-collapse">
<a href="index.php?page=role_groups" class="nav-link <?= $page === 'role_groups' ? 'active' : '' ?>">
<i class="fas fa-user-shield"></i> <span data-en="Role Groups" data-ar="مجموعات الأدوار">Role Groups</span>
</a>
@ -1803,6 +1804,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<a href="index.php?page=scale_devices" class="nav-link <?= $page === 'scale_devices' ? 'active' : '' ?>">
<i class="fas fa-microchip"></i> <span data-en="Devices" data-ar="الأجهزة">Devices</span>
</a>
<a href="index.php?page=customer_display_settings" class="nav-link <?= $page === 'customer_display_settings' ? 'active' : '' ?>">
<i class="fas fa-desktop"></i> <span data-en="Customer Display" data-ar="شاشة العميل">Customer Display</span>
</a>
<a href="index.php?page=backups" class="nav-link <?= $page === 'backups' ? 'active' : '' ?>">
<i class="fas fa-database"></i> <span data-en="Backups" data-ar="نسخ احتياطي">Backups</span>
</a>
@ -1860,6 +1864,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
'backups' => ['en' => 'Database Backups', 'ar' => 'نسخ قاعدة البيانات'],
'role_groups' => ['en' => 'Role Groups', 'ar' => 'مجموعات الأدوار'],
'scale_devices' => ['en' => 'POS Devices', 'ar' => 'أجهزة نقاط البيع'],
'customer_display_settings' => ['en' => 'Customer Display', 'ar' => 'شاشة العميل'],
'cash_registers' => ['en' => 'Cash Registers', 'ar' => 'خزائن الكاشير'],
'register_sessions' => ['en' => 'Register Sessions', 'ar' => 'جلسات الكاشير'],
];
@ -2811,6 +2816,14 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<?php elseif ($page === 'pos'): ?>
<?php
// Check for active session
$stmt = db()->prepare("SELECT * FROM register_sessions WHERE user_id = ? AND status = 'open'");
$stmt->execute([$_SESSION['user_id']]);
$active_session = $stmt->fetch(PDO::FETCH_ASSOC);
$_SESSION['register_session_id'] = $active_session['id'] ?? null;
$registers = db()->query("SELECT * FROM cash_registers WHERE status = 'active'")->fetchAll();
$allow_zero_stock_sell = ($data['settings']['allow_zero_stock_sell'] ?? '1') === '1';
$sql = "SELECT * FROM stock_items ORDER BY name_en ASC";
$products_raw = db()->query($sql)->fetchAll(PDO::FETCH_ASSOC);
@ -2869,6 +2882,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<h6 class="m-0 fw-bold"><i class="bi bi-cart3 me-2"></i>Cart</h6>
<div class="d-flex gap-2">
<button class="btn btn-sm btn-outline-info" onclick="window.open('customer-display.php?v=<?= time() ?>', 'CustomerDisplay', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=' + screen.availWidth + ',height=' + screen.availHeight + ',left=0,top=0')" title="Customer Display"><i class="bi bi-display me-1"></i> Customer Screen</button>
<?php if ($active_session): ?>
<button class="btn btn-sm btn-outline-dark" data-bs-toggle="modal" data-bs-target="#closeRegisterModal" title="Close Register"><i class="bi bi-x-circle me-1"></i> Close</button>
<?php endif; ?>
<button class="btn btn-sm btn-outline-warning" onclick="cart.openHeldCartsModal()" title="Held List"><i class="bi bi-list-task"></i></button>
<button class="btn btn-sm btn-outline-secondary" onclick="cart.hold()" title="Hold Cart"><i class="bi bi-pause-circle"></i></button>
<button class="btn btn-sm btn-outline-danger" onclick="cart.clear()" title="Clear Cart"><i class="bi bi-trash"></i></button>
@ -3739,6 +3755,87 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
});
</script>
<?php if (!$active_session): ?>
<!-- Open Register Modal -->
<div class="modal fade" id="openRegisterModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Open Cash Register</h5>
</div>
<form method="POST">
<div class="modal-body">
<input type="hidden" name="open_register" value="1">
<div class="mb-3">
<label class="form-label">Select Register</label>
<select name="register_id" class="form-select" required>
<?php if (isset($registers)): foreach ($registers as $r): ?>
<option value="<?= $r['id'] ?>"><?= htmlspecialchars($r['name']) ?></option>
<?php endforeach; endif; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Opening Balance</label>
<div class="input-group">
<span class="input-group-text">OMR</span>
<input type="number" step="0.001" name="opening_balance" class="form-control" required placeholder="0.000">
</div>
</div>
</div>
<div class="modal-footer">
<a href="index.php?page=dashboard" class="btn btn-secondary">Cancel & Go to Dashboard</a>
<button type="submit" class="btn btn-primary">Open Session</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($active_session): ?>
<!-- Close Register Modal -->
<div class="modal fade" id="closeRegisterModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Close Cash Register</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<input type="hidden" name="close_register" value="1">
<input type="hidden" name="session_id" value="<?= $_SESSION['register_session_id'] ?? '' ?>">
<div class="mb-3">
<label class="form-label">Cash in Hand (Counted)</label>
<div class="input-group">
<span class="input-group-text">OMR</span>
<input type="number" step="0.001" name="cash_in_hand" class="form-control" required placeholder="0.000">
</div>
</div>
<div class="mb-3">
<label class="form-label">Notes</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Any discrepancies or notes..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Close Session</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
<?php if (!$active_session): ?>
var openModal = new bootstrap.Modal(document.getElementById('openRegisterModal'));
openModal.show();
<?php endif; ?>
});
</script>
<?php elseif ($page === 'quotations'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
@ -6053,6 +6150,68 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div>
</div>
<?php elseif ($page === 'customer_display_settings'): ?>
<div class="card p-4">
<h5 class="mb-4" data-en="Customer Display Settings" data-ar="إعدادات شاشة العميل">Customer Display Settings</h5>
<form method="POST" enctype="multipart/form-data">
<div class="row g-3">
<div class="col-md-12">
<h6 class="text-muted border-bottom pb-2" data-en="Greeting Message" data-ar="رسالة الترحيب">Greeting Message</h6>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Title" data-ar="العنوان">Title</label>
<input type="text" name="settings[customer_display_greeting_title]" class="form-control" value="<?= htmlspecialchars($data['settings']['customer_display_greeting_title'] ?? 'Welcome') ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Subtitle" data-ar="العنوان الفرعي">Subtitle</label>
<input type="text" name="settings[customer_display_greeting_text]" class="form-control" value="<?= htmlspecialchars($data['settings']['customer_display_greeting_text'] ?? 'We are ready to serve you.') ?>">
</div>
<div class="col-md-12 mt-4">
<h6 class="text-muted border-bottom pb-2" data-en="Slideshow Images" data-ar="صور العرض">Slideshow Images</h6>
<p class="text-muted small">Upload images for the customer display slideshow (1920x1080 recommended).</p>
</div>
<div class="col-md-4">
<label class="form-label">Slide 1</label>
<input type="file" name="display_slide_1" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['display_slide_1'])): ?>
<div class="mt-2 position-relative">
<img src="<?= htmlspecialchars($data['settings']['display_slide_1']) ?>?v=<?= time() ?>" alt="Slide 1" class="img-thumbnail" style="max-height: 120px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<label class="form-label">Slide 2</label>
<input type="file" name="display_slide_2" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['display_slide_2'])): ?>
<div class="mt-2 position-relative">
<img src="<?= htmlspecialchars($data['settings']['display_slide_2']) ?>?v=<?= time() ?>" alt="Slide 2" class="img-thumbnail" style="max-height: 120px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<label class="form-label">Slide 3</label>
<input type="file" name="display_slide_3" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['display_slide_3'])): ?>
<div class="mt-2 position-relative">
<img src="<?= htmlspecialchars($data['settings']['display_slide_3']) ?>?v=<?= time() ?>" alt="Slide 3" class="img-thumbnail" style="max-height: 120px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-12 mt-4">
<button type="submit" name="update_settings" class="btn btn-primary">
<i class="bi bi-save"></i> <span data-en="Save Changes" data-ar="حفظ التغييرات">Save Changes</span>
</button>
</div>
</div>
</form>
</div>
<?php elseif ($page === 'backups'): ?>
<div class="row g-4">
<div class="col-md-4">

View File

@ -19,3 +19,19 @@
2026-02-18 13:33:14 - POST: {"action":"save_pos_transaction","customer_id":"1","payments":"[{\"method\":\"credit\",\"amount\":1.19}]","total_amount":"1.19","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":1,\"qty\":2,\"price\":0.3825},{\"id\":2,\"qty\":2,\"price\":0.2125}]"}
2026-02-18 14:03:07 - POST: {"action":"hold_pos_cart","cart_name":"Cart 6:03:04 PM","items":"[{\"id\":1,\"nameEn\":\"Tomato\",\"nameAr\":\"\u0637\u0645\u0627\u0637\u0645\",\"price\":0.3825,\"stock_quantity\":-17.5,\"qty\":1}]","customer_id":""}
2026-02-18 14:03:18 - POST: {"action":"delete_held_cart","id":"9"}
2026-02-18 15:09:18 - POST: {"username":"admin","password":"admin","login":""}
2026-02-18 15:09:38 - POST: {"action":"save_theme","theme":"dark"}
2026-02-18 15:09:45 - POST: {"action":"save_theme","theme":"forest"}
2026-02-18 15:09:50 - POST: {"action":"save_theme","theme":"sunset"}
2026-02-18 15:09:55 - POST: {"action":"save_theme","theme":"dark"}
2026-02-18 15:10:04 - POST: {"action":"save_theme","theme":"forest"}
2026-02-18 15:10:09 - POST: {"action":"save_theme","theme":"sunset"}
2026-02-18 15:24:03 - POST: {"action":"save_theme","theme":"default"}
2026-02-18 15:32:30 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.595}]","total_amount":"0.595","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":1,\"qty\":1,\"price\":0.3825},{\"id\":2,\"qty\":1,\"price\":0.2125}]"}
2026-02-18 15:36:20 - POST: {"action":"save_theme","theme":"forest"}
2026-02-18 15:36:22 - POST: {"action":"save_theme","theme":"sunset"}
2026-02-18 15:37:25 - POST: {"action":"save_theme","theme":"default"}
2026-02-18 15:40:10 - POST: {"action":"save_theme","theme":"sunset"}
2026-02-18 15:40:14 - POST: {"action":"save_theme","theme":"ocean"}
2026-02-18 15:40:20 - POST: {"action":"save_theme","theme":"default"}
2026-02-18 17:02:02 - POST: {"settings":{"customer_display_greeting_title":"Welcome","customer_display_greeting_text":"\u0623\u0647\u0644\u0627 \u0648\u0633\u0647\u0644\u0627\u064b \u0628\u0643\u0640\u0640\u0645"},"update_settings":""}

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";profile_pic|s:32:"uploads/profile_1_1771401598.png";theme|s:7:"default";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";

View File

@ -1 +0,0 @@
user_id|i:1;username|s:5:"admin";user_role_name|s:13:"Administrator";user_permissions|s:3:"all";