Reservasi-Cafe/app/Http/Controllers/TransaksiController.php

445 lines
16 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Reservasi;
use App\Models\Cart;
use App\Models\Transaksi;
use App\Models\TransaksiItem;
use App\Models\Meja;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class TransaksiController extends Controller
{
// Menampilkan daftar transaksi
public function index()
{
$transaksi = Transaksi::with(['reservasi'])
->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.');
}
}
}