get(); return view('user/booking-foto', compact('foto')); } public function detail($id) { $foto = PaketFoto::findOrFail($id); \Carbon\Carbon::setLocale('id'); $additionals = Additional::all(); $start = \Carbon\Carbon::now(); $end = \Carbon\Carbon::now()->addMonth(); $prevMonth = $start->copy()->subMonth(); $nextMonth = $start->copy()->addMonth(); $currentMonthLabel = $start->isoFormat('MMMM YYYY'); return view('user.detail-foto', compact('foto', 'additionals', 'start', 'end', 'currentMonthLabel', 'prevMonth', 'nextMonth')); } public function loadCalendar(Request $request) { \Carbon\Carbon::setLocale('id'); $month = $request->month ?? date('m'); $year = $request->year ?? date('Y'); $start = \Carbon\Carbon::createFromDate($year, $month, 1); $prevMonth = $start->copy()->subMonth(); $nextMonth = $start->copy()->addMonth(); $currentMonthLabel = $start->isoFormat('MMMM YYYY'); $html = view('user.components.calendar-grid', compact( 'start', 'prevMonth', 'nextMonth', 'currentMonthLabel' ))->render(); return response()->json(['html' => $html]); } public function cekSlot(Request $request) { $booked = BookingFoto::where('tgl_booking', $request->tanggal) ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima', 'selesai']) ->get(['jam_mulai']); return response()->json($booked); } public function formulir(Request $request) { $details = $this->calculateDetails($request); if (!session()->has('payment_deadline')) { session()->put('payment_deadline', now()->addHours(2)); } $sisaWaktu = now()->diffInSeconds(session('payment_deadline'), false); if ($sisaWaktu <= 0) { session()->forget(['payment_deadline', 'addons']); return redirect()->route('booking.foto')->with('error', 'Waktu pembayaran telah habis.'); } return view('user.pembayaran-foto', array_merge($details, [ 'sisaWaktu' => $sisaWaktu, 'request' => $request ])); } public function cancelBooking() { session()->forget(['payment_deadline', 'addons']); return redirect()->route('booking.foto'); } public function store(BookingFotoRequest $request) { $details = $this->calculateDetails($request); return DB::transaction(function () use ($request, $details) { if (BookingFoto::where(['tgl_booking' => $request->tgl_booking, 'jam_mulai' => $request->jam_mulai]) ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima'])->exists() ) { return back()->with('error', 'Slot baru saja diambil orang lain.'); } $pelanggan = Pelanggan::firstOrCreate(['no_wa' => $request->no_wa], ['nama' => $request->nama]); $pathBukti = $request->hasFile('bukti_bayar') ? $request->file('bukti_bayar')->store('img/payment/foto', 'public') : null; $booking = BookingFoto::create([ 'no_invoice' => 'INV-FOTO-' . strtoupper(Str::random(6)), 'id_pelanggan' => $pelanggan->id_pelanggan, 'id_paket' => $details['foto']->id_paket, 'tgl_booking' => $request->tgl_booking, 'jam_mulai' => $request->jam_mulai, 'jam_selesai' => $details['jamSelesaiBaru'], 'total_bayar' => $details['grandTotal'], 'bukti_bayar' => $pathBukti, 'status_booking' => 'menunggu_verifikasi' ]); foreach ($details['addonsDetails'] as $item) { DetailAdditional::create([ 'id_booking' => $booking->id_booking, 'id_additional' => $item['id'], 'qty' => $item['qty'], 'subtotal' => $item['subtotal'] ]); } $urlWA = WhatsAppService::getBookingFotoMessage($booking, $details['foto'], $details['addonsDetails'], $details['grandTotal'], $details['jamSelesaiBaru']); session()->forget('payment_deadline'); return redirect()->route('booking.foto')->with(['success' => 'Pesanan Berhasil!', 'waUrl' => $urlWA]); }); } private function calculateDetails($request) { $foto = PaketFoto::findOrFail($request->id_paket); $totalAddon = 0; $tambahanMenit = 0; $addonsDetails = []; if ($request->has('addons')) { foreach ($request->addons as $id => $qty) { if ($qty > 0 && $add = Additional::find($id)) { $subtotal = $add->harga * $qty; $totalAddon += $subtotal; if ($id == 4) $tambahanMenit += (5 * $qty); if ($id == 6) $tambahanMenit += (10 * $qty); $addonsDetails[] = ['nama' => $add->nama, 'qty' => $qty, 'subtotal' => $subtotal, 'id' => $id]; } } } return [ 'foto' => $foto, 'addonsDetails' => $addonsDetails, 'grandTotal' => $foto->harga + $totalAddon, 'jamSelesaiBaru' => Carbon::createFromFormat('H:i', $request->jam_mulai) ->addMinutes($foto->durasi + $tambahanMenit)->format('H:i') ]; } }