File "manage_bookings.php"
Full path: /home/itsevak/public_html/prepaiddev.itsevak.com/operator/manage_bookings.php
File
size: 30.52 B (30.52 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 = '';
// Check if operator has active session
$currentSession = $db->fetch(
"SELECT os.*, fl.name as from_location_name
FROM operator_sessions os
JOIN from_locations fl ON os.from_location_id = fl.id
WHERE os.operator_id = ? AND os.status = 'active'",
[$user['id']]
);
if (!$currentSession) {
redirect('index.php');
}
// Handle status updates
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
if (!validateCSRFToken($_POST['csrf_token'] ?? '')) {
$errors[] = 'Invalid request. Please try again.';
} else {
$bookingId = (int)($_POST['booking_id'] ?? 0);
$newStatus = $_POST['new_status'] ?? '';
if (empty($bookingId) || empty($newStatus)) {
$errors[] = 'Missing booking information.';
} else {
try {
$updateFields = ['status = ?'];
$params = [$newStatus];
if ($newStatus === 'completed') {
$updateFields[] = 'completion_time = NOW()';
}
$sql = "UPDATE bookings SET " . implode(', ', $updateFields) . " WHERE id = ? AND operator_id = ?";
$params[] = $bookingId;
$params[] = $user['id'];
$db->query($sql, $params);
$success = 'Booking status updated successfully!';
} catch (Exception $e) {
$errors[] = 'Error updating booking: ' . $e->getMessage();
}
}
}
}
// Get filter parameters
$statusFilter = $_GET['status'] ?? '';
$startDate = $_GET['start_date'] ?? '';
$endDate = $_GET['end_date'] ?? '';
// Build query for bookings
$whereConditions = ['b.operator_id = ?', 'b.from_location_id = ?'];
$params = [$user['id'], $currentSession['from_location_id']];
if ($statusFilter) {
$whereConditions[] = 'b.status = ?';
$params[] = $statusFilter;
}
if ($startDate && $endDate) {
$whereConditions[] = 'DATE(b.created_at) BETWEEN ? AND ?';
$params[] = $startDate;
$params[] = $endDate;
} elseif ($startDate) {
$whereConditions[] = 'DATE(b.created_at) >= ?';
$params[] = $startDate;
} elseif ($endDate) {
$whereConditions[] = 'DATE(b.created_at) <= ?';
$params[] = $endDate;
}
$whereClause = implode(' AND ', $whereConditions);
// Get bookings for current session only
$bookings = $db->fetchAll(
"SELECT b.*, p.name as passenger_name, p.phone as passenger_phone,
tl.name as to_location_name, tl.city as to_city,
ar.number_plate, ar.unique_local_id, ao.name as owner_name
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 auto_rickshaws ar ON b.auto_rickshaw_id = ar.id
LEFT JOIN auto_owners ao ON ar.owner_id = ao.id
WHERE $whereClause
ORDER BY b.created_at DESC",
$params
);
// Get status counts for current session only
$statusCounts = $db->fetchAll(
"SELECT status, COUNT(*) as count FROM bookings WHERE operator_id = ? AND from_location_id = ? GROUP BY status",
[$user['id'], $currentSession['from_location_id']]
);
$statusStats = [];
foreach ($statusCounts as $stat) {
$statusStats[$stat['status']] = $stat['count'];
}
$pageTitle = 'Manage Bookings';
require_once '../includes/header.php';
?>
<div class="container py-4">
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-body">
<h2 class="card-title mb-2">Manage Bookings</h2>
<p class="card-text text-muted">
Current Location: <?php echo htmlspecialchars($currentSession['from_location_name'] ?? 'Location not set'); ?>
</p>
</div>
</div>
</div>
</div>
<?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; ?>
<!-- Status Statistics -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h3 class="card-title text-primary"><?php echo $statusStats['confirmed'] ?? 0; ?></h3>
<p class="card-text text-muted">Confirmed</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h3 class="card-title text-info"><?php echo $statusStats['in_progress'] ?? 0; ?></h3>
<p class="card-text text-muted">In Progress</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h3 class="card-title text-success"><?php echo $statusStats['completed'] ?? 0; ?></h3>
<p class="card-text text-muted">Completed</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<h3 class="card-title text-warning"><?php echo $statusStats['cancelled'] ?? 0; ?></h3>
<p class="card-text text-muted">Cancelled</p>
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-body">
<form method="GET" action="" class="row g-3">
<div class="col-md-4">
<label for="status" class="form-label">Status Filter</label>
<select class="form-select" id="status" name="status">
<option value="">All Statuses</option>
<option value="confirmed" <?php echo $statusFilter === 'confirmed' ? 'selected' : ''; ?>>Confirmed</option>
<option value="in_progress" <?php echo $statusFilter === 'in_progress' ? 'selected' : ''; ?>>In Progress</option>
<option value="completed" <?php echo $statusFilter === 'completed' ? 'selected' : ''; ?>>Completed</option>
<option value="cancelled" <?php echo $statusFilter === 'cancelled' ? 'selected' : ''; ?>>Cancelled</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Date Range</label>
<div class="input-group">
<input type="date" class="form-control" id="start_date" name="start_date" value="<?php echo htmlspecialchars($startDate); ?>" placeholder="From">
<span class="input-group-text">to</span>
<input type="date" class="form-control" id="end_date" name="end_date" value="<?php echo htmlspecialchars($endDate); ?>" placeholder="To">
</div>
</div>
<div class="col-md-2">
<label class="form-label"> </label>
<div class="d-grid">
<button type="submit" class="btn btn-primary">
<i class="bi bi-funnel"></i> Apply Filters
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Bookings Table -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="bi bi-list-check"></i> Bookings (<?php echo count($bookings); ?>)
</h5>
<a href="index.php" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> Back to Dashboard
</a>
</div>
<div class="card-body">
<?php if (empty($bookings)): ?>
<div class="text-center text-muted py-4">
<i class="bi bi-inbox" style="font-size: 3rem;"></i>
<p class="mt-2">No bookings found for the selected filters.</p>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Booking ID</th>
<th>Passenger</th>
<th>Destination</th>
<th>Auto Rickshaw</th>
<th>Amount</th>
<th>Status</th>
<th>Time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($bookings as $booking): ?>
<tr>
<td>
<strong>#<?php echo $booking['id']; ?></strong>
<br><small class="text-muted"><?php echo ucfirst($booking['booking_type']); ?></small>
</td>
<td>
<?php echo htmlspecialchars($booking['passenger_name']); ?>
<br><small class="text-muted"><?php echo $booking['passenger_phone']; ?></small>
</td>
<td>
<?php echo htmlspecialchars($booking['to_location_name']); ?>
<br><small class="text-muted"><?php echo $booking['to_city']; ?></small>
</td>
<td>
<?php if ($booking['auto_rickshaw_id']): ?>
<?php echo htmlspecialchars($booking['number_plate']); ?>
<br><small class="text-muted"><?php echo $booking['owner_name']; ?></small>
<?php else: ?>
<span class="text-muted">Not assigned</span>
<?php endif; ?>
</td>
<td>
<strong>₹<?php echo number_format($booking['total_amount'], 2); ?></strong>
<br><small class="text-muted">Fare: ₹<?php echo number_format($booking['fare_amount'], 2); ?></small>
</td>
<td>
<?php
$statusClass = [
'confirmed' => 'bg-warning',
'in_progress' => 'bg-info',
'completed' => 'bg-success',
'cancelled' => 'bg-danger'
];
$statusText = [
'confirmed' => 'Confirmed',
'in_progress' => 'In Progress',
'completed' => 'Completed',
'cancelled' => 'Cancelled'
];
?>
<span class="badge <?php echo $statusClass[$booking['status']] ?? 'bg-secondary'; ?>">
<?php echo $statusText[$booking['status']] ?? ucfirst($booking['status']); ?>
</span>
</td>
<td>
<?php echo date('H:i', strtotime($booking['created_at'])); ?>
<br><small class="text-muted"><?php echo date('M d', strtotime($booking['created_at'])); ?></small>
</td>
<td>
<div class="btn-group btn-group-sm">
<!-- View Booking Button (Always visible) -->
<button type="button" class="btn btn-outline-primary btn-sm"
onclick="viewBooking(<?php echo $booking['id']; ?>)">
<i class="bi bi-eye"></i> View
</button>
<?php if ($booking['status'] !== 'completed' && $booking['status'] !== 'cancelled'): ?>
<?php if ($booking['status'] === 'confirmed'): ?>
<button type="button" class="btn btn-info btn-sm"
onclick="updateStatus(<?php echo $booking['id']; ?>, 'in_progress')">
Start Trip
</button>
<?php elseif ($booking['status'] === 'in_progress'): ?>
<button type="button" class="btn btn-success btn-sm"
onclick="updateStatus(<?php echo $booking['id']; ?>, 'completed')">
Complete
</button>
<?php endif; ?>
<button type="button" class="btn btn-danger btn-sm"
onclick="updateStatus(<?php echo $booking['id']; ?>, 'cancelled')">
Cancel
</button>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!-- Status Update Form (Hidden) -->
<form id="statusUpdateForm" method="POST" action="" style="display: none;">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<input type="hidden" name="update_status" value="1">
<input type="hidden" name="booking_id" id="updateBookingId">
<input type="hidden" name="new_status" id="updateNewStatus">
</form>
<!-- View Booking Modal -->
<div class="modal fade" id="viewBookingModal" tabindex="-1" aria-labelledby="viewBookingModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="viewBookingModalLabel">
<i class="bi bi-eye"></i> Booking Details
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="viewBookingModalBody">
<!-- Content will be loaded here -->
<div class="text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<!-- Print Receipt Button - Only show when status is NOT cancelled -->
<button type="button" class="btn btn-primary" id="printBookingReceiptBtn" style="display: none;">
<i class="bi bi-printer"></i> Print Receipt
</button>
</div>
</div>
</div>
</div>
<script>
function updateStatus(bookingId, newStatus) {
if (confirm('Are you sure you want to update this booking status?')) {
document.getElementById('updateBookingId').value = bookingId;
document.getElementById('updateNewStatus').value = newStatus;
document.getElementById('statusUpdateForm').submit();
}
}
function viewBooking(bookingId) {
// Show the modal
const modal = new bootstrap.Modal(document.getElementById('viewBookingModal'));
modal.show();
// Load booking details via AJAX
loadBookingDetails(bookingId);
}
function loadBookingDetails(bookingId) {
const modalBody = document.getElementById('viewBookingModalBody');
const printBtn = document.getElementById('printBookingReceiptBtn');
// Show loading spinner
modalBody.innerHTML = `
<div class="text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
`;
// Fetch booking details
fetch(`get_booking_details.php?booking_id=${bookingId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
displayBookingDetails(data.booking);
// Set print button functionality for all bookings
printBtn.onclick = () => printBookingReceipt(data.booking);
} else {
modalBody.innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> ${data.message}
</div>
`;
}
})
.catch(error => {
console.error('Error:', error);
modalBody.innerHTML = `
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle"></i> Error loading booking details
</div>
`;
});
}
function displayBookingDetails(booking) {
const modalBody = document.getElementById('viewBookingModalBody');
const printBtn = document.getElementById('printBookingReceiptBtn');
const statusClass = {
'confirmed': 'bg-warning',
'in_progress': 'bg-info',
'completed': 'bg-success',
'cancelled': 'bg-danger'
};
const statusText = {
'confirmed': 'Confirmed',
'in_progress': 'In Progress',
'completed': 'Completed',
'cancelled': 'Cancelled'
};
// Show/hide print button based on status
if (booking.status === 'cancelled') {
printBtn.style.display = 'none';
} else {
printBtn.style.display = 'inline-block';
}
modalBody.innerHTML = `
<div class="row">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h6 class="card-title mb-0">
<i class="bi bi-person"></i> Passenger Information
</h6>
</div>
<div class="card-body">
<p><strong>Name:</strong> ${booking.passenger_name}</p>
<p><strong>Phone:</strong> ${booking.passenger_phone}</p>
<p><strong>Booking ID:</strong> #${booking.id}</p>
<p><strong>Booking Type:</strong> ${booking.booking_type}</p>
<p><strong>Created:</strong> ${new Date(booking.created_at).toLocaleString()}</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h6 class="card-title mb-0">
<i class="bi bi-geo-alt"></i> Location Details
</h6>
</div>
<div class="card-body">
<p><strong>From:</strong> ${booking.from_location_name || 'Not set'}</p>
<p><strong>To:</strong> ${booking.to_location_name}</p>
<p><strong>City:</strong> ${booking.to_city}</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h6 class="card-title mb-0">
<i class="bi bi-truck"></i> Auto Rickshaw Details
</h6>
</div>
<div class="card-body">
${booking.auto_rickshaw_id ? `
<p><strong>Number Plate:</strong> ${booking.number_plate}</p>
<p><strong>Owner:</strong> ${booking.owner_name}</p>
<p><strong>ID:</strong> ${booking.unique_local_id}</p>
` : '<p class="text-muted">Not assigned yet</p>'}
</div>
</div>
</div>
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header">
<h6 class="card-title mb-0">
<i class="bi bi-currency-exchange"></i> Payment Details
</h6>
</div>
<div class="card-body">
<p><strong>Commission Amount:</strong> ₹${parseFloat(booking.commission_amount).toFixed(2)}</p>
<p><strong>Fare Amount:</strong> ₹${parseFloat(booking.fare_amount).toFixed(2)}</p>
<p><strong>Total Amount:</strong> ₹${parseFloat(booking.total_amount).toFixed(2)}</p>
<p><strong>Status:</strong>
<span class="badge ${statusClass[booking.status]}">${statusText[booking.status]}</span>
</p>
</div>
</div>
</div>
</div>
${booking.confirmation_time ? `
<div class="row">
<div class="col-12">
<div class="card mb-3">
<div class="card-header">
<h6 class="card-title mb-0">
<i class="bi bi-clock"></i> Trip Timeline
</h6>
</div>
<div class="card-body">
<p><strong>Confirmed At:</strong> ${new Date(booking.confirmation_time).toLocaleString()}</p>
${booking.completion_time ? `<p><strong>Completed At:</strong> ${new Date(booking.completion_time).toLocaleString()}</p>` : ''}
</div>
</div>
</div>
</div>
` : ''}
`;
}
function printBookingReceipt(booking) {
// Create a new window for printing
const printWindow = window.open('', '_blank');
// Define status text mapping
const statusText = {
'confirmed': 'Confirmed',
'in_progress': 'In Progress',
'completed': 'Completed',
'cancelled': 'Cancelled'
};
const receiptContent = `
<!DOCTYPE html>
<html>
<head>
<title>Receipt #${booking.id}</title>
<style>
@media print {
body { margin: 0; padding: 0; }
.receipt { border: none; box-shadow: none; }
}
body {
font-family: 'Courier New', monospace;
margin: 5px;
font-size: 10px;
line-height: 1.2;
}
.receipt {
max-width: 300px;
margin: 0 auto;
border: 1px solid #000;
padding: 8px;
}
.header {
text-align: center;
border-bottom: 1px solid #000;
padding-bottom: 5px;
margin-bottom: 8px;
}
.header h3 {
margin: 0 0 2px 0;
font-size: 12px;
font-weight: bold;
}
.header p {
margin: 1px 0;
font-size: 9px;
}
.row {
border-bottom: 1px solid #ccc;
padding: 3px 0;
font-size: 9px;
}
.total {
border-top: 1px solid #000;
padding-top: 5px;
margin-top: 8px;
font-weight: bold;
}
.footer {
text-align: center;
margin-top: 8px;
padding-top: 5px;
border-top: 1px solid #ccc;
font-size: 8px;
}
.footer p { margin: 1px 0; }
</style>
</head>
<body>
<div class="receipt">
<div class="header">
<h3>AUTO RICKSHAW SERVICE</h3>
<p>Booking Receipt</p>
<p>Date: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}</p>
</div>
<div class="row">
<strong>Passenger:</strong> ${booking.passenger_name}
</div>
<div class="row">
<strong>From:</strong> ${booking.from_location_name || 'Not set'}
</div>
<div class="row">
<strong>To:</strong> ${booking.to_location_name}
</div>
${booking.auto_rickshaw_id ? `
<div class="row">
<strong>Rickshaw:</strong> ${booking.number_plate}
</div>
<div class="row">
<strong>Driver:</strong> ${booking.owner_name}
</div>
` : ''}
<div class="total">
<div style="display: flex; justify-content: space-between; margin-bottom: 3px;">
<span>Commission:</span>
<span>₹${parseFloat(booking.commission_amount).toFixed(2)}</span>
</div>
<div style="display: flex; justify-content: space-between; margin-bottom: 3px;">
<span>Fare:</span>
<span>₹${parseFloat(booking.fare_amount).toFixed(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>₹${parseFloat(booking.fare_amount).toFixed(2)}</span>
</div>
</div>
<div class="footer">
<p>Thank you for using our service!</p>
<p>Status: ${statusText[booking.status]}</p>
</div>
</div>
</body>
</html>
`;
printWindow.document.write(receiptContent);
printWindow.document.close();
// Wait for content to load then print
printWindow.onload = function() {
printWindow.print();
printWindow.close();
};
}
</script>
<?php require_once '../includes/footer.php'; ?>