diff --git a/app/Http/Controllers/User/BookingFotoController.php b/app/Http/Controllers/User/BookingFotoController.php index 0cf4b4f..93ecddc 100755 --- a/app/Http/Controllers/User/BookingFotoController.php +++ b/app/Http/Controllers/User/BookingFotoController.php @@ -3,16 +3,13 @@ namespace App\Http\Controllers\User; use App\Http\Controllers\Controller; -use App\Models\Additional; -use App\Models\BookingFoto; -use App\Models\DetailAdditional; -use App\Models\PaketFoto; -use App\Models\Pelanggan; +use App\Models\{Additional, BookingFoto, DetailAdditional, PaketFoto, Pelanggan}; +use App\Http\Requests\User\BookingFotoRequest; +use App\Services\WhatsAppService; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; -use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Facades\Validator; +use Carbon\Carbon; class BookingFotoController extends Controller @@ -64,204 +61,87 @@ public function cekSlot(Request $request) } public function formulir(Request $request) { - $foto = PaketFoto::findOrFail($request->id_paket); - $durasiDasar = $foto->durasi; - $addonsDetails = []; - $totalAddon = 0; - $tambahanMenit = 0; - if ($request->has('addons')) { - foreach ($request->addons as $id => $qty) { - if ($qty > 0) { - $add = Additional::find($id); - if ($add) { - $subtotal = $add->harga * $qty; - $totalAddon += $subtotal; - - if ($id == 4) { - $tambahanMenit += (5 * $qty); - } elseif ($id == 6) { - $tambahanMenit += (10 * $qty); - } - - $addonsDetails[] = [ - 'nama' => $add->nama, - 'qty' => $qty, - 'subtotal' => $subtotal, - 'id' => $id - ]; - } - } - } - } - $totalDurasi = $durasiDasar + $tambahanMenit; - $jamMulai = \Carbon\Carbon::createFromFormat('H:i', $request->jam_mulai); - $jamSelesaiBaru = $jamMulai->copy()->addMinutes($totalDurasi)->format('H:i'); - $grandTotal = $foto->harga + $totalAddon; + $details = $this->calculateDetails($request); if (!session()->has('payment_deadline')) { - $deadline = now()->addHours(2); - session()->put('payment_deadline', $deadline); - } else { - $deadline = session('payment_deadline'); + session()->put('payment_deadline', now()->addHours(2)); } - $sisaWaktu = now()->diffInSeconds($deadline, false); + $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', compact( - 'foto', - 'request', - 'addonsDetails', - 'grandTotal', - 'sisaWaktu', - 'jamSelesaiBaru' - )); + 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(Request $request) + public function store(BookingFotoRequest $request) { - $validator = Validator::make($request->all(), [ - 'id_paket' => 'required|exists:paket_fotos,id_paket', - 'tgl_booking' => 'required|date|after_or_equal:today', - 'jam_mulai' => 'required', - 'nama' => 'required|string|min:3|max:100', - 'no_wa' => 'required|numeric|digits_between:10,15', - 'bukti_bayar' => 'required|image|mimes:jpeg,png,jpg|max:2048', - ], [ - 'required' => 'Kolom :attribute wajib diisi.', - 'string' => 'Input :attribute harus berupa teks valid.', - 'min' => ':attribute terlalu pendek, minimal :min karakter.', - 'max' => ':attribute terlalu panjang, maksimal :max karakter.', - 'numeric' => ':attribute harus berupa angka.', - 'digits_between' => ':attribute harus antara :min sampai :max digit.', - 'date' => 'Format tanggal pada :attribute tidak valid.', - 'after_or_equal' => ':attribute tidak boleh tanggal yang sudah lewat.', - 'image' => ':attribute harus berupa file gambar.', - 'mimes' => 'Format :attribute harus jpeg, png, atau jpg.', - 'bukti_bayar.max' => 'Ukuran :attribute maksimal adalah 2MB.', - ], [ - 'nama' => 'nama pemesan', - 'no_wa' => 'nomor WhatsApp', - 'bukti_bayar' => 'bukti pembayaran', - ]); - - DB::beginTransaction(); - try { - $paket = PaketFoto::findOrFail($request->id_paket); - $durasiMenit = $paket->durasi; - $jamMulai = \Carbon\Carbon::createFromFormat('H:i', $request->jam_mulai); - $jamSelesai = $jamMulai->copy()->addMinutes($durasiMenit); - - $isTaken = BookingFoto::where('tgl_booking', $request->tgl_booking) - ->where('jam_mulai', $request->jam_mulai) - ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima', 'selesai']) - ->exists(); - - if ($isTaken) { - return back()->with('error', 'Mohon maaf, slot waktu ini baru saja diambil orang lain.'); + $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] - ); - $grandTotal = $paket->harga; - $listAdditional = []; - $totalDurasi = $durasiMenit; - if ($request->has('addons')) { - foreach ($request->addons as $idAddon => $qty) { - if ($qty > 0) { - $add = \App\Models\Additional::find($idAddon); - if ($add) { - $subtotal = $add->harga * $qty; - $grandTotal += $subtotal; - - if ($idAddon == 4) $totalDurasi += (5 * $qty); - if ($idAddon == 6) $totalDurasi += (10 * $qty); - - $listAdditional[] = [ - 'id_additional' => $idAddon, - 'qty' => $qty, - 'subtotal' => $subtotal, - 'nama_barang' => $add->nama - ]; - } - } - } - } - $jamMulai = \Carbon\Carbon::createFromFormat('H:i', $request->jam_mulai); - $jamSelesai = $jamMulai->copy()->addMinutes($totalDurasi); - $isTaken = \App\Models\BookingFoto::where('tgl_booking', $request->tgl_booking) - ->where('jam_mulai', $request->jam_mulai) - ->whereIn('status_booking', ['menunggu_verifikasi', 'diterima']) - ->exists(); - if ($isTaken) { - return back()->with('error', 'Mohon maaf, slot waktu ini baru saja diambil orang lain.'); - } - $pelanggan = \App\Models\Pelanggan::create([ - 'nama' => $request->nama, - 'no_wa' => $request->no_wa - ]); - $pathBukti = null; - if ($request->hasFile('bukti_bayar')) { - $file = $request->file('bukti_bayar'); - $namaFile = 'bukti_' . time() . '.' . $file->getClientOriginalExtension(); - $pathBukti = $file->storeAs('img/payment/foto', $namaFile, 'public'); - } - $booking = \App\Models\BookingFoto::create([ - 'no_invoice' => 'INV-FOTO-' . strtoupper(\Illuminate\Support\Str::random(6)), - 'id_pelanggan' => $pelanggan->id_pelanggan, - 'id_paket' => $paket->id_paket, - 'tgl_booking' => $request->tgl_booking, - 'jam_mulai' => $request->jam_mulai, - 'jam_selesai' => $jamSelesai->format('H:i'), - 'total_bayar' => $grandTotal, - 'bukti_bayar' => $pathBukti, + $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 ($listAdditional as $item) { - \App\Models\DetailAdditional::create([ - 'id_booking' => $booking->id_booking, - 'id_additional' => $item['id_additional'], - 'qty' => $item['qty'], - 'subtotal' => $item['subtotal'] + foreach ($details['addonsDetails'] as $item) { + DetailAdditional::create([ + 'id_booking' => $booking->id_booking, + 'id_additional' => $item['id'], + 'qty' => $item['qty'], + 'subtotal' => $item['subtotal'] ]); } - \Illuminate\Support\Facades\DB::commit(); - $txtAddons = ""; - if (count($listAdditional) > 0) { - $txtAddons = "*Additional:*"; - foreach ($listAdditional as $item) { - $txtAddons .= "\n- " . $item['nama_barang'] . " (" . $item['qty'] . "x)"; - } - $txtAddons .= "\n"; - } - $pesan = "Halo Admin Flo.do! Saya sudah melakukan pembayaran untuk invoice {$booking->no_invoice}:\n\n" . - "*Data Pemesan:*\n" . - "Nama: {$request->nama}\n" . - "WA: {$request->no_wa}\n\n" . - "*Detail Booking:*\n" . - "Nama Paket: {$paket->nama}\n" . - $txtAddons . - "Tanggal: " . \Carbon\Carbon::parse($request->tgl_booking)->translatedFormat('l, d F Y') . "\n" . - "Jam: {$request->jam_mulai} - {$jamSelesai->format('H:i')} WIB\n" . - "Total: Rp " . number_format($grandTotal, 0, ',', '.') . "\n\n" . - "Mohon segera diproses, ya! Terima kasih."; - - $urlWA = "https://wa.me/6282337687878?text=" . urlencode($pesan); + $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 Dibuat!', - 'waUrl' => $urlWA - ]); - } catch (\Exception $e) { - \Illuminate\Support\Facades\DB::rollBack(); - return back()->with('error', 'Error: ' . $e->getMessage())->withInput(); + 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') + ]; } } diff --git a/app/Http/Requests/User/BookingFotoRequest.php b/app/Http/Requests/User/BookingFotoRequest.php new file mode 100644 index 0000000..701ed04 --- /dev/null +++ b/app/Http/Requests/User/BookingFotoRequest.php @@ -0,0 +1,51 @@ + 'required|exists:paket_fotos,id_paket', + 'tgl_booking' => 'required|date|after_or_equal:today', + 'jam_mulai' => 'required', + 'nama' => 'required|string|min:3|max:100', + 'no_wa' => 'required|numeric|digits_between:10,15', + 'bukti_bayar' => 'required|image|mimes:jpeg,png,jpg|max:2048', + ]; + } + + public function messages(): array + { + return [ + 'required' => 'Kolom :attribute wajib diisi.', + 'image' => ':attribute harus berupa file gambar.', + 'max' => 'Ukuran :attribute maksimal adalah 2MB.', + 'string' => 'Input :attribute harus berupa teks valid.', + 'min' => ':attribute terlalu pendek, minimal :min karakter.', + 'numeric' => ':attribute harus berupa angka.', + 'digits_between' => ':attribute harus antara :min sampai :max digit.', + 'date' => 'Format tanggal pada :attribute tidak valid.', + 'after_or_equal' => ':attribute tidak boleh tanggal yang sudah lewat.', + 'mimes' => 'Format :attribute harus jpeg, png, atau jpg.', + 'bukti_bayar.max' => 'Ukuran :attribute maksimal adalah 2MB.', + + ]; + } + public function attributes(): array + { + return [ + 'nama' => 'nama pemesan', + 'no_wa' => 'nomor WhatsApp', + 'bukti_bayar' => 'bukti pembayaran', + ]; + } +}