where('user_id', auth()->id()) ->orderBy('created_at', 'desc') ->get(); return view('transaksi.index', compact('transaksi')); } // Menampilkan halaman transaksi berdasarkan ID reservasi public function show($id) { try { // Find the transaction with its relationships $transaksi = Transaksi::with(['reservasi.meja', 'items.menu', 'user']) ->where('user_id', auth()->id()) ->findOrFail($id); if (!$transaksi) { throw new \Exception('Transaksi tidak ditemukan'); } $reservasi = $transaksi->reservasi; if (!$reservasi) { throw new \Exception('Data reservasi tidak ditemukan'); } $items = $transaksi->items; // Get Midtrans snap token if payment is pending $snapToken = null; if ($transaksi->status === 'pending') { $midtransService = new \App\Services\MidtransService(); $snapToken = $midtransService->createTransaction($transaksi); } return view('transaksi', compact('transaksi', 'reservasi', 'items', 'snapToken')); } catch (\Exception $e) { Log::error('Error in TransaksiController@show: ' . $e->getMessage()); return redirect()->route('menu.index') ->with('error', 'Terjadi kesalahan saat menampilkan transaksi: ' . $e->getMessage()); } } // Simpan transaksi public function store(Request $request) { // Debug log Log::info('Transaksi Request:', $request->all()); // Validasi input $validated = $request->validate([ 'meja_id' => 'required|exists:meja,id', 'tanggal' => 'required|date|after_or_equal:today', 'jam' => 'required|date_format:H:i', 'durasi' => 'required|integer|min:1|max:4', 'jumlah_orang' => 'required|integer|min:1', 'payment_method' => 'required|in:cash,transfer,qris' ]); DB::beginTransaction(); try { // Cek ketersediaan meja $meja = Meja::findOrFail($validated['meja_id']); if ($meja->status !== 'tersedia') { return back()->with('error', 'Maaf, meja ini sudah tidak tersedia'); } // Cek kapasitas meja if ($validated['jumlah_orang'] > $meja->kapasitas) { return back()->with('error', 'Jumlah orang melebihi kapasitas meja'); } // Ambil items dari cart $cartItems = Cart::where('user_id', auth()->id()) ->with('menu') ->get(); Log::info('Cart Items:', $cartItems->toArray()); if ($cartItems->isEmpty()) { return back()->with('error', 'Keranjang belanja kosong'); } // Hitung total amount $totalAmount = $cartItems->sum(function($item) { return $item->price * $item->quantity; }); // Generate kode transaksi $transactionCode = 'TRX-' . date('Ymd') . '-' . strtoupper(uniqid()); // Final amount sama dengan total amount karena tidak ada tax dan service charge $finalAmount = $totalAmount; // Buat reservasi $reservasi = Reservasi::create([ 'meja_id' => $meja->id, 'user_id' => auth()->id(), 'date' => $validated['tanggal'], 'start_time' => $validated['jam'], 'end_time' => Carbon::parse($validated['jam'])->addHours($validated['durasi'])->format('H:i'), 'status' => 'pending' ]); Log::info('Created Reservasi:', $reservasi->toArray()); // Buat transaksi $transaksi = Transaksi::create([ 'transaction_code' => $transactionCode, 'user_id' => auth()->id(), 'reservasi_id' => $reservasi->id, 'total_amount' => $totalAmount, 'final_amount' => $finalAmount, 'status' => 'pending', 'payment_method' => $validated['payment_method'] ]); Log::info('Created Transaksi:', $transaksi->toArray()); // Simpan item transaksi foreach ($cartItems as $item) { $transaksiItem = TransaksiItem::create([ 'transaksi_id' => $transaksi->id, 'menu_id' => $item->menu_id, 'menu_name' => $item->menu->name, 'quantity' => $item->quantity, 'price' => $item->price, 'subtotal' => $item->subtotal ]); Log::info('Created TransaksiItem:', $transaksiItem->toArray()); } // Update status meja $meja->status = 'dipesan'; $meja->save(); // Hapus cart items Cart::where('user_id', auth()->id())->delete(); DB::commit(); return redirect()->route('transaksi.show', $transaksi->id) ->with('success', 'Reservasi berhasil dibuat, silahkan lakukan pembayaran'); } catch (\Exception $e) { DB::rollback(); Log::error('Transaksi Error:', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return back()->with('error', 'Terjadi kesalahan saat memproses transaksi: ' . $e->getMessage()); } } // Konfirmasi pembayaran public function confirm(Request $request, $id) { DB::beginTransaction(); try { $transaksi = Transaksi::with('reservasi')->findOrFail($id); // Pastikan transaksi milik user yang sedang login if ($transaksi->user_id !== auth()->id()) { throw new \Exception('Unauthorized access'); } // Pastikan status transaksi masih pending if ($transaksi->status !== 'pending') { throw new \Exception('Transaksi sudah tidak dapat diproses'); } // Update status transaksi $transaksi->status = 'paid'; $transaksi->paid_at = now(); $transaksi->save(); // Update status reservasi if ($transaksi->reservasi) { $transaksi->reservasi->status = 'confirmed'; $transaksi->reservasi->save(); } DB::commit(); return redirect()->route('transaksi.show', $id) ->with('success', 'Pembayaran berhasil dikonfirmasi'); } catch (\Exception $e) { DB::rollback(); Log::error('Error in payment confirmation: ' . $e->getMessage()); return back()->with('error', 'Terjadi kesalahan saat mengkonfirmasi pembayaran: ' . $e->getMessage()); } } // Callback untuk Midtrans notification public function notification(Request $request) { try { $midtransService = new \App\Services\MidtransService(); $notificationData = $midtransService->handleNotification(); Log::info('Processing Midtrans notification', $notificationData); // Handle order_id with modal suffix $originalOrderId = preg_replace('/-modal-\d+$/', '', $notificationData['order_id']); DB::beginTransaction(); $transaksi = Transaksi::where('transaction_code', $originalOrderId)->firstOrFail(); $reservasi = $transaksi->reservasi; // Get current status to check if we need to update $currentStatus = $transaksi->status; $newStatus = null; switch ($notificationData['transaction_status']) { case 'capture': if ($notificationData['payment_type'] == 'credit_card') { if ($notificationData['fraud_status'] == 'challenge') { $newStatus = 'pending'; } else { $newStatus = 'paid'; } } break; case 'settlement': $newStatus = 'paid'; break; case 'pending': $newStatus = 'pending'; break; case 'deny': case 'expire': case 'cancel': $newStatus = 'cancelled'; break; } // Only update if status has changed if ($newStatus && $currentStatus !== $newStatus) { Log::info("Updating transaction status from {$currentStatus} to {$newStatus}", [ 'transaction_code' => $transaksi->transaction_code ]); $transaksi->status = $newStatus; if ($newStatus === 'paid') { $transaksi->paid_at = now(); if ($reservasi) { $reservasi->status = 'confirmed'; $reservasi->save(); } } elseif ($newStatus === 'cancelled') { if ($reservasi) { $reservasi->status = 'cancelled'; $reservasi->save(); } } $transaksi->save(); } DB::commit(); return response()->json(['status' => 'success']); } catch (\Exception $e) { DB::rollback(); Log::error('Error processing Midtrans notification: ' . $e->getMessage(), [ 'trace' => $e->getTraceAsString() ]); return response()->json([ 'status' => 'error', 'message' => 'An error occurred while processing the payment notification' ], 500); } } // Add new method to check payment status public function checkStatus($id) { try { $transaksi = Transaksi::findOrFail($id); return response()->json([ 'status' => $transaksi->status, 'paid_at' => $transaksi->paid_at ? $transaksi->paid_at->format('Y-m-d H:i:s') : null ]); } catch (\Exception $e) { Log::error('Error checking payment status: ' . $e->getMessage()); return response()->json(['error' => 'Failed to check payment status'], 500); } } // Halaman sukses setelah pembayaran public function finish(Request $request) { try { $order_id = $request->order_id; $transaksi = Transaksi::where('transaction_code', $order_id)->firstOrFail(); return redirect()->route('transaksi.show', $transaksi->id) ->with('success', 'Pembayaran berhasil diproses'); } catch (\Exception $e) { Log::error('Payment Finish Error: ' . $e->getMessage()); return redirect()->route('transaksi.index') ->with('error', 'Terjadi kesalahan saat memproses pembayaran'); } } // Halaman saat pembayaran tidak berhasil public function unfinish(Request $request) { try { $order_id = $request->order_id; $transaksi = Transaksi::where('transaction_code', $order_id)->firstOrFail(); return redirect()->route('transaksi.show', $transaksi->id) ->with('error', 'Pembayaran belum selesai'); } catch (\Exception $e) { Log::error('Payment Unfinish Error: ' . $e->getMessage()); return redirect()->route('transaksi.index') ->with('error', 'Terjadi kesalahan saat memproses pembayaran'); } } // Halaman saat pembayaran error public function error(Request $request) { return redirect()->route('transaksi.index') ->with('error', 'Terjadi kesalahan dalam proses pembayaran'); } // Menampilkan detail transaksi untuk modal public function detail($id) { try { // Find the transaction with its relationships and get fresh data $transaksi = Transaksi::with(['reservasi.meja', 'items.menu', 'user']) ->where('user_id', auth()->id()) ->findOrFail($id); // Refresh the model to get the latest status $transaksi->refresh(); if (!$transaksi) { throw new \Exception('Transaksi tidak ditemukan'); } $reservasi = $transaksi->reservasi; if (!$reservasi) { throw new \Exception('Data reservasi tidak ditemukan'); } $items = $transaksi->items; // Get Midtrans snap token if payment is pending $snapToken = null; if ($transaksi->status === 'pending') { try { $midtransService = new \App\Services\MidtransService(); // Add modal suffix to create a unique order ID $originalCode = $transaksi->transaction_code; $transaksi->transaction_code = $originalCode . '-modal-' . time(); $snapToken = $midtransService->createTransaction($transaksi); // Restore original transaction code $transaksi->transaction_code = $originalCode; } catch (\Exception $e) { Log::error('Error creating Midtrans token for modal: ' . $e->getMessage()); // Continue without snap token } } return view('transaksi.detail', compact('transaksi', 'reservasi', 'items', 'snapToken')); } catch (\Exception $e) { return response()->json([ 'error' => 'Terjadi kesalahan saat menampilkan transaksi: ' . $e->getMessage() ], 500); } } public function cancel(Transaksi $transaksi) { try { // Check if transaction can be cancelled if ($transaksi->status !== 'pending') { return redirect()->back()->with('error', 'Hanya transaksi dengan status pending yang dapat dibatalkan.'); } DB::beginTransaction(); // Update transaction status $transaksi->update([ 'status' => 'cancelled' ]); // Update reservation status if ($transaksi->reservasi) { $transaksi->reservasi->update([ 'status' => 'cancelled' ]); // Update table status if the reservation is for today if ($transaksi->reservasi->date == now()->format('Y-m-d')) { $transaksi->reservasi->meja()->update([ 'status' => 'tersedia' ]); } } DB::commit(); return redirect()->route('transaksi.show', $transaksi->id) ->with('success', 'Pesanan berhasil dibatalkan.'); } catch (\Exception $e) { DB::rollback(); Log::error('Error cancelling transaction: ' . $e->getMessage()); return redirect()->back() ->with('error', 'Terjadi kesalahan saat membatalkan pesanan. Silakan coba lagi.'); } } }