check() ? Cart::where('user_id', auth()->id())->with('menu')->get() : collect(); $totals = [ 'subtotal' => 0 ]; if ($cartItems->count() > 0) { $subtotal = $cartItems->sum(function ($item) { return $item->quantity * $item->menu->price; }); $totals = [ 'subtotal' => $subtotal ]; } return view('reservasi', compact('meja', 'cartItems', 'totals')); } catch (\Exception $e) { Log::error('Error in ReservasiController@index: ' . $e->getMessage()); return redirect()->route('menu.index')->with('error', 'Terjadi kesalahan. Silakan coba lagi.'); } } // Simpan data reservasi public function store(Request $request) { DB::beginTransaction(); try { // Validasi input $request->validate([ 'tanggal' => 'required|date|after_or_equal:today', 'start_time' => 'required' ]); $mejaId = session('selected_meja'); if (!$mejaId) { throw new \Exception('Silakan pilih meja terlebih dahulu'); } // Cek ketersediaan meja $meja = Meja::findOrFail($mejaId); if ($meja->status === 'tidak_tersedia') { throw new \Exception('Meja tidak tersedia'); } // Ambil items dari cart $cartItems = Cart::where('user_id', auth()->id()) ->with('menu') ->get(); if ($cartItems->isEmpty()) { throw new \Exception('Keranjang belanja kosong'); } // Hitung total harga $totalHarga = $cartItems->sum(function($item) { return $item->quantity * $item->menu->price; }); // Final amount sama dengan total harga karena tidak ada tax dan service charge $finalAmount = $totalHarga; // Buat reservasi $reservasi = Reservasi::create([ 'meja_id' => $mejaId, 'user_id' => auth()->id(), 'date' => $request->tanggal, 'start_time' => $request->start_time, 'status' => 'pending', 'name' => auth()->user()->name, 'phone' => auth()->user()->phone ?? '', 'total_harga' => $totalHarga ]); // Generate kode transaksi $transactionCode = 'TRX-' . date('Ymd') . '-' . strtoupper(uniqid()); // Buat transaksi $transaksi = Transaksi::create([ 'transaction_code' => $transactionCode, 'user_id' => auth()->id(), 'reservasi_id' => $reservasi->id, 'total_amount' => $totalHarga, 'final_amount' => $finalAmount, 'status' => 'pending' ]); // Simpan item transaksi foreach ($cartItems as $item) { TransaksiItem::create([ 'transaksi_id' => $transaksi->id, 'menu_id' => $item->menu_id, 'menu_name' => $item->menu->name, 'quantity' => $item->quantity, 'price' => $item->menu->price, 'subtotal' => $item->quantity * $item->menu->price ]); } // Update status meja jika reservasi untuk hari ini if ($request->tanggal === date('Y-m-d')) { $meja->status = 'dipesan'; $meja->save(); } // Hapus cart items Cart::where('user_id', auth()->id())->delete(); // Clear session meja session()->forget('selected_meja'); DB::commit(); // Redirect ke halaman detail transaksi return redirect()->route('transaksi.detail', $transaksi->id) ->with('success', 'Reservasi berhasil dibuat, silakan lakukan pembayaran'); } catch (\Exception $e) { DB::rollback(); Log::error('Error creating reservation and transaction: ' . $e->getMessage()); return back()->with('error', 'Terjadi kesalahan saat membuat reservasi: ' . $e->getMessage()); } } public function success($id) { $reservasi = Reservasi::with('meja')->findOrFail($id); return view('reservasi.success', compact('reservasi')); } public function checkAvailability(Request $request) { $request->validate([ 'tanggal' => 'required|date', 'meja_id' => 'required|exists:mejas,id' ]); $reservasi = Reservasi::where('meja_id', $request->meja_id) ->where('tanggal', $request->tanggal) ->get(); $bookedHours = []; foreach ($reservasi as $r) { $startTime = Carbon::parse($r->jam); for ($i = 0; $i < $r->durasi; $i++) { $bookedHours[] = $startTime->copy()->addHours($i)->format('H:i'); } } $availableHours = []; $start = Carbon::parse('10:00'); $end = Carbon::parse('22:00'); while ($start <= $end) { if (!in_array($start->format('H:i'), $bookedHours)) { $availableHours[] = $start->format('H:i'); } $start->addHour(); } return response()->json($availableHours); } public function getSchedule(Request $request, Meja $meja) { $date = $request->date; $reservations = Reservasi::where('meja_id', $meja->id) ->where('date', $date) ->where('status', '!=', 'cancelled') ->get(['start_time', 'end_time']); return response()->json([ 'success' => true, 'reservations' => $reservations ]); } public function getAvailableSlots(Request $request) { try { $date = $request->date; $mejaId = session('selected_meja'); if (!$date || !$mejaId) { return response()->json([ 'status' => 'error', 'error' => 'Data tidak lengkap' ], 400); } $meja = Meja::findOrFail($mejaId); $availableSlots = $meja->getAvailableTimeSlots($date); // Jika tanggal hari ini, filter slot yang sudah lewat if ($date === date('Y-m-d')) { $currentTime = Carbon::now(); $availableSlots = array_filter($availableSlots, function($slot) use ($currentTime) { return Carbon::parse($slot)->gt($currentTime); }); } return response()->json([ 'status' => 'success', 'data' => array_values($availableSlots) ]); } catch (\Exception $e) { Log::error('Error in getAvailableSlots: ' . $e->getMessage()); return response()->json([ 'status' => 'error', 'error' => 'Terjadi kesalahan saat memuat slot waktu' ], 500); } } /** * Handle Midtrans payment notification */ public function handlePaymentNotification(Request $request) { try { $notification = json_decode($request->getContent(), true); // Get transaction $transaction = Transaksi::where('transaction_code', $notification['order_id'])->firstOrFail(); $reservasi = $transaction->reservasi; // Update payment method based on Midtrans payment type $paymentType = $notification['payment_type']; switch ($paymentType) { case 'credit_card': $paymentMethod = 'credit_card'; break; case 'bank_transfer': $vaNumbers = $notification['va_numbers'][0] ?? null; if ($vaNumbers) { $bank = strtolower($vaNumbers['bank']); $paymentMethod = $bank . '_va'; } else { $paymentMethod = 'other_va'; } break; case 'gopay': $paymentMethod = 'gopay'; break; case 'shopeepay': $paymentMethod = 'shopeepay'; break; case 'qris': $paymentMethod = 'qris'; break; case 'cstore': $store = strtolower($notification['store']); $paymentMethod = $store; break; default: $paymentMethod = $paymentType; } // Update reservation payment method $reservasi->update([ 'payment_method' => $paymentMethod ]); // Handle transaction status if ($notification['transaction_status'] == 'capture' || $notification['transaction_status'] == 'settlement') { $transaction->update(['status' => 'paid']); $reservasi->update(['status' => 'confirmed']); } elseif ($notification['transaction_status'] == 'cancel' || $notification['transaction_status'] == 'deny' || $notification['transaction_status'] == 'expire') { $transaction->update(['status' => 'cancelled']); $reservasi->update(['status' => 'cancelled']); } return response()->json(['status' => 'success']); } catch (\Exception $e) { Log::error('Error handling Midtrans notification: ' . $e->getMessage()); return response()->json(['status' => 'error'], 500); } } }