277 lines
11 KiB
PHP
277 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Reservasi;
|
|
use App\Models\Meja;
|
|
use App\Models\User;
|
|
use Illuminate\Http\Request;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class ReservationController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
$reservations = Reservasi::with(['user', 'meja'])
|
|
->orderBy('date', 'desc')
|
|
->orderBy('start_time', 'desc')
|
|
->get();
|
|
$users = User::where('role', 'user')->get();
|
|
|
|
// Get all tables regardless of status
|
|
$tables = Meja::orderBy('nomor_meja')->get();
|
|
|
|
return view('admin.reservations', compact('reservations', 'users', 'tables'));
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|exists:users,id',
|
|
'meja_id' => 'required|exists:meja,id',
|
|
'name' => 'required|string|max:255',
|
|
'phone' => 'required|string|max:20',
|
|
'date' => 'required|date|after_or_equal:today',
|
|
'start_time' => 'required|date_format:H:i',
|
|
'end_time' => 'required|date_format:H:i|after:start_time',
|
|
'notes' => 'nullable|string',
|
|
'total_harga' => 'required|numeric|min:0'
|
|
]);
|
|
|
|
// Check if the time slot is available
|
|
if (!Reservasi::isTimeSlotAvailable(
|
|
$request->meja_id,
|
|
$request->date,
|
|
$request->start_time,
|
|
$request->end_time
|
|
)) {
|
|
return back()->withErrors(['time' => 'Waktu yang dipilih sudah dipesan']);
|
|
}
|
|
|
|
try {
|
|
// Create reservation
|
|
$reservation = Reservasi::create([
|
|
'user_id' => $request->user_id,
|
|
'meja_id' => $request->meja_id,
|
|
'name' => $request->name,
|
|
'phone' => $request->phone,
|
|
'date' => $request->date,
|
|
'start_time' => $request->start_time,
|
|
'end_time' => $request->end_time,
|
|
'notes' => $request->notes,
|
|
'status' => 'pending',
|
|
'total_harga' => $request->total_harga
|
|
]);
|
|
|
|
// Update table status if reservation is for today
|
|
if ($request->date == now()->format('Y-m-d')) {
|
|
Meja::where('id', $request->meja_id)
|
|
->update(['status' => 'dipesan']);
|
|
}
|
|
|
|
return redirect()->back()->with('success', 'Reservasi berhasil ditambahkan');
|
|
} catch (\Exception $e) {
|
|
Log::error('Error creating reservation:', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
return back()->withErrors(['error' => 'Terjadi kesalahan saat membuat reservasi. Silakan coba lagi.'])->withInput();
|
|
}
|
|
}
|
|
|
|
public function update(Request $request, Reservasi $reservation)
|
|
{
|
|
$request->validate([
|
|
'status' => 'required|in:pending,confirmed,completed,cancelled',
|
|
'meja_id' => 'required|exists:meja,id'
|
|
]);
|
|
|
|
// Update both status and table
|
|
$reservation->update([
|
|
'status' => $request->status,
|
|
'meja_id' => $request->meja_id
|
|
]);
|
|
|
|
// Update table status based on reservation status
|
|
if ($reservation->date == now()->format('Y-m-d')) {
|
|
if ($request->status === 'confirmed') {
|
|
$reservation->meja()->update(['status' => 'dipesan']);
|
|
} elseif (in_array($request->status, ['completed', 'cancelled'])) {
|
|
$reservation->meja()->update(['status' => 'tersedia']);
|
|
}
|
|
}
|
|
|
|
if ($request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Reservasi berhasil diperbarui'
|
|
]);
|
|
}
|
|
|
|
return redirect()->back()->with('success', 'Reservasi berhasil diperbarui');
|
|
}
|
|
|
|
public function destroy(Reservasi $reservation)
|
|
{
|
|
try {
|
|
// Set table status back to available if reservation was for today
|
|
if ($reservation->date == now()->format('Y-m-d') && $reservation->meja) {
|
|
$reservation->meja()->update(['status' => 'tersedia']);
|
|
}
|
|
|
|
$reservation->delete();
|
|
return redirect()->back()->with('success', 'Reservasi berhasil dihapus');
|
|
} catch (\Exception $e) {
|
|
Log::error('Error deleting reservation:', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
return back()->withErrors(['error' => 'Terjadi kesalahan saat menghapus reservasi.']);
|
|
}
|
|
}
|
|
|
|
public function getAvailableTimeSlots(Request $request)
|
|
{
|
|
try {
|
|
Log::info('Admin getAvailableTimeSlots called with request:', [
|
|
'all_params' => $request->all(),
|
|
'date' => $request->date,
|
|
'meja_id' => $request->meja_id
|
|
]);
|
|
|
|
$request->validate([
|
|
'meja_id' => 'required|exists:meja,id',
|
|
'date' => 'required|date|after_or_equal:today',
|
|
]);
|
|
|
|
Log::info('Validation passed, getting reservations');
|
|
|
|
// Get existing reservations for this table and date
|
|
$reservations = Reservasi::where('meja_id', $request->meja_id)
|
|
->whereDate('date', $request->date)
|
|
->whereNotIn('status', ['cancelled'])
|
|
->get();
|
|
|
|
Log::info('Found existing reservations', [
|
|
'count' => $reservations->count(),
|
|
'reservations' => $reservations->toArray()
|
|
]);
|
|
|
|
$timeSlots = [];
|
|
$startHour = 10; // 10:00
|
|
$endHour = 22; // 22:00
|
|
$interval = 30; // 30 minutes interval
|
|
|
|
Log::info('Starting to generate time slots');
|
|
|
|
// Create a helper function to check if a time slot is reserved
|
|
$isTimeSlotReserved = function($checkTime) use ($reservations) {
|
|
$checkDateTime = Carbon::parse($checkTime);
|
|
foreach ($reservations as $reservation) {
|
|
$reservationStart = Carbon::parse($reservation->start_time);
|
|
$reservationEnd = Carbon::parse($reservation->end_time);
|
|
if ($checkDateTime->between($reservationStart, $reservationEnd, true)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// Generate all possible time slots
|
|
for ($hour = $startHour; $hour < $endHour; $hour++) {
|
|
for ($minute = 0; $minute < 60; $minute += $interval) {
|
|
$currentTime = sprintf('%02d:%02d', $hour, $minute);
|
|
|
|
// Check if this time slot is already reserved
|
|
$isReserved = $isTimeSlotReserved($currentTime);
|
|
|
|
if (!$isReserved) {
|
|
$endTimeOptions = [];
|
|
// Generate possible end times (30 minutes to 4 hours after start time)
|
|
for ($duration = 30; $duration <= 240; $duration += 30) {
|
|
$potentialEndTime = Carbon::parse($currentTime)->addMinutes($duration);
|
|
|
|
// Don't add end times past closing time
|
|
if ($potentialEndTime->format('H:i') > '22:00') {
|
|
continue;
|
|
}
|
|
|
|
// Check if any time between start and potential end time is reserved
|
|
$hasConflict = false;
|
|
$checkTime = Carbon::parse($currentTime);
|
|
while ($checkTime < $potentialEndTime) {
|
|
if ($isTimeSlotReserved($checkTime->format('H:i'))) {
|
|
$hasConflict = true;
|
|
break;
|
|
}
|
|
$checkTime->addMinutes(30);
|
|
}
|
|
|
|
if (!$hasConflict) {
|
|
$endTimeOptions[] = $potentialEndTime->format('H:i');
|
|
}
|
|
}
|
|
|
|
// Only add start time if it has at least one valid end time option
|
|
if (count($endTimeOptions) > 0) {
|
|
$timeSlots[] = [
|
|
'start_time' => $currentTime,
|
|
'end_time_options' => $endTimeOptions,
|
|
'is_available' => true
|
|
];
|
|
}
|
|
} else {
|
|
// Add reserved time slot
|
|
$timeSlots[] = [
|
|
'start_time' => $currentTime,
|
|
'end_time_options' => [],
|
|
'is_available' => false
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// If date is today, remove past time slots
|
|
if ($request->date == Carbon::today()->format('Y-m-d')) {
|
|
$currentTime = Carbon::now();
|
|
Log::info('Filtering past time slots for today', [
|
|
'current_time' => $currentTime->format('H:i'),
|
|
'before_count' => count($timeSlots)
|
|
]);
|
|
|
|
$timeSlots = array_filter($timeSlots, function($slot) use ($currentTime) {
|
|
return Carbon::parse($slot['start_time'])->gt($currentTime);
|
|
});
|
|
|
|
Log::info('After filtering past slots', [
|
|
'after_count' => count($timeSlots)
|
|
]);
|
|
}
|
|
|
|
$timeSlots = array_values($timeSlots);
|
|
|
|
Log::info('Generated available time slots', [
|
|
'count' => count($timeSlots),
|
|
'first_few_slots' => array_slice($timeSlots, 0, 3)
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $timeSlots
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('Error in admin getAvailableTimeSlots', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Terjadi kesalahan saat memuat jadwal: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
}
|