File "scan_qr.php"
Full path: /home/itsevak/public_html/prepaiddev.itsevak.com/operator/scan_qr.php
File
size: 51.32 B (51.32 KB bytes)
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor Back
<?php
require_once '../includes/functions.php';
// Require login and operator access
requireLogin();
if ($_SESSION['user_type'] !== 'operator') {
redirect('/auth/login.php');
}
$user = getCurrentUser();
$db = Database::getInstance();
$errors = [];
$success = '';
$scannedData = null;
$booking = null;
// Check if operator has active session
$currentSession = $db->fetch(
"SELECT * FROM operator_sessions WHERE operator_id = ? AND status = 'active'",
[$user['id']]
);
if (!$currentSession) {
redirect('/operator/');
}
// Handle QR code scanning (simulated)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!validateCSRFToken($_POST['csrf_token'] ?? '')) {
$errors[] = 'Invalid request. Please try again.';
} else {
$passengerQrData = $_POST['passenger_qr_data'] ?? '';
$rickshawQrData = $_POST['rickshaw_qr_data'] ?? '';
if (empty($passengerQrData)) {
$errors[] = 'Please scan the passenger QR code.';
} elseif (empty($rickshawQrData)) {
$errors[] = 'Please scan the auto rickshaw QR code.';
} else {
try {
// Process passenger QR code - handle multiple formats
$passengerQrInfo = null;
$bookingId = null;
// Try to parse as JSON first
try {
$passengerQrInfo = json_decode($passengerQrData, true);
if ($passengerQrInfo && isset($passengerQrInfo['booking_id'])) {
$bookingId = $passengerQrInfo['booking_id'];
} elseif ($passengerQrInfo && isset($passengerQrInfo['id'])) {
$bookingId = $passengerQrInfo['id'];
} elseif ($passengerQrInfo && isset($passengerQrInfo['booking'])) {
$bookingId = $passengerQrInfo['booking'];
} elseif ($passengerQrInfo && isset($passengerQrInfo['passenger_id'])) {
$bookingId = $passengerQrInfo['passenger_id'];
}
} catch (Exception $e) {
// JSON parsing failed, try other formats
}
// If JSON parsing failed or no booking_id found, try to extract from plain text
if (!$bookingId) {
// Try to extract booking ID from plain text (e.g., "BOOKING_123" or just "123")
if (preg_match('/booking[_-]?(\d+)/i', $passengerQrData, $matches)) {
$bookingId = $matches[1];
} elseif (preg_match('/(\d+)/', $passengerQrData, $matches)) {
// If just numbers, assume it's the booking ID
$bookingId = $matches[1];
}
}
if (!$bookingId) {
$errors[] = 'Invalid passenger QR code format. Could not extract booking ID.';
} else {
// Get booking details
$booking = $db->fetch(
"SELECT b.*, p.name as passenger_name, p.phone as passenger_phone,
tl.name as to_location_name, tl.city as to_city,
fl.name as from_location_name, fl.city as from_city
FROM bookings b
JOIN passengers p ON b.passenger_id = p.id
JOIN to_locations tl ON b.to_location_id = tl.id
LEFT JOIN from_locations fl ON b.from_location_id = fl.id
WHERE b.id = ? AND b.status = 'confirmed'",
[$bookingId]
);
if (!$booking) {
$errors[] = 'Booking not found or already processed.';
} else {
// Set the from_location_id based on operator's current session location
$db->query(
"UPDATE bookings SET from_location_id = ? WHERE id = ?",
[$currentSession['from_location_id'], $booking['id']]
);
// Calculate the actual fare based on pickup and destination locations
$actualFare = 0.00;
$fareDetails = $db->fetch(
"SELECT * FROM fare_details WHERE from_location_id = ? AND to_location_id = ? AND status = 'active'",
[$currentSession['from_location_id'], $booking['to_location_id']]
);
if ($fareDetails) {
$actualFare = $fareDetails['fix_rate'] ?? 50.00; // Use database fare
} else {
// If no specific fare found, use a default calculation
$actualFare = 50.00; // Base fare, could be enhanced with distance calculation
}
// Update the booking with the actual fare amount
$db->query(
"UPDATE bookings SET fare_amount = ? WHERE id = ?",
[$actualFare, $booking['id']]
);
// Process rickshaw QR code - handle multiple formats
$rickshawQrInfo = null;
$rickshawId = null;
// Try to parse as JSON first
try {
$rickshawQrInfo = json_decode($rickshawQrData, true);
if ($rickshawQrInfo && isset($rickshawQrInfo['auto_rickshaw_id'])) {
$rickshawId = $rickshawQrInfo['auto_rickshaw_id'];
} elseif ($rickshawQrInfo && isset($rickshawQrInfo['id'])) {
$rickshawId = $rickshawQrInfo['id'];
} elseif ($rickshawQrInfo && isset($rickshawQrInfo['rickshaw_id'])) {
$rickshawId = $rickshawQrInfo['rickshaw_id'];
} elseif ($rickshawQrInfo && isset($rickshawQrInfo['unique_local_id'])) {
$rickshawId = $rickshawQrInfo['unique_local_id'];
} elseif ($rickshawQrInfo && isset($rickshawQrInfo['number_plate'])) {
$rickshawId = $rickshawQrInfo['number_plate'];
}
} catch (Exception $e) {
// JSON parsing failed, try other formats
}
// If JSON parsing failed or no rickshaw ID found, try to extract from plain text
if (!$rickshawId) {
// Try to extract rickshaw ID from plain text (e.g., "RICKSHAW_123" or just "123")
if (preg_match('/rickshaw[_-]?(\d+)/i', $rickshawQrData, $matches)) {
$rickshawId = $matches[1];
} elseif (preg_match('/(\d+)/', $rickshawQrData, $matches)) {
// If just numbers, assume it's the rickshaw ID
$rickshawId = $matches[1];
}
}
if (!$rickshawId) {
$errors[] = 'Invalid auto rickshaw QR code format. Could not extract rickshaw ID.';
} else {
// Try different lookup strategies
$rickshaw = null;
// First try: Look by unique_local_id (most common in QR codes)
$rickshaw = $db->fetch(
"SELECT ar.*, ao.name as owner_name
FROM auto_rickshaws ar
JOIN auto_owners ao ON ar.owner_id = ao.id
WHERE ar.unique_local_id = ? AND ar.status = 'active'",
[$rickshawId]
);
if (!$rickshaw) {
// Second try: Look by number_plate
$rickshaw = $db->fetch(
"SELECT ar.*, ao.name as owner_name
FROM auto_rickshaws ar
JOIN auto_owners ao ON ar.owner_id = ao.id
WHERE ar.number_plate = ? AND ar.status = 'active'",
[$rickshawId]
);
if (!$rickshaw) {
// Third try: Look by ID
$rickshaw = $db->fetch(
"SELECT ar.*, ao.name as owner_name
FROM auto_rickshaws ar
JOIN auto_owners ao ON ar.owner_id = ao.id
WHERE ar.id = ? AND ar.status = 'active'",
[$rickshawId]
);
if (!$rickshaw) {
// Fourth try: Look by any field (case insensitive)
$rickshaw = $db->fetch(
"SELECT ar.*, ao.name as owner_name
FROM auto_rickshaws ar
JOIN auto_owners ao ON ar.owner_id = ao.id
WHERE (ar.id = ? OR ar.unique_local_id = ? OR ar.number_plate = ?) AND ar.status = 'active'",
[$rickshawId, $rickshawId, $rickshawId]
);
}
}
}
if (!$rickshaw) {
$errors[] = 'Auto rickshaw not found or inactive. Please check the QR code or contact support.';
} else {
// Both QR codes are valid, complete the booking
try {
// Update booking with rickshaw assignment and operator
$db->query(
"UPDATE bookings SET auto_rickshaw_id = ?, operator_id = ?, status = 'in_progress', confirmation_time = NOW() WHERE id = ?",
[$rickshaw['id'], $user['id'], $booking['id']]
);
// Update operator session stats
$db->query(
"UPDATE operator_sessions SET total_bookings = total_bookings + 1 WHERE id = ?",
[$currentSession['id']]
);
$success = 'Booking completed successfully! Rickshaw assigned to passenger.';
// Set scanned data for display
$scannedData = [
'type' => 'completed',
'passenger' => ['booking_id' => $bookingId],
'rickshaw' => ['auto_rickshaw_id' => $rickshawId],
'booking' => $booking,
'rickshaw_details' => $rickshaw,
'actual_fare' => $actualFare
];
} catch (Exception $e) {
$errors[] = 'Error completing booking: ' . $e->getMessage();
}
}
}
}
}
} catch (Exception $e) {
$errors[] = 'Error processing QR codes: ' . $e->getMessage();
}
}
}
}
$pageTitle = 'Scan QR Code';
require_once '../includes/header.php';
?>
<!-- Add HTML5 QR Code Scanner -->
<script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js"></script>
<style>
/* QR Scanner styling */
#qr-reader {
border: 2px solid #dee2e6;
border-radius: 0.5rem;
overflow: hidden;
}
#qr-reader video {
border-radius: 0.5rem;
}
#qr-reader-results {
min-height: 60px;
}
/* Custom QR Scanner Overlay */
.qr-scanner-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
opacity: 1;
visibility: visible;
transition: none;
pointer-events: auto;
}
.qr-scanner-overlay[style*="display: none"] {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.qr-scanner-content {
background: white;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
max-width: 600px;
width: 100%;
max-height: 90vh;
overflow: hidden;
display: flex;
flex-direction: column;
transform: none;
transition: none;
border: 1px solid #dee2e6;
}
.qr-scanner-overlay[style*="display: none"] .qr-scanner-content {
transform: none;
}
.qr-scanner-header {
padding: 1rem 1.5rem;
border-bottom: 1px solid #dee2e6;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f8f9fa;
margin: 0;
}
.qr-scanner-title {
margin: 0;
font-size: 1.1rem;
font-weight: 600;
color: #495057;
}
.qr-scanner-close {
background: none;
border: none;
font-size: 1.25rem;
color: #6c757d;
cursor: pointer;
padding: 0.25rem;
border-radius: 0.25rem;
transition: none;
}
.qr-scanner-close:hover {
color: #495057;
background-color: #e9ecef;
}
.qr-scanner-body {
padding: 2rem;
text-align: center;
flex: 1;
overflow-y: auto;
margin: 0;
}
.qr-scanner-footer {
padding: 1rem 1.5rem;
border-top: 1px solid #dee2e6;
background-color: #f8f9fa;
text-align: right;
margin: 0;
}
/* Disable any Bootstrap card effects */
.qr-scanner-overlay *,
.qr-scanner-overlay *:hover,
.qr-scanner-overlay *:focus,
.qr-scanner-overlay *:active {
transition: none !important;
animation: none !important;
transform: none !important;
box-shadow: none !important;
}
.qr-scanner-content:hover,
.qr-scanner-header:hover,
.qr-scanner-body:hover,
.qr-scanner-footer:hover {
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
transform: none !important;
}
/* Scan button styling */
.scan-btn {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.qr-input {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
/* QR input validation styling */
.qr-input.is-valid {
border-color: #198754;
box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
}
.qr-input.is-invalid {
border-color: #dc3545;
box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
}
/* Custom form styling to replace Bootstrap cards */
.scan-form-container {
background: white;
border: 1px solid #dee2e6;
border-radius: 0.5rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
overflow: hidden;
}
.scan-form-header {
padding: 1rem 1.25rem;
background-color: #f8f9fa;
border-bottom: 1px solid #dee2e6;
}
.scan-form-title {
color: #495057;
font-weight: 600;
}
.scan-form-subtitle {
margin: 0;
}
.scan-form-body {
padding: 1.25rem;
}
/* Disable all hover effects */
.scan-form-container:hover,
.scan-form-header:hover,
.scan-form-body:hover {
transform: none !important;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;
transition: none !important;
}
/* Print-specific styles */
@media print {
body * {
visibility: hidden;
}
#printableReceipt,
#printableReceipt * {
visibility: visible;
}
#printableReceipt {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 20px;
}
.receipt-container {
max-width: none !important;
margin: 0 !important;
padding: 0 !important;
}
}
/* Receipt styling */
.receipt-container {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.receipt-container h3 {
color: #333;
font-weight: bold;
}
.receipt-container strong {
color: #333;
}
/* Cancel button styling */
#cancelBookingBtn {
transition: all 0.2s ease-in-out;
}
#cancelBookingBtn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(220, 53, 69, 0.3);
}
#cancelBookingBtn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
</style>
<div class="container py-4">
<div class="row">
<div class="col-md-8 mx-auto">
<div class="scan-form-container">
<div class="scan-form-header">
<h3 class="scan-form-title mb-0">
<i class="bi bi-qr-code-scan"></i> Scan QR Code
</h3>
<p class="scan-form-subtitle text-muted mb-0">Scan passenger or auto rickshaw QR codes</p>
</div>
<div class="scan-form-body">
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<ul class="mb-0">
<?php foreach ($errors as $error): ?>
<li><?php echo htmlspecialchars($error); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success">
<?php echo htmlspecialchars($success); ?>
</div>
<?php endif; ?>
<?php if (!$scannedData): ?>
<!-- QR Code Scanner Form -->
<form method="POST" action="">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<div class="mb-4">
<label for="passenger_qr_data" class="form-label">
<i class="bi bi-person"></i> Passenger QR Code
</label>
<div class="input-group">
<input type="text" class="form-control qr-input" id="passenger_qr_data" name="passenger_qr_data"
placeholder="Scan passenger QR code..." readonly>
<button type="button" class="btn btn-outline-primary scan-btn" id="scanPassengerQRBtn">
<i class="bi bi-qr-code-scan"></i> Scan
</button>
</div>
<div class="form-text">Scan the passenger's QR code to get booking details</div>
<!-- Passenger QR Scanner Modal -->
<div id="passengerQRScannerOverlay" class="qr-scanner-overlay" style="display: none;">
<div class="qr-scanner-content">
<div class="qr-scanner-header">
<h5 class="qr-scanner-title">
<i class="bi bi-person"></i> Scan Passenger QR Code
</h5>
<button type="button" class="qr-scanner-close" id="closePassengerQRScanner">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="qr-scanner-body">
<div id="passenger-qr-reader" style="width: 100%; max-width: 500px; margin: 0 auto;"></div>
<div id="passenger-qr-reader-results" class="mt-3"></div>
</div>
<div class="qr-scanner-footer">
<button type="button" class="btn btn-secondary" id="cancelPassengerQRScanner">Cancel</button>
</div>
</div>
</div>
</div>
<div class="mb-4">
<label for="rickshaw_qr_data" class="form-label">
<i class="bi bi-truck"></i> Auto Rickshaw QR Code
</label>
<div class="input-group">
<input type="text" class="form-control qr-input" id="rickshaw_qr_data" name="rickshaw_qr_data"
placeholder="Scan auto rickshaw QR code..." readonly>
<button type="button" class="btn btn-outline-success scan-btn" id="scanRickshawQRBtn">
<i class="bi bi-qr-code-scan"></i> Scan
</button>
</div>
<div class="form-text">Scan the auto rickshaw's QR code to assign it to the passenger</div>
<!-- Rickshaw QR Scanner Modal -->
<div id="rickshawQRScannerOverlay" class="qr-scanner-overlay" style="display: none;">
<div class="qr-scanner-content">
<div class="qr-scanner-header">
<h5 class="qr-scanner-title">
<i class="bi bi-truck"></i> Scan Auto Rickshaw QR Code
</h5>
<button type="button" class="qr-scanner-close" id="closeRickshawQRScanner">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="qr-scanner-body">
<div id="rickshaw-qr-reader" style="width: 100%; max-width: 500px; margin: 0 auto;"></div>
<div id="rickshaw-qr-reader-results" class="mt-3"></div>
</div>
<div class="qr-scanner-footer">
<button type="button" class="btn btn-secondary" id="cancelRickshawQRScanner">Cancel</button>
</div>
</div>
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg" id="processBookingBtn" disabled>
<i class="bi bi-check-circle"></i> Process Booking
</button>
</div>
</form>
<!-- Manual Entry Option -->
<div class="mt-4">
<hr>
<h6>Manual Entry</h6>
<p class="text-muted">If QR code scanning is not working, you can manually enter the information:</p>
<a href="direct_booking.php" class="btn btn-outline-secondary">
<i class="bi bi-pencil"></i> Manual Booking Entry
</a>
</div>
<?php else: ?>
<!-- Display Scanned Data -->
<?php if ($scannedData['type'] === 'completed'): ?>
<!-- Complete Booking -->
<div class="alert alert-success">
<h6><i class="bi bi-check-circle"></i> Both QR Codes Scanned Successfully!</h6>
<p class="mb-0">Booking has been completed and rickshaw assigned to passenger.</p>
</div>
<!-- Print Receipt Section -->
<div class="d-print-none mb-4">
<button type="button" class="btn btn-primary" id="printReceiptBtn" onclick="printReceipt()">
<i class="bi bi-printer"></i> Print Receipt
</button>
<!-- Cancel Booking Button - Only show when status is in_progress -->
<button type="button" class="btn btn-danger ms-2" id="cancelBookingBtn" onclick="cancelBooking()">
<i class="bi bi-x-circle"></i> Cancel Booking
</button>
</div>
<!-- Printable Receipt -->
<div id="printableReceipt" class="d-none d-print-block">
<div class="receipt-container" style="max-width: 300px; margin: 0 auto; padding: 8px; font-family: 'Courier New', monospace; font-size: 10px; line-height: 1.2;">
<div style="text-align: center; border-bottom: 1px solid #000; padding-bottom: 5px; margin-bottom: 8px;">
<h3 style="margin: 0 0 2px 0; font-size: 12px; font-weight: bold;">AUTO RICKSHAW SERVICE</h3>
<p style="margin: 1px 0; font-size: 9px;">Booking Receipt</p>
<p style="margin: 1px 0; font-size: 9px;">Date: <?php echo date('d/m/Y H:i:s'); ?></p>
</div>
<div style="margin-bottom: 8px;">
<div style="border-bottom: 1px solid #ccc; padding: 3px 0; font-size: 9px;">
<strong>Passenger:</strong> <?php echo htmlspecialchars($scannedData['booking']['passenger_name']); ?>
</div>
<div style="border-bottom: 1px solid #ccc; padding: 3px 0; font-size: 9px;">
<strong>From:</strong> <?php echo htmlspecialchars($scannedData['booking']['from_location_name']); ?>
</div>
<div style="border-bottom: 1px solid #ccc; padding: 3px 0; font-size: 9px;">
<strong>To:</strong> <?php echo htmlspecialchars($scannedData['booking']['to_location_name']); ?>
</div>
<div style="border-bottom: 1px solid #ccc; padding: 3px 0; font-size: 9px;">
<strong>Rickshaw:</strong> <?php echo htmlspecialchars($scannedData['rickshaw_details']['number_plate']); ?>
</div>
<div style="border-bottom: 1px solid #ccc; padding: 3px 0; font-size: 9px;">
<strong>Driver:</strong> <?php echo htmlspecialchars($scannedData['rickshaw_details']['owner_name']); ?>
</div>
</div>
<div style="border-top: 1px solid #000; padding-top: 5px; margin-top: 8px;">
<div style="display: flex; justify-content: space-between; margin-bottom: 3px; font-size: 9px;">
<span>Commission:</span>
<span>₹<?php echo number_format($scannedData['booking']['commission_amount'], 2); ?></span>
</div>
<div style="display: flex; justify-content: space-between; margin-bottom: 3px; font-size: 9px;">
<span>Fare:</span>
<span>₹<?php echo number_format($scannedData['actual_fare'], 2); ?></span>
</div>
<div style="display: flex; justify-content: space-between; font-weight: bold; font-size: 16px; margin-top: 8px; padding-top: 8px; border-top: 2px solid #000;">
<span>Total:</span>
<span>₹<?php echo number_format($scannedData['actual_fare'], 2); ?></span>
</div>
</div>
<div style="text-align: center; margin-top: 8px; padding-top: 5px; border-top: 1px solid #ccc; font-size: 8px;">
<p style="margin: 1px 0;">Thank you for using our service!</p>
<p style="margin: 1px 0;">Status: Completed</p>
</div>
</div>
</div>
<!-- Screen Display (Non-Printable) -->
<div class="d-print-none">
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h6 class="card-title mb-0">Passenger Details</h6>
</div>
<div class="card-body">
<p><strong>Name:</strong> <?php echo htmlspecialchars($scannedData['booking']['passenger_name']); ?></p>
<p><strong>Phone:</strong> <?php echo htmlspecialchars($scannedData['booking']['passenger_phone']); ?></p>
<p><strong>Destination:</strong> <?php echo htmlspecialchars($scannedData['booking']['to_location_name']); ?></p>
<p><strong>Booking ID:</strong> #<?php echo $scannedData['booking']['id']; ?></p>
<p><strong>Calculated Fare:</strong> ₹<?php echo number_format($scannedData['actual_fare'], 2); ?></p>
<p><strong>Commission Paid:</strong> ₹<?php echo number_format($scannedData['booking']['commission_amount'], 2); ?></p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h6 class="card-title mb-0">Auto Rickshaw Details</h6>
</div>
<div class="card-body">
<p><strong>Number Plate:</strong> <?php echo htmlspecialchars($scannedData['rickshaw_details']['number_plate']); ?></p>
<p><strong>Owner:</strong> <?php echo htmlspecialchars($scannedData['rickshaw_details']['owner_name']); ?></p>
<p><strong>ID:</strong> <?php echo htmlspecialchars($scannedData['rickshaw_details']['unique_local_id']); ?></p>
</div>
</div>
</div>
</div>
<div class="alert alert-info mt-4">
<h6><i class="bi bi-info-circle"></i> Booking Status:</h6>
<p class="mb-0">The passenger has been successfully assigned to the auto rickshaw. The booking is now in progress.</p>
<p class="mb-0 mt-2"><strong>Fare Calculation:</strong> Actual fare (₹<?php echo number_format($scannedData['actual_fare'], 2); ?>) has been calculated based on pickup location and destination.</p>
<p class="mb-0 mt-2"><strong>Payment:</strong> Passenger has already paid commission (₹<?php echo number_format($scannedData['booking']['commission_amount'], 2); ?>). They need to pay the fare amount (₹<?php echo number_format($scannedData['actual_fare'], 2); ?>) to the driver.</p>
<p class="mb-0 mt-2"><strong>Next Step:</strong> Print the receipt to mark this booking as completed.</p>
</div>
</div>
<?php endif; ?>
<div class="mt-4">
<a href="scan_qr.php" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Scan Another QR Code
</a>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<script>
// QR Scanner functionality
let passengerHtml5QrcodeScanner = null;
let rickshawHtml5QrcodeScanner = null;
let isPassengerScannerInitialized = false;
let isRickshawScannerInitialized = false;
$(document).ready(function() {
// Handle Passenger QR scan button click
$('#scanPassengerQRBtn').on('click', function() {
$('#passengerQRScannerOverlay').show();
initializeQRScanner('passenger');
});
// Handle Rickshaw QR scan button click
$('#scanRickshawQRBtn').on('click', function() {
$('#rickshawQRScannerOverlay').show();
initializeQRScanner('rickshaw');
});
// Handle close button clicks
$('#closePassengerQRScanner').on('click', function() {
closeQRScanner('passenger');
});
$('#closeRickshawQRScanner').on('click', function() {
closeQRScanner('rickshaw');
});
// Handle cancel button clicks
$('#cancelPassengerQRScanner').on('click', function() {
closeQRScanner('passenger');
});
$('#cancelRickshawQRScanner').on('click', function() {
closeQRScanner('rickshaw');
});
// Close scanner when clicking outside the content
$('#passengerQRScannerOverlay').on('click', function(e) {
if (e.target === this) {
closeQRScanner('passenger');
}
});
$('#rickshawQRScannerOverlay').on('click', function(e) {
if (e.target === this) {
closeQRScanner('rickshaw');
}
});
// Check if both QR codes are scanned to enable Process Booking button
function checkBothQRCodesScanned() {
const passengerData = $('#passenger_qr_data').val().trim();
const rickshawData = $('#rickshaw_qr_data').val().trim();
if (passengerData && rickshawData) {
$('#processBookingBtn').prop('disabled', false);
} else {
$('#processBookingBtn').prop('disabled', true);
}
}
// Monitor both input fields for changes
$('#passenger_qr_data, #rickshaw_qr_data').on('input', checkBothQRCodesScanned);
function closeQRScanner(type) {
if (type === 'passenger') {
$('#passengerQRScannerOverlay').hide();
if (passengerHtml5QrcodeScanner && isPassengerScannerInitialized) {
try {
passengerHtml5QrcodeScanner.stop();
passengerHtml5QrcodeScanner.clear();
} catch (e) {
// Passenger scanner cleanup error handled silently
}
passengerHtml5QrcodeScanner = null;
isPassengerScannerInitialized = false;
}
$('#passenger-qr-reader-results').empty();
} else {
$('#rickshawQRScannerOverlay').hide();
if (rickshawHtml5QrcodeScanner && isRickshawScannerInitialized) {
try {
rickshawHtml5QrcodeScanner.stop();
rickshawHtml5QrcodeScanner.clear();
} catch (e) {
// Rickshaw scanner cleanup error handled silently
}
rickshawHtml5QrcodeScanner = null;
isRickshawScannerInitialized = false;
}
$('#rickshaw-qr-reader-results').empty();
}
}
function initializeQRScanner(type) {
const scannerId = type === 'passenger' ? 'passenger-qr-reader' : 'rickshaw-qr-reader';
const resultsId = type === 'passenger' ? 'passenger-qr-reader-results' : 'rickshaw-qr-reader-results';
if (type === 'passenger') {
if (passengerHtml5QrcodeScanner) {
try {
passengerHtml5QrcodeScanner.clear();
} catch (e) {
// Passenger scanner clear error handled silently
}
}
} else {
if (rickshawHtml5QrcodeScanner) {
try {
rickshawHtml5QrcodeScanner.clear();
} catch (e) {
// Rickshaw scanner clear error handled silently
}
}
}
try {
const scanner = new Html5Qrcode(scannerId);
const config = {
fps: 10,
qrbox: { width: 250, height: 250 },
aspectRatio: 1.0
};
scanner.start(
{ facingMode: "environment" },
config,
(decodedText, decodedResult) => onScanSuccess(decodedText, decodedResult, type),
(error) => onScanFailure(error, type)
).then(() => {
if (type === 'passenger') {
isPassengerScannerInitialized = true;
passengerHtml5QrcodeScanner = scanner;
} else {
isRickshawScannerInitialized = true;
rickshawHtml5QrcodeScanner = scanner;
}
}).catch(function (err) {
console.error('Scanner start error:', err);
$(`#${resultsId}`).html(`
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> Camera access error: ${err.message}
</div>
`);
});
} catch (error) {
$(`#${resultsId}`).html(`
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> Failed to initialize scanner
</div>
`);
}
}
function onScanSuccess(decodedText, decodedResult, type) {
// Stop scanning
if (type === 'passenger') {
passengerHtml5QrcodeScanner.stop();
} else {
rickshawHtml5QrcodeScanner.stop();
}
// Process the scanned QR code
processScannedQR(decodedText, type);
// Close modal
if (type === 'passenger') {
$('#passengerQRScannerOverlay').hide();
} else {
$('#rickshawQRScannerOverlay').hide();
}
// Show success message
const resultsId = type === 'passenger' ? 'passenger-qr-reader-results' : 'rickshaw-qr-reader-results';
$(`#${resultsId}`).html(`
<div class="alert alert-success">
<i class="bi bi-check-circle"></i> QR Code scanned successfully!
</div>
`);
// Check if both QR codes are scanned
checkBothQRCodesScanned();
}
function onScanFailure(error, type) {
// Handle scan failure silently
}
function processScannedQR(qrData, type) {
try {
if (type === 'passenger') {
// Update passenger QR input
$('#passenger_qr_data').val(qrData);
$('#passenger_qr_data').addClass('is-valid');
setTimeout(() => {
$('#passenger_qr_data').removeClass('is-valid');
}, 2000);
} else {
// Update rickshaw QR input
$('#rickshaw_qr_data').val(qrData);
$('#rickshaw_qr_data').addClass('is-valid');
setTimeout(() => {
$('#rickshaw_qr_data').removeClass('is-valid');
}, 2000);
}
} catch (error) {
console.error('Error processing QR data:', error);
const inputId = type === 'passenger' ? 'passenger_qr_data' : 'rickshaw_qr_data';
$(`#${inputId}`).addClass('is-invalid');
$(`#${inputId}`).val('Invalid QR code format');
setTimeout(() => {
$(`#${inputId}`).removeClass('is-invalid');
$(`#${inputId}`).val('');
}, 3000);
}
}
// Print receipt functionality
window.printReceipt = function() {
// Show the printable receipt
$('#printableReceipt').removeClass('d-none');
// Hide non-printable elements
$('.d-print-none').hide();
// Print the page
window.print();
// After printing, update booking status to completed
setTimeout(() => {
// Restore the display
$('#printableReceipt').addClass('d-none');
$('.d-print-none').show();
// Update booking status to completed via AJAX
updateBookingStatus();
}, 1000);
};
// Function to update booking status to completed
function updateBookingStatus() {
const bookingId = <?php echo $scannedData['booking']['id'] ?? 'null'; ?>;
if (bookingId) {
$.ajax({
url: 'update_booking_status.php',
type: 'POST',
data: {
booking_id: bookingId,
status: 'completed',
csrf_token: '<?php echo generateCSRFToken(); ?>'
},
success: function(response) {
try {
const result = JSON.parse(response);
if (result.success) {
// Update the display to show completed status
updateDisplayToCompleted();
} else {
console.error('Failed to update booking status:', result.message);
}
} catch (e) {
console.error('Error parsing response:', e);
}
},
error: function(xhr, status, error) {
console.error('AJAX error:', error);
}
});
}
}
// Function to update display to show completed status
function updateDisplayToCompleted() {
// Update the success alert
$('.alert-success h6').html('<i class="bi bi-check-circle"></i> Booking Completed and Receipt Printed!');
$('.alert-success p').text('The booking has been marked as completed and receipt has been printed.');
// Update the print button to show completed
$('#printReceiptBtn').html('<i class="bi bi-check-circle"></i> Receipt Printed');
$('#printReceiptBtn').removeClass('btn-primary').addClass('btn-success');
$('#printReceiptBtn').prop('disabled', true);
// Hide the cancel booking button since status is now completed
$('#cancelBookingBtn').hide();
// Add a completion timestamp
if (!$('.completion-timestamp').length) {
$('.alert-success').append('<p class="completion-timestamp mb-0 mt-2"><small>Completed at: ' + new Date().toLocaleString() + '</small></p>');
}
}
// Function to cancel booking
window.cancelBooking = function() {
if (confirm('Are you sure you want to cancel this booking? This action cannot be undone.')) {
const bookingId = <?php echo $scannedData['booking']['id'] ?? 'null'; ?>;
if (bookingId) {
// Show loading state
$('#cancelBookingBtn').html('<i class="bi bi-hourglass-split"></i> Cancelling...');
$('#cancelBookingBtn').prop('disabled', true);
$.ajax({
url: 'update_booking_status.php',
type: 'POST',
data: {
booking_id: bookingId,
status: 'cancelled',
csrf_token: '<?php echo generateCSRFToken(); ?>'
},
success: function(response) {
try {
const result = JSON.parse(response);
if (result.success) {
// Update the display to show cancelled status
updateDisplayToCancelled();
} else {
alert('Failed to cancel booking: ' + result.message);
// Reset button state
$('#cancelBookingBtn').html('<i class="bi bi-x-circle"></i> Cancel Booking');
$('#cancelBookingBtn').prop('disabled', false);
}
} catch (e) {
alert('Error processing response. Please try again.');
// Reset button state
$('#cancelBookingBtn').html('<i class="bi bi-x-circle"></i> Cancel Booking');
$('#cancelBookingBtn').prop('disabled', false);
}
},
error: function(xhr, status, error) {
let errorMessage = 'Network error. Please try again.';
if (xhr.responseText) {
try {
const response = JSON.parse(xhr.responseText);
if (response.message) {
errorMessage = response.message;
}
} catch (e) {
// If response is not JSON, use the raw text
if (xhr.responseText.length < 100) {
errorMessage = 'Server error: ' + xhr.responseText;
}
}
}
alert(errorMessage);
// Reset button state
$('#cancelBookingBtn').html('<i class="bi bi-x-circle"></i> Cancel Booking');
$('#cancelBookingBtn').prop('disabled', false);
}
});
}
}
};
// Function to update display to show cancelled status
function updateDisplayToCancelled() {
// Update the success alert to show cancelled status
$('.alert-success').removeClass('alert-success').addClass('alert-warning');
$('.alert-success h6').html('<i class="bi bi-exclamation-triangle"></i> Booking Cancelled');
$('.alert-success p').text('The booking has been cancelled successfully.');
// Hide the print receipt button completely for cancelled bookings
$('#printReceiptBtn').hide();
// Hide the cancel booking button
$('#cancelBookingBtn').hide();
// Update the receipt status
$('#printableReceipt .receipt-container .footer p:last-child').text('Status: Cancelled');
// Add a cancellation timestamp
if (!$('.cancellation-timestamp').length) {
$('.alert-warning').append('<p class="cancellation-timestamp mb-0 mt-2"><small>Cancelled at: ' + new Date().toLocaleString() + '</small></p>');
}
// Update the instructions
$('.alert-info').removeClass('alert-info').addClass('alert-warning');
$('.alert-info h6').html('<i class="bi bi-info-circle"></i> Booking Cancelled');
$('.alert-info ol').html('<li>This booking has been cancelled</li><li>No payment is required</li><li>No commission will be earned</li>');
}
});
</script>
<?php require_once '../includes/footer.php'; ?>