445 lines
16 KiB
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.');
|
|
}
|
|
}
|
|
}
|