diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index b6318f3..7b710c9 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -4,26 +4,84 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use Illuminate\Http\Response; class AuthController extends Controller { + private int $loginDecaySeconds = 60; + private int $maxLoginAttempts = 10; + public function index(){ + $captcha = $this->generateCaptchaCode(6); + session(['login_captcha' => $captcha]); $data = [ - 'title' => 'Login Admin | Order Gizi' + 'title' => 'Login Admin | Order Gizi', ]; return view('auth.index', $data); } - public function authanticate(){ - $credentials = request()->validate([ + public function authanticate(Request $request){ + $validated = $request->validate([ 'username' => 'required', - 'password' => 'required' + 'password' => 'required', + 'captcha' => 'required', + 'website' => 'nullable', ]); + + if (trim((string) $request->input('website', '')) !== '') { + return back()->withInput($request->only('username')) + ->with(['alertError' => 'Gagal Login!']); + } + + $now = time(); + $rateKey = 'login:' . $request->ip() . ':' . strtolower((string) $request->input('username')); + $windowSeconds = 60; + $maxAttempts = 10; + $attempts = (array) $request->session()->get($rateKey, []); + $attempts = array_values(array_filter($attempts, fn($ts) => is_int($ts) && $ts > ($now - $windowSeconds))); + if(count($attempts) >= $maxAttempts){ + return back()->withInput($request->only('username')) + ->with(['alertError' => 'rate']); + } + + $backoffKey = $rateKey . ':backoff_until'; + $until = (int) $request->session()->get($backoffKey, 0); + if($until > $now){ + return back()->withInput($request->only('username')) + ->with(['alertError' => 'backoff']); + } + + $expectedCaptcha = (string) session('login_captcha', ''); + $givenCaptcha = strtoupper(preg_replace('/\s+/', '', (string) $request->input('captcha', ''))); + if($expectedCaptcha === '' || !hash_equals(strtoupper($expectedCaptcha), (string) $givenCaptcha)){ + return back()->withInput($request->only('username')) + ->with(['alertError' => 'captcha']); + } + $request->session()->forget('login_captcha'); + + + // IMPORTANT: only pass auth credentials to Auth::attempt + // (do not include captcha / honeypot fields, otherwise Laravel will query non-existent columns) + $credentials = [ + 'username' => (string) ($validated['username'] ?? ''), + 'password' => (string) ($validated['password'] ?? ''), + ]; + if(Auth::attempt($credentials)){ - request()->session()->regenerate(); + $request->session()->regenerate(); + $request->session()->forget($rateKey); + $request->session()->forget($backoffKey); return redirect()->intended('/dashboard'); } - return back()->with(['alertError' => 'Terdapat kesalahan disini!']); + // record failed attempt + $attempts[] = $now; + $request->session()->put($rateKey, $attempts); + + // set exponential backoff (1,2,4,8,16,30 seconds max) based on failures in window + $failCount = count($attempts); + $delay = min(30, (int) pow(2, max(0, $failCount - 1))); + $request->session()->put($backoffKey, $now + $delay); + return back()->with(['alertError' => 'Gagal Login!']); } public function logout() @@ -33,4 +91,63 @@ class AuthController extends Controller request()->session()->regenerateToken(); return redirect('/login'); } + + public function captcha(){ + $captcha = (string) session('login_captcha', ''); + if($captcha === ''){ + $captcha = $this->generateCaptchaCode(6); + session(['login_captcha' => $captcha]); + } + if(!function_exists('imagecreatetruecolor')){ + return response('GD extension is not available', Response::HTTP_INTERNAL_SERVER_ERROR)->header('Content-Type', 'text/plain'); + } + + $width=140; + $height=44; + $img = imagecreatetruecolor($width, $height); + $bg = imagecolorallocate($img, 245, 247, 250); + $fg = imagecolorallocate($img, 35, 45, 70); + $noise = imagecolorallocate($img, 120, 130, 150); + + imagefilledrectangle($img, 0, 0, $width, $height, $bg); + + for($i = 0; $i < 6; $i++){ + imageline( + $img, + random_int(0, $width), + random_int(0, $height), + random_int(0, $width), + random_int(0, $height), + $noise + ); + } + + for($i = 0; $i < 180; $i++){ + imagesetpixel($img, random_int(0, $width - 1), random_int(0, $height - 1), $noise); + } + + $font = 5; + $textWidth = imagefontwidth($font) * strlen($captcha); + $textHeight = imagefontwidth($font); + $x = (int) (($width - $textWidth) / 2); + $y = (int) (($height - $textHeight) / 2); + imagestring($img, $font, $x, $y, $captcha, $fg); + + ob_start(); + imagepng($img); + $png = ob_get_clean(); + imagedestroy($img); + return response($png, 200)->header('Content-Type', 'image/png')->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0'); + } + + public function generateCaptchaCode(int $length = 6): string + { + $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; + $out = ''; + $max = strlen($chars) - 1; + for ($i = 0; $i < $length; $i++){ + $out .= $chars[random_int(0, $max)]; + } + return $out; + } } diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index fe5487c..04e6750 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -6,22 +6,26 @@ use App\Mail\NotifikasiCustomer; use App\Mail\NotifikasiPembayaran; use App\Models\JadwalKonsul; use App\Models\Karbohidrat; +use App\Models\Karyawan; use App\Models\MasterMcu; use App\Models\Order; use App\Models\OrderDetail; +use App\Models\UnitInstalasi; use Carbon\Carbon; use Carbon\CarbonPeriod; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Validator; class CustomerController extends Controller { public function index(){ $payload = [ - 'title' => 'Halaman Utama' + 'title' => 'Halaman Utama', + 'mcu' => false, ]; return view('guest.index', $payload); } @@ -151,6 +155,7 @@ class CustomerController extends Controller return [ 'master_menu_id' => $menu->master_menu_id, 'nama' => $menu->nama_menu, + 'exist_foto' => file_exists(public_path('gambar/' . $menu->foto)) ? true : false, 'foto' => $menu->foto, 'jenis_menu' => $menu->jenis_menu, 'harga_public' => $menu->harga_public, @@ -183,7 +188,7 @@ class CustomerController extends Controller // Urutkan: someday → tgl_harian terdekat $sorted = $enriched->sortBy(function ($menu) { - $hariIni = now()->day; + $besok = now()->addDay()->day; $isSomeday = $menu['apakah_someday'] ? 0 : 1; if ($menu['apakah_someday']) { @@ -191,8 +196,11 @@ class CustomerController extends Controller } $tglTerdekat = collect($menu['dmph'])->pluck('tgl_harian') - ->map(function ($tgl) use ($hariIni) { - return $tgl >= $hariIni ? $tgl : $tgl + 31; + ->map(function ($tgl) use ($besok) { + if ($tgl == $besok) { + return 0; // Besok paling awal + } + return $tgl > $besok ? $tgl : $tgl + 31; }) ->sort() ->first() ?? 99; @@ -248,7 +256,8 @@ class CustomerController extends Controller $karbohidrat = Karbohidrat::where('statusenabled', true)->select('karbohidrat_id', 'nama_karbohidrat', 'nilai_kalori')->get(); $payload = [ 'title' => 'Checkout ', - 'karbohidrat' => $karbohidrat + 'karbohidrat' => $karbohidrat, + 'mcu' => false, ]; return view('guest.checkout.checkout_payment', $payload); } @@ -258,7 +267,7 @@ class CustomerController extends Controller $dataCart = request()->input('cartResult'); $biodataResult = request()->input('biodataResult'); $totalHarga = request()->input('totalHarga'); - DB::beginTransaction(); + DB::connection('dbOrderGizi')->beginTransaction(); try { $jenisCustomer = $biodataResult['jenis_customer']; $today = now()->toDateString(); @@ -274,18 +283,24 @@ class CustomerController extends Controller 'no_wa' => $biodataResult['no_whatsapp'], 'tinggi_badan' => $biodataResult['tinggi_badan'], 'berat_badan' => $biodataResult['berat_badan'], - 'nama_pasien' => $biodataResult['nama_pasien'], - 'ruang_perawatan' => $biodataResult['ruang_perawatan'], - 'no_kamar_perawatan' => $biodataResult['no_kamar'], - 'kelas_perawatan' => $biodataResult['kelas_perawatan'], - 'bagian_instalasi' => $biodataResult['bagian_instalasi'], - 'no_ekstensien' => $biodataResult['no_ekstensien'], 'total_harga' => $totalHarga, 'status_order' => "Belum Bayar", 'email' => $biodataResult['email'], - 'alamat' => $biodataResult['alamat'], 'entry_at' => Carbon::now()->format('Y-m-d H:i:s.u'), ]; + if($jenisCustomer === "Karyawan RSAB Harapan Kita"){ + $nip_pns = Karyawan::where('namalengkap',$biodataResult['nama_pemesan'])->first()?->nip_pns; + $payloadOrder['nip'] = $nip_pns ?? null; + $payloadOrder['bagian_instalasi'] = $biodataResult['bagian_instalasi'] ?? null; + $payloadOrder['no_ekstensien'] = $biodataResult['no_ekstensien'] ?? null; + }else if($jenisCustomer === "Keluarga Pasien / Penunggu Pasien"){ + $payloadOrder['nama_pasien'] = $biodataResult['nama_pasien'] ?? null; + $payloadOrder['ruang_perawatan'] = $biodataResult['ruang_perawatan'] ?? null; + $payloadOrder['no_kamar_perawatan'] = $biodataResult['no_kamar'] ?? null; + $payloadOrder['kelas_perawatan'] = $biodataResult['kelas_perawatan'] ?? null; + }else{ + $payloadOrder['alamat'] = $biodataResult['alamat'] ?? null; + } $order = Order::create($payloadOrder); foreach ($dataCart as $cart) { $payloadOrderDetail = [ @@ -300,14 +315,20 @@ class CustomerController extends Controller $payloadOrderDetail['karbohidrat_id'] = $value['karbohidrat_id'] ?? null; $payloadOrderDetail['catatan'] = $value['catatan'] ?? null; $payloadOrderDetail['master_menu_id'] = $cart['id_menu']; + $payloadOrderDetail['total_kalori'] = $value['resultKalori'] ?? ($cart['kalori'] ?? null); OrderDetail::create($payloadOrderDetail); } } //code... if($order->email){ - Mail::to($order->email)->queue(new NotifikasiCustomer($order->nama_pemesan, $order->no_order, $order->total_harga)); + try { + Mail::to($order->email)->send(new NotifikasiCustomer($order->nama_pemesan, $order->no_order, $order->total_harga)); + } catch (\Throwable $th) { + //throw $th; + } + } - DB::commit(); + DB::connection('dbOrderGizi')->commit(); return response()->json([ 'status' => true, 'data' => $order, @@ -315,7 +336,7 @@ class CustomerController extends Controller 'message' => 'Data berhasil disimpan' ]); } catch (\Throwable $th) { - DB::rollBack(); + DB::connection('dbOrderGizi')->rollBack(); return response()->json([ 'status' => false, 'message' => 'Data gagal disimpan ' . $th->getMessage() @@ -324,7 +345,7 @@ class CustomerController extends Controller } public function finishCheckout(){ - DB::beginTransaction(); + DB::connection('dbOrderGizi')->beginTransaction(); try { $noOrder = request('no_order_result'); @@ -363,18 +384,27 @@ class CustomerController extends Controller $order->update($payload); if($order->email){ - Mail::to($order->email)->queue(new NotifikasiPembayaran($order->nama_pemesan, $order->no_order)); + try { + Mail::to($order->email)->send( + new NotifikasiPembayaran($order->nama_pemesan, $order->no_order) + ); + } catch (\Exception $e) { + // log error biar bisa ditelusuri nanti + // \Log::error('Gagal mengirim email ke ' . $order->email . ': ' . $e->getMessage()); + // continue tanpa break flow + } } - DB::commit(); + DB::connection('dbOrderGizi')->commit(); session()->flash('payment_success', true); session()->flash('no_order', $noOrder); return response([ 'status' => true, + 'no_order' => $noOrder, 'message' => 'Terima kasih atas pesanan Anda. Mohon tunggu, kami sedang memprosesnya' ], 200); return back()->with('success', 'Bukti pembayaran berhasil diunggah.'); } catch (\Throwable $th) { - DB::rollBack(); + DB::connection('dbOrderGizi')->rollBack(); return response([ 'status' => false, 'message' => 'Gagal melakukan pesanan!' @@ -388,7 +418,8 @@ class CustomerController extends Controller } $payload = [ 'title' => 'Berhasil Melakukan Pembayaran ', - 'no_order' => session('no_order') + 'no_order' => session('no_order'), + 'mcu' => false, ]; return view('guest.success_page', $payload); } @@ -396,7 +427,8 @@ class CustomerController extends Controller public function checkOrder(){ $payload = [ - 'title' => 'Check Order' + 'title' => 'Check Order', + 'mcu' => false, ]; return view('guest.check_order.index', $payload); } @@ -407,6 +439,7 @@ class CustomerController extends Controller ->table('public.order as o') ->leftJoin('public.order_detail as od', 'od.order_id', '=', 'o.order_id') ->leftJoin('public.master_menu as mm', 'mm.master_menu_id', '=', 'od.master_menu_id') + ->leftJoin('public.menu_mcu as mcu', 'mcu.menu_mcu_id', '=', 'od.menu_mcu_id') ->where('o.no_order', 'ILIKE', '%' . $noOrder . '%') ->select( 'o.*', @@ -416,7 +449,10 @@ class CustomerController extends Controller 'od.harga_satuan', 'od.status_order as status_order_detail', 'od.catatan', - 'mm.nama_menu as nama_item', + 'od.total_kalori', + 'od.type', + 'od.jam_layanan', + DB::raw('COALESCE(mm.nama_menu, mcu.nama_mcu) as nama_item'), 'mm.foto as foto' ) ->get(); @@ -451,16 +487,22 @@ class CustomerController extends Controller // karyawan 'no_ekstensien' => $data->no_ekstensien, 'bagian_instalasi' => $data->bagian_instalasi, + // umum + 'alamat' => $data->alamat, 'items' => $order->map(function ($item) { return [ 'order_detail_id' => $item->order_detail_id, 'nama_item' => $item->nama_item, 'tgl_antar' => $item->tgl_antar, + 'exist_foto' => file_exists(public_path('gambar/' . $item->foto)) ? true : false, 'foto' => $item->foto, 'jumlah' => $item->jumlah, 'harga_satuan' => $item->harga_satuan, 'status_order' => $item->status_order_detail, - 'catatan' => $item->catatan ?? '-' + 'catatan' => $item->catatan ?? '-', + 'total_kalori' => $item->total_kalori, + 'type' => $item->type, + 'jam_layanan' => $item->jam_layanan, // tambahkan field tambahan jika diperlukan ]; })->values(), @@ -477,7 +519,8 @@ class CustomerController extends Controller $paketMcu = MasterMcu::where('statusenabled', true)->get(); $data = [ 'title' => 'Order Gizi MCU', - 'paketMcu' => $paketMcu + 'paketMcu' => $paketMcu, + 'mcu' => true, ]; return view('guest.mcu.index', $data); } @@ -487,6 +530,7 @@ class CustomerController extends Controller DB::connection('dbOrderGizi')->beginTransaction(); $today = now()->toDateString(); $jumlahHariIni = Order::whereDate('entry_at', $today)->count(); + $priceMcu = MasterMcu::where('menu_mcu_id', request('paket_mcu'))->first(); $urutan = $jumlahHariIni + 1; $noOrder = 'TX/CT/GIZI/' . now()->year .'/'. now()->month .'/' . now()->day .'/MCU/' . Str::random(6) .'/' . str_pad($urutan, 4, '0', STR_PAD_LEFT); $payload = [ @@ -499,17 +543,21 @@ class CustomerController extends Controller 'no_wa' => request('no_hp') ?? null, 'tinggi_badan' => request('tinggi_badan') ?? null, 'berat_badan' => request('berat_badan') ?? null, - 'status_order' =>'Menunggu Konfirmasi Pesanan MCU' + 'nama_institusi' => request('nama_institusi'), + 'status_order' =>'Menunggu Konfirmasi Pesanan MCU', + 'total_harga' => $priceMcu ? $priceMcu->harga : null, + 'cara_pembayaran' =>'MCU', ]; $order = Order::create($payload); + $payloadDetail = [ 'order_id' => $order->order_id, 'jumlah' => 1, 'tgl_antar' => request('tgl_mcu'), 'menu_mcu_id' => request('paket_mcu'), 'jam_layanan' => request('jam_layanan'), - 'cara_pembayaran' => 'MCU', - 'status_order' =>'Menunggu Konfirmasi' + 'status_order' =>'Pending', + 'harga_satuan' => $priceMcu ? $priceMcu->harga : null, ]; OrderDetail::create($payloadDetail); @@ -521,7 +569,7 @@ class CustomerController extends Controller 'message' => 'Pesanan Berhasil diproses' ]); } catch (\Throwable $th) { - DB::rollBack(); + DB::connection('dbOrderGizi')->rollBack(); return response()->json([ 'status' => false, 'message' => 'Pesanan gagal diproses ' . $th->getMessage() @@ -536,8 +584,57 @@ class CustomerController extends Controller $payload = [ 'title' => 'Berhasil Melakukan Pesanan ', 'no_order' => session('no_order'), - 'back_href' => '/order-mcu' + 'back_href' => '/order-mcu', + 'mcu' => false ]; return view('guest.success_page', $payload); } + + public function karyawan(Request $request) + { + $search = trim($request->input('search')); + + // 1. Validasi dulu + $validator = Validator::make( + ['search' => $search], + ['search' => 'required|string|min:2|max:50|regex:/^[a-zA-Z.\s]+$/'] + ); + if ($validator->fails()) { + return response()->json(['error' => 0, 'data' => []]); + } + + // 2. Baru query kalau ada keyword + $data =Karyawan::where('statusenabled', true)->where('kedudukanfk', 1) + ->where('namalengkap', 'ILIKE', "%{$search}%") + ->limit(5) + ->pluck('namalengkap') // langsung ambil string + ->map(fn($nama) => ['label' => $nama]); + + return response()->json(['error' => 0, 'data' => $data]); + } + + public function unitInstalasi(Request $request) + { + $search = trim($request->input('search')); + + // 1. Validasi dulu + $validator = Validator::make( + ['search' => $search], + ['search' => 'required|string|min:2|max:50|regex:/^[a-zA-Z.\s]+$/'] + ); + if ($validator->fails()) { + return response()->json(['error' => 0, 'data' => []]); + } + + // 2. Baru query kalau ada keyword + $data = UnitInstalasi::where('statusenabled', true) + ->select('name') + ->where('name', 'ILIKE', "%{$search}%") + ->limit(5) + ->get() + ->map(fn($row) => ['label' => $row->name]); + + return response()->json(['error' => 0, 'data' => $data]); + } } + diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 322e881..f9b3c8e 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -61,15 +61,15 @@ class DashboardController extends Controller 'note_dibatalkan' => $first->note_dibatalkan, ]; })->values(); - $pemasukanKaryawan = $grouped->where('jenis_customer', 'Karyawan RSAB Harapan Kita')->sum('total_harga'); - $pemasukanMasyarakat = $grouped->where('jenis_customer', 'Masyarakat Umum')->sum('total_harga'); - $pemasukanKeluargaPasien = $grouped->where('jenis_customer', 'Keluarga Pasien / Penunggu Pasien')->sum('total_harga'); + $pemasukanKaryawan = $grouped->where('jenis_customer', 'Karyawan RSAB Harapan Kita')->whereNotIn('status_order', ['Belum Bayar'])->sum('total_harga'); + $pemasukanMasyarakat = $grouped->where('jenis_customer', 'Masyarakat Umum')->whereNotIn('status_order', ['Belum Bayar'])->sum('total_harga'); + $pemasukanKeluargaPasien = $grouped->where('jenis_customer', 'Keluarga Pasien / Penunggu Pasien')->whereNotIn('status_order', ['Belum Bayar'])->sum('total_harga'); - $totalPemasukan = $grouped->sum('total_harga'); - $pesananPending = $grouped->whereNotIn('status_order', ['Lunas', 'Dibatalkan'])->count(); + $totalPemasukan = $grouped->whereNotIn('status_order', ['Belum Bayar'])->sum('total_harga'); + $pesananPending = $grouped->whereNotIn('status_order', ['Lunas', 'Dibatalkan', 'Belum Bayar'])->count(); $pesananLunas = $grouped->where('status_order', 'Lunas')->count(); $pesananBatal = $grouped->where('status_order', 'Dibatalkan')->count(); - $totalPesanan = $grouped->count(); + $totalPesanan = $grouped->whereNotIn('status_order', ['Belum Bayar'])->count(); $pesananSelesai = DB::connection('dbOrderGizi')->table('public.order as o') ->where('o.statusenabled', true) diff --git a/app/Http/Controllers/PesananController.php b/app/Http/Controllers/PesananController.php index 5313e07..128b0a8 100644 --- a/app/Http/Controllers/PesananController.php +++ b/app/Http/Controllers/PesananController.php @@ -37,6 +37,16 @@ class PesananController extends Controller }else{ $tanggalFormatted = [Carbon::now()->toDateString()]; } + + $dataPending = Order::where('statusenabled', true)->whereIn('status_order', [ + 'Menunggu Konfirmasi Pembayaran', + 'Menunggu Konfirmasi Pembayaran Via Billing', + 'Menunggu Konfirmasi Pesanan MCU' + ]) + ->select(DB::raw('COUNT(DISTINCT DATE(entry_at)) as total')) + ->value('total'); + + $orders = DB::connection('dbOrderGizi')->table('public.order as o') ->leftJoin('public.order_detail as od', 'od.order_id', '=', 'o.order_id') ->where('o.statusenabled', true) @@ -57,6 +67,7 @@ class PesananController extends Controller 'o.bukti_pembayaran', 'o.note_dibatalkan', 'o.medical_record', + 'o.nama_institusi', 'od.status_order as detail_status_order' )->get()->groupBy('order_id'); $grouped = $orders->map(function($items){ @@ -79,15 +90,18 @@ class PesananController extends Controller 'total_detail' => $totalDetail, 'selesai_detail' => $selesaiDetail, 'note_dibatalkan' => $first->note_dibatalkan, + 'nama_institusi' => $first->nama_institusi, ]; }) ->filter(function($item){ return $item['total_detail'] > 0 && $item['total_detail'] != $item['selesai_detail']; })->values(); + return response()->json([ 'status' => true, 'rows' => $grouped->values(), - 'total' => $grouped->count() + 'total' => $grouped->count(), + 'dataPending'=> $dataPending ]); } @@ -107,8 +121,13 @@ class PesananController extends Controller } $order->update($payload); - if($order->email){ - Mail::to($order->email)->queue(new NotifikasiKonfirmasiPembayaran($order->nama_pemesan, $order->no_order, $order->total_harga)); + if($order->email && $order->status_order === "Lunas"){ + try { + //code... + Mail::to($order->email)->send(new NotifikasiKonfirmasiPembayaran($order->nama_pemesan, $order->no_order, $order->total_harga)); + } catch (\Throwable $th) { + //throw $th; + } } DB::connection('dbOrderGizi')->commit(); @@ -136,7 +155,6 @@ class PesananController extends Controller 'pegawai_name_confirm_order' => auth()->user()->full_name, 'pegawai_at_confirm_order' => Carbon::now(), 'status_order' => 'Lunas', - 'cara_pembayaran' => 'Billing' ]; if($request->hasFile('evidence_medical_record')){ $file = $request->file('evidence_medical_record'); @@ -146,7 +164,7 @@ class PesananController extends Controller $order->update($payload); if($order->email){ - Mail::to($order->email)->queue(new NotifikasiKonfirmasiPembayaran($order->nama_pemesan, $order->no_order, $order->total_harga)); + Mail::to($order->email)->send(new NotifikasiKonfirmasiPembayaran($order->nama_pemesan, $order->no_order, $order->total_harga)); } DB::connection('dbOrderGizi')->commit(); return response()->json([ @@ -180,6 +198,24 @@ class PesananController extends Controller ]); } + public function dataPending(){ + $data = Order::selectRaw('DATE(entry_at) as tgl, COUNT(*) as total') + ->where('statusenabled', true) + ->whereIn('status_order', [ + 'Menunggu Konfirmasi Pembayaran', + 'Menunggu Konfirmasi Pembayaran Via Billing', + 'Menunggu Konfirmasi Pesanan MCU' + ]) + ->groupBy(DB::raw('DATE(entry_at)')) + ->orderBy('tgl', 'asc') + ->get(); + return response()->json([ + 'status' => true, + 'rows' => $data->values(), + 'total' => $data->count() + ]); + } + public function indexSelesai() { $payload = [ @@ -218,6 +254,7 @@ class PesananController extends Controller 'o.note_dibatalkan', 'o.medical_record', 'o.evidence_medical_record', + 'o.nama_institusi', 'od.status_order as detail_status_order' )->get()->groupBy('order_id'); @@ -242,6 +279,7 @@ class PesananController extends Controller 'total_detail' => $totalDetail, 'selesai_detail' => $selesaiDetail, 'note_dibatalkan' => $first->note_dibatalkan, + 'nama_institusi' => $first->nama_institusi, ]; }) ->filter(function($item){ @@ -264,7 +302,7 @@ class PesananController extends Controller } public function getPekerjaan(){ - $data = OrderDetail::with(['menu', 'paketMenu', 'order', 'karbohidrat'])->whereHas('order', function($q){ + $data = OrderDetail::with(['menu', 'masterMcu', 'order', 'karbohidrat'])->whereHas('order', function($q){ $q->where('status_order', 'Lunas'); }); $tanggal = request('tanggal'); @@ -279,16 +317,39 @@ class PesananController extends Controller // if($status !== "all"){ // $data->where('status_order', $status); // } + $dataPending = OrderDetail::whereHas('order', function($query) { + $query->where('status_order', 'Lunas'); + })->where('status_order', 'Pending') + ->select(DB::raw('COUNT(DISTINCT DATE(tgl_antar)) as total')) + ->value('total'); + $data = $data->get(); return response()->json([ + 'rows' => $data->values(), + 'total' => $data->count(), + 'dataPending' => $dataPending + ]); + } + + public function dataPekerjaanPending(){ + $data = OrderDetail::with('order')->where('status_order', 'Pending') + ->select(DB::raw('DATE(tgl_antar) as tgl'), DB::raw('COUNT(*) as total')) + ->whereHas('order', function($query) { + $query->where('status_order', 'Lunas'); // filter status di tabel orders + }) + ->groupBy(DB::raw('DATE(tgl_antar)')) + ->orderBy('tgl', 'asc') + ->get(); + return response()->json([ + 'status' => true, 'rows' => $data->values(), 'total' => $data->count() ]); } public function getPekerjaanDetail($order_detail_id){ - $data = OrderDetail::where('order_detail_id', $order_detail_id)->with(['order', 'menu', 'paketMenu'])->first(); + $data = OrderDetail::where('order_detail_id', $order_detail_id)->with(['order', 'menu', 'masterMcu'])->first(); return response()->json([ 'status' => true, 'data' => $data @@ -301,7 +362,7 @@ class PesananController extends Controller $type_customer = request('type_customer'); $type = request('type'); - $orderDetail = OrderDetail::with(['menu', 'paketMenu', 'order', 'karbohidrat'])->whereHas('order', function($q) use($type_customer){ + $orderDetail = OrderDetail::with(['menu', 'masterMcu', 'order', 'karbohidrat'])->whereHas('order', function($q) use($type_customer){ $q->where('status_order', 'Lunas'); if($type_customer !== 'all'){ $q->where('jenis_customer', $type_customer); @@ -338,18 +399,18 @@ class PesananController extends Controller $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValue('A1', "Menu Pesanan dari {$startDateFormatted} sampai {$endDateFormatted}"); - $sheet->mergeCells('A1:K1'); + $sheet->mergeCells('A1:P1'); $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14); $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); $sheet->setCellValue('A2', "Waktu Cetak: {$waktu_cetak}"); - $sheet->mergeCells('A2:K2'); + $sheet->mergeCells('A2:P2'); $sheet->getStyle('A2')->getAlignment()->setHorizontal('center'); // Header tabel - $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Customer", "Status Pesanan", "Menu Pesanan", "Karbohidrat", "Jumlah", "Tanggal Antar", "Waktu Makan", "Catatan"]; + $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Pembayaran", "Jenis Customer", "Ruangan", "Status Pesanan", "Jenis Menu", "Menu Pesanan", "Karbohidrat", "Total Kalori (kal)", "Jumlah", "Tanggal Antar", "Waktu Makan / Jam Layanan", "Harga Total", "Catatan"]; $sheet->fromArray($headers, null, 'A4'); - $sheet->getStyle('A4:K4')->applyFromArray([ + $sheet->getStyle('A4:P4')->applyFromArray([ 'font' => ['bold' => true], 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER], 'borders' => [ @@ -358,36 +419,58 @@ class PesananController extends Controller ] ] ]); - $sheet->getStyle('A4:K4')->getFont()->setBold(true); - $sheet->getStyle('A4:K4')->getAlignment()->setHorizontal('center'); - $sheet->getStyle('A4:K4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $sheet->getStyle('A4:P4')->getFont()->setBold(true); + $sheet->getStyle('A4:P4')->getAlignment()->setHorizontal('center'); + $sheet->getStyle('A4:P4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); // Isi data $row = 5; + $totalPendapatan = 0; foreach ($orderDetail as $index => $item) { $sheet->setCellValue("A{$row}", $index + 1); $sheet->setCellValue("B{$row}", $item?->order?->no_order); $sheet->setCellValue("C{$row}", $item?->order?->nama_pemesan); - $sheet->setCellValue("D{$row}", $item?->order?->jenis_customer); - $sheet->setCellValue("E{$row}", $item?->status_order ?? "-"); - $sheet->setCellValue("F{$row}", $item?->menu?->nama_menu ?? '-'); + $sheet->setCellValue("D{$row}", $item?->order?->cara_pembayaran); + $sheet->setCellValue("E{$row}", $item?->order?->jenis_customer === "MCU" ? $item?->order?->nama_institusi . '- MCU' : $item?->order?->jenis_customer); + if($item->order?->jenis_customer === "Keluarga Pasien / Penunggu Pasien"){ + $sheet->setCellValue("F{$row}", $item?->order?->kelas_perawatan . '/' . $item?->order?->no_kamar_perawatan . '/' . $item?->order?->ruang_perawatan); + }else if($item->order?->jenis_customer === "Karyawan RSAB Harapan Kita"){ + $sheet->setCellValue("F{$row}", $item?->order?->bagian_instalasi ?? '-'); + }else{ + $sheet->setCellValue("F{$row}", '-'); + } + $sheet->setCellValue("G{$row}", $item?->status_order ?? "-"); + if($item->menu?->masterMcu){ + $sheet->setCellValue("H{$row}", 'Menu MCU'); + }else{ + $sheet->setCellValue("H{$row}", $item?->menu?->apakah_someday ? "Menu Sameday" : "Menu Normal"); + } + $sheet->setCellValue("I{$row}", $item?->menu?->nama_menu ?? $item?->masterMcu?->nama_mcu); $karbohidratNama = $item?->karbohidrat?->nama_karbohidrat ?? '-'; $karbohidratNilai = $item?->karbohidrat?->nilai_kalori ?? '-'; - $sheet->setCellValue("G{$row}", $karbohidratNama . ($karbohidratNilai !== '-' ? " ({$karbohidratNilai} kal)" : '')); - $sheet->setCellValue("H{$row}", $item?->jumlah ?? '-'); - $sheet->setCellValue("I{$row}", $item?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "Tanggal Antar"); - $sheet->setCellValue("J{$row}", $item?->type ?? "-"); - $sheet->setCellValue("K{$row}", $item?->catatan ?? "-"); + $sheet->setCellValue("J{$row}", $karbohidratNama . ($karbohidratNilai !== '-' ? " ({$karbohidratNilai} kal)" : '')); + $sheet->setCellValue("K{$row}", $item?->total_kalori ?? '-'); + $sheet->setCellValue("L{$row}", $item?->jumlah ?? '-'); + $sheet->setCellValue("M{$row}", $item?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "Tanggal Antar"); + $sheet->setCellValue("N{$row}", $item?->type ?? $item->jam_layanan); + $sheet->setCellValue("O{$row}", $item?->order?->total_harga); + $sheet->setCellValue("P{$row}", $item?->catatan ?? "-"); // Border tiap baris - $sheet->getStyle("A{$row}:K{$row}")->getBorders()->getAllBorders() + $sheet->getStyle("A{$row}:P{$row}")->getBorders()->getAllBorders() ->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $totalPendapatan += $item?->order?->total_harga; $row++; } + $sheet->getStyle("L{$row}:O{$row}")->getFont()->setBold(true); + $sheet->getStyle("L{$row}:O{$row}")->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $sheet->setCellValue("M{$row}", 'Total Pendapatan'); + $sheet->setCellValue("O{$row}", $totalPendapatan); + // Auto size kolom - foreach(range('A', 'K') as $col){ + foreach(range('A', 'P') as $col){ $sheet->getColumnDimension($col)->setAutoSize(true); } $lastRow = $row - 1; - $sheet->setAutoFilter("A4:K{$lastRow}"); + $sheet->setAutoFilter("A4:P{$lastRow}"); // Download file $fileName = 'menu-pesanan' . now()->format('Ymd-His') . '.xlsx'; $writer = new Xlsx($spreadsheet); @@ -409,7 +492,7 @@ class PesananController extends Controller $type_customer = request('type_customer'); $query = Order::where('statusenabled', true) ->whereBetween('entry_at', [$startDate, $endDate]) - ->whereIn('status_order', ['Menunggu Konfirmasi Pembayaran', 'Menunggu Konfirmasi Pembayaran Via Billing']); + ->whereIn('status_order', ['Menunggu Konfirmasi Pembayaran', 'Menunggu Konfirmasi Pembayaran Via Billing', 'Menunggu Konfirmasi Pesanan MCU']); if($type_customer !== 'all'){ $query->where('jenis_customer', $type_customer); } @@ -447,20 +530,19 @@ class PesananController extends Controller $waktu_cetak = Carbon::now()->locale('id')->translatedFormat('d F Y'); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->setCellValue('A1', "Laporan Pesanan dari {$startDateFormatted} sampai {$endDateFormatted}"); - $sheet->mergeCells('A1:P1'); + $sheet->mergeCells('A1:T1'); $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14); $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); $sheet->setCellValue('A2', "Waktu Cetak: {$waktu_cetak}"); - $sheet->mergeCells('A2:P2'); + $sheet->mergeCells('A2:T2'); $sheet->getStyle('A2')->getAlignment()->setHorizontal('center'); // Header tabel - $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Customer", "Status Pembayaran", "Jenis Kelamin", "NO.HP/WA", "Email" , "Cara Pembayaran", "Tanggal Pesan", "Harga Total", "Menu Pesanan", "Jumlah", "Status Pesanan", "Tanggal Antar", "Waktu Makan", "Catatan"]; + $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Customer", "Ruangan", "Status Pembayaran", "Jenis Kelamin", "NO.HP/WA", "Email" , "Jenis Pembayaran", "Tanggal Pesan", "Harga Total", "Jenis Menu", "Menu Pesanan", "Total Kalori", "Jumlah", "Status Pesanan", "Tanggal Antar", "Waktu Makan / Jam Layanan", "Catatan"]; $sheet->fromArray($headers, null, 'A4'); - $sheet->getStyle('A4:Q4')->applyFromArray([ + $sheet->getStyle('A4:T4')->applyFromArray([ 'font' => ['bold' => true], 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER], 'borders' => [ @@ -469,46 +551,64 @@ class PesananController extends Controller ] ] ]); - $sheet->getStyle('A4:Q4')->getFont()->setBold(true); - $sheet->getStyle('A4:Q4')->getAlignment()->setHorizontal('center'); - $sheet->getStyle('A4:Q4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); - + $sheet->getStyle('A4:T4')->getFont()->setBold(true); + $sheet->getStyle('A4:T4')->getAlignment()->setHorizontal('center'); + $sheet->getStyle('A4:T4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); // Isi data + $totalPendapatan = 0; $row = 5; foreach ($order as $index => $item) { foreach($item->orderDetail as $detail){ + $sheet->setCellValue("A{$row}", $index + 1); $sheet->setCellValue("B{$row}", $item->no_order); $sheet->setCellValue("C{$row}", $item->nama_pemesan); - $sheet->setCellValue("D{$row}", $item->jenis_customer); - $sheet->setCellValue("E{$row}", $item->status_order); - $sheet->setCellValue("F{$row}", $item->jenis_kelamin); - $sheet->setCellValue("G{$row}", $item->no_wa); - $sheet->setCellValue("H{$row}", $item->email); - $sheet->setCellValue("I{$row}", $item->cara_pembayaran); - $sheet->setCellValue("J{$row}", Carbon::parse($item->entry_at)->translatedFormat('d F Y H:i')); - $sheet->setCellValue("K{$row}", $item->total_harga); - - $sheet->setCellValue("L{$row}", $detail?->menu?->nama_menu ?? '-'); - $sheet->setCellValue("M{$row}", $detail?->jumlah ?? '-'); - $sheet->setCellValue("N{$row}", $detail?->status_order ?? "-"); - $sheet->setCellValue("O{$row}", $detail?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "Tanggal Antar"); - $sheet->setCellValue("P{$row}", $detail?->type ?? "-"); - $sheet->setCellValue("Q{$row}", $detail?->catatan ?? "-"); + $sheet->setCellValue("D{$row}", $item->jenis_customer === "MCU" ? $item->nama_institusi . '-' . $item->jenis_customer : $item->jenis_customer); + if($item->jenis_customer === "Keluarga Pasien / Penunggu Pasien"){ + $sheet->setCellValue("E{$row}", $item->kelas_perawatan . '/' . $item->no_kamar_perawatan . '/' . $item->ruang_perawatan); + }else if($item->jenis_customer === "Karyawan RSAB Harapan Kita"){ + $sheet->setCellValue("E{$row}", $item->bagian_instalasi ?? '-'); + }else{ + $sheet->setCellValue("E{$row}", '-'); + } + $sheet->setCellValue("F{$row}", $item->status_order); + $sheet->setCellValue("G{$row}", $item->jenis_kelamin); + $sheet->setCellValue("H{$row}", $item->no_wa); + $sheet->setCellValue("I{$row}", $item->email); + $sheet->setCellValue("J{$row}", $item->cara_pembayaran); + $sheet->setCellValue("K{$row}", Carbon::parse($item->entry_at)->translatedFormat('d F Y H:i')); + $sheet->setCellValue("L{$row}", $item->total_harga); + if($detail?->masterMcu){ + $sheet->setCellValue("M{$row}", 'Menu MCU'); + }else{ + $sheet->setCellValue("M{$row}", $detail?->menu?->apakah_someday ? "Menu Sameday" : "Menu Normal"); + } + $sheet->setCellValue("N{$row}", $detail?->menu?->nama_menu ?? $detail?->masterMcu?->nama_mcu); + $sheet->setCellValue("O{$row}", $detail?->total_kalori ?? '-'); + $sheet->setCellValue("P{$row}", $detail?->jumlah ?? '-'); + $sheet->setCellValue("Q{$row}", $detail?->status_order ?? "-"); + $sheet->setCellValue("R{$row}", $detail?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "Tanggal Antar"); + $sheet->setCellValue("S{$row}", $detail?->type ?? $detail->jam_layanan); + $sheet->setCellValue("T{$row}", $detail?->catatan ?? "-"); // Border tiap baris - $sheet->getStyle("A{$row}:Q{$row}")->getBorders()->getAllBorders() + $sheet->getStyle("A{$row}:T{$row}")->getBorders()->getAllBorders() ->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); - + if($item->status_order === "Lunas"){ + $totalPendapatan += $item?->total_harga; + } $row++; } } - + $sheet->getStyle("K{$row}:L{$row}")->getFont()->setBold(true); + $sheet->getStyle("K{$row}:L{$row}")->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $sheet->setCellValue("K{$row}", 'Total Pendapatan'); + $sheet->setCellValue("L{$row}", $totalPendapatan); // Auto size kolom - foreach(range('A', 'Q') as $col){ + foreach(range('A', 'T') as $col){ $sheet->getColumnDimension($col)->setAutoSize(true); } $lastRow = $row - 1; - $sheet->setAutoFilter("A4:Q{$lastRow}"); + $sheet->setAutoFilter("A4:T{$lastRow}"); // Download file $fileName = $title . now()->format('Ymd-His') . '.xlsx'; $writer = new Xlsx($spreadsheet); @@ -600,6 +700,7 @@ class PesananController extends Controller 'total_detail' => $totalDetail, 'selesai_detail' => $selesaiDetail, 'note_dibatalkan' => $first->note_dibatalkan, + 'nama_institusi' => $first->nama_institusi, ]; }) ->values(); @@ -632,6 +733,7 @@ class PesananController extends Controller 'o.note_dibatalkan', 'o.medical_record', 'o.evidence_medical_record', + 'o.nama_institusi', 'od.status_order as detail_status_order' )->get()->groupBy('order_id'); return $data; @@ -682,18 +784,18 @@ class PesananController extends Controller $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValue('A1', "Laporan Pesanan dari {$startDateFormatted} sampai {$endDateFormatted}"); - $sheet->mergeCells('A1:P1'); + $sheet->mergeCells('A1:R1'); $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14); $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); $sheet->setCellValue('A2', "Waktu Cetak: {$waktu_cetak}"); - $sheet->mergeCells('A2:P2'); + $sheet->mergeCells('A2:S2'); $sheet->getStyle('A2')->getAlignment()->setHorizontal('center'); // Header tabel - $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Customer", "Jenis Kelamin", "NO.HP/WA", "Email" , "Cara Pembayaran", "Tanggal Pesan", "Harga Total", "Menu Pesanan", "Jumlah", "Status Pesanan", "Tanggal Antar", "Waktu Makan", "Catatan"]; + $headers = ["No", "Nomor Order", "Nama Pemesan", "Jenis Customer", "Ruangan", "Jenis Kelamin", "NO.HP/WA", "Email" , "Jenis Pembayaran", "Tanggal Pesan", "Harga Total", "Jenis Menu", "Menu Pesanan", "Total Kalori (kal)", "Jumlah", "Status Pesanan", "Tanggal Antar", "Waktu Makan / Jam Layanan", "Catatan"]; $sheet->fromArray($headers, null, 'A4'); - $sheet->getStyle('A4:P4')->applyFromArray([ + $sheet->getStyle('A4:S4')->applyFromArray([ 'font' => ['bold' => true], 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER], 'borders' => [ @@ -702,45 +804,63 @@ class PesananController extends Controller ] ] ]); - $sheet->getStyle('A4:P4')->getFont()->setBold(true); - $sheet->getStyle('A4:P4')->getAlignment()->setHorizontal('center'); - $sheet->getStyle('A4:P4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $sheet->getStyle('A4:S4')->getFont()->setBold(true); + $sheet->getStyle('A4:S4')->getAlignment()->setHorizontal('center'); + $sheet->getStyle('A4:S4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); // Isi data $row = 5; + $totalPendapatan = 0; foreach ($order as $index => $item) { foreach($item->orderDetail as $detail){ $sheet->setCellValue("A{$row}", $index + 1); $sheet->setCellValue("B{$row}", $item->no_order); $sheet->setCellValue("C{$row}", $item->nama_pemesan); - $sheet->setCellValue("D{$row}", $item->jenis_customer); - $sheet->setCellValue("E{$row}", $item->jenis_kelamin); - $sheet->setCellValue("F{$row}", $item->no_wa); - $sheet->setCellValue("G{$row}", $item->email); - $sheet->setCellValue("H{$row}", $item->cara_pembayaran); - $sheet->setCellValue("I{$row}", Carbon::parse($item->entry_at)->translatedFormat('d F Y H:i')); - $sheet->setCellValue("J{$row}", $item->total_harga); + $sheet->setCellValue("D{$row}", $item->jenis_customer === "MCU" ? $item->nama_institusi . '-' . $item->jenis_customer : $item->jenis_customer); + if($item->jenis_customer === "Keluarga Pasien / Penunggu Pasien"){ + $sheet->setCellValue("E{$row}", $item->kelas_perawatan . '/' . $item->no_kamar_perawatan . '/' . $item->ruang_perawatan); + }else if($item->jenis_customer === "Karyawan RSAB Harapan Kita"){ + $sheet->setCellValue("E{$row}", $item->bagian_instalasi ?? '-'); + }else{ + $sheet->setCellValue("E{$row}", '-'); + } + $sheet->setCellValue("F{$row}", $item->jenis_kelamin); + $sheet->setCellValue("G{$row}", $item->no_wa); + $sheet->setCellValue("H{$row}", $item->email); + $sheet->setCellValue("I{$row}", $item->cara_pembayaran); + $sheet->setCellValue("J{$row}", Carbon::parse($item->entry_at)->translatedFormat('d F Y H:i')); + $sheet->setCellValue("K{$row}", $item->total_harga); - $sheet->setCellValue("K{$row}", $detail?->menu?->nama_menu ?? '-'); - $sheet->setCellValue("L{$row}", $detail?->jumlah ?? '-'); - $sheet->setCellValue("M{$row}", $detail?->status_order ?? "-"); - $sheet->setCellValue("N{$row}", $detail?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "Tanggal Antar"); - $sheet->setCellValue("O{$row}", $detail?->type ?? "-"); - $sheet->setCellValue("P{$row}", $detail?->catatan ?? "-"); + if($detail?->masterMcu){ + $sheet->setCellValue("L{$row}", 'Menu MCU'); + }else{ + $sheet->setCellValue("L{$row}", $detail?->menu?->apakah_someday ? "Menu Sameday" : "Menu Normal"); + } + $sheet->setCellValue("M{$row}", $detail?->menu?->nama_menu ?? $detail?->masterMcu?->nama_mcu); + $sheet->setCellValue("N{$row}", $detail?->total_kalori ?? '-'); + $sheet->setCellValue("O{$row}", $detail?->jumlah ?? '-'); + $sheet->setCellValue("P{$row}", $detail?->status_order ?? "-"); + $sheet->setCellValue("Q{$row}", $detail?->tgl_antar ? Carbon::parse($item->tgl_antar)->translatedFormat('d F Y') : "-"); + $sheet->setCellValue("R{$row}", $detail?->type ?? $detail->jam_layanan); + $sheet->setCellValue("S{$row}", $detail?->catatan ?? "-"); // Border tiap baris - $sheet->getStyle("A{$row}:P{$row}")->getBorders()->getAllBorders() + $sheet->getStyle("A{$row}:S{$row}")->getBorders()->getAllBorders() ->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); - + $totalPendapatan += $item->total_harga; $row++; } } - + $sheet->getStyle("I{$row}:K{$row}")->getFont()->setBold(true); + $sheet->getStyle("I{$row}:K{$row}")->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + $sheet->setCellValue("I{$row}", 'Total Pendapatan'); + $sheet->setCellValue("K{$row}", $totalPendapatan); + // dd($totalPendapatan); // Auto size kolom - foreach(range('A', 'P') as $col){ + foreach(range('A', 'S') as $col){ $sheet->getColumnDimension($col)->setAutoSize(true); } $lastRow = $row - 1; - $sheet->setAutoFilter("A4:P{$lastRow}"); + $sheet->setAutoFilter("A4:S{$lastRow}"); // Download file $fileName = 'laporan-pesanan-' . now()->format('Ymd-His') . '.xlsx'; $writer = new Xlsx($spreadsheet); @@ -847,7 +967,7 @@ class PesananController extends Controller $sheet->setCellValue("A{$row}", $index + 1); $sheet->setCellValue("B{$row}", $item->no_order); $sheet->setCellValue("C{$row}", $item->nama_pemesan); - $sheet->setCellValue("D{$row}", $item->jenis_customer); + $sheet->setCellValue("D{$row}", $item->jenis_customer === "MCU" ? $item->nama_institusi . ' - ' . $item->jenis_customer : $item->jenis_customer); $sheet->setCellValue("E{$row}", $item->cara_pembayaran); $sheet->setCellValue("F{$row}", Carbon::parse($item->entry_at)->translatedFormat('d F Y H:i')); $sheet->setCellValue("G{$row}", $item->total_harga); @@ -924,6 +1044,7 @@ class PesananController extends Controller 'o.note_dibatalkan', 'o.medical_record', 'o.evidence_medical_record', + 'o.nama_institusi', 'od.status_order as detail_status_order' )->get()->groupBy('order_id'); @@ -948,6 +1069,7 @@ class PesananController extends Controller 'total_detail' => $totalDetail, 'selesai_detail' => $selesaiDetail, 'note_dibatalkan' => $first->note_dibatalkan, + 'nama_institusi' => $first->nama_institusi, ]; }) ->values(); @@ -958,6 +1080,15 @@ class PesananController extends Controller 'total' => $grouped->count() ]); } + + public function downloadLabel(){ + $data = request('data'); + $dataArray = explode(',', $data); + $orderDetail = OrderDetail::whereIn('order_detail_id', $dataArray)->with(['masterMcu', 'menu', 'order'])->get(); + $pdf = Pdf::loadView('dashboard.label.multi', compact('orderDetail')); + + return $pdf->stream('label_.pdf'); + } /** * Show the form for creating a new resource. */ diff --git a/app/Http/Controllers/SurveyController.php b/app/Http/Controllers/SurveyController.php new file mode 100644 index 0000000..22fd4ce --- /dev/null +++ b/app/Http/Controllers/SurveyController.php @@ -0,0 +1,178 @@ +has('payment_success')){ + return redirect('/'); + } + $no_order = $request->query('no_order'); + $type = $request->query('type'); + $data = [ + 'title' => 'Survey Gizi', + 'mcu' => false, + 'no_order' => $no_order, + 'type' => $type + ]; + return view('guest.survey.index', $data); + } + + public function store(){ + DB::connection('dbOrderGizi')->beginTransaction(); + try { + $payload =[ + 'no_order' => request('no_order'), + 'type' => request('type'), + 'keterangan' => request('kritik_saran'), + 'kepuasan' => request('kepuasan'), + 'created_at' => now() + ]; + Survey::create($payload); + DB::connection('dbOrderGizi')->commit(); + session()->flash('payment_success', true); + session()->flash('no_order', $payload['no_order']); + return response()->json([ + 'status' => true, + 'message' => 'Survei berhasil disimpan' + ]); + } catch (\Throwable $th) { + DB::connection('dbOrderGizi')->rollBack(); + return response()->json([ + 'status' => false, + 'message' => 'Data gagal disimpan ' . $th->getMessage() + ]); + } + + } + + public function datatable(){ + $data = Survey::query(); + $tanggal = request('tanggal'); + if(!empty($tanggal)){ + $flattened = is_array($tanggal[0]) ? Arr::flatten($tanggal) : $tanggal; + $data->whereIn(DB::raw('DATE(created_at)'), $flattened); + }else{ + $now = Carbon::now()->format('Y-m-d'); + $data->whereDate('created_at', $now); + } + $data = $data->get(); + return response()->json([ + 'rows' => $data->values(), + 'total' => $data->count(), + ]); + } + + public function chartDataSurvey(Request $request) + { + $tanggal = $request->query('tanggal'); + if(is_string($tanggal)) $tanggal = json_decode($tanggal, true); + + $query = Survey::query(); + if (!empty($tanggal) && is_array($tanggal)) { + $query->whereIn(DB::raw('DATE(created_at)'), $tanggal); + } else { + $query->whereDate('created_at', Carbon::today()); + } + + $allData = $query->get(); + + // Pisahkan data untuk perhitungan Card + $dataBaru = $allData->where('type', 'pengguna_baru'); + $dataLama = $allData->where('type', 'pelanggan_setia'); + + return response()->json([ + 'responden' => [ + 'baru' => $dataBaru->count(), + 'lama' => $dataLama->count(), + ], + 'kepuasan_baru' => [ + 'total' => $dataBaru->count(), + 'puas' => $dataBaru->where('kepuasan', 'Puas')->count(), + 'tidak_puas' => $dataBaru->where('kepuasan', 'Tidak Puas')->count(), + ], + 'kepuasan_lama' => [ + 'total' => $dataLama->count(), + 'puas' => $dataLama->where('kepuasan', 'Puas')->count(), + 'tidak_puas' => $dataLama->where('kepuasan', 'Tidak Puas')->count(), + ] + ]); + } + + + public function dashboardSurvey(){ + $data = [ + 'title' => 'List Survey Order Gizi' + ]; + return view('dashboard.survey.index', $data); + } + + public function exportSurveyExcel(){ + $startDate = Carbon::parse(request('start_date'))->startOfDay(); + $endDate = Carbon::parse(request('end_date'))->endOfDay(); + $data = Survey::whereBetween('created_at', [$startDate, $endDate])->get(); + $waktu_cetak = Carbon::now()->locale('id')->translatedFormat('d F Y'); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A1', "Laporan Survei dari {$startDate->format('Y-m-d')} sampai {$endDate->format('Y-m-d')}"); + $sheet->mergeCells('A1:E1'); + $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + $sheet->setCellValue('A2', "Waktu Cetak: {$waktu_cetak}"); + $sheet->mergeCells('A2:E2'); + $sheet->getStyle('A2')->getAlignment()->setHorizontal('center'); + + // Header tabel + $headers = ["No", "Nama", "Tipe Survei", "Kepuasan", "Kritik dan Saran"]; + $sheet->fromArray($headers, null, 'A4'); + $sheet->getStyle('A4:E4')->applyFromArray([ + 'font' => ['bold' => true], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER], + 'borders' => [ + 'allBorders' => [ + 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN + ] + ] + ]); + $sheet->getStyle('A4:E4')->getFont()->setBold(true); + $sheet->getStyle('A4:E4')->getAlignment()->setHorizontal('center'); + $sheet->getStyle('A4:E4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN); + // Isi data + $row = 5; + foreach ($data as $index => $item) { + $sheet->setCellValue("A{$row}", $index + 1); + $sheet->setCellValue("B{$row}", $item->order->nama_pemesan); + $sheet->setCellValue("C{$row}", $item->type === "pelanggan_setia" ? "Pelanggan Setia" : "Pengguna Baru"); + $sheet->setCellValue("D{$row}", $item->kepuasan); + $sheet->setCellValue("E{$row}", $item->keterangan); + $row++; + } + // Auto size kolom + foreach(range('A', 'E') as $col){ + $sheet->getColumnDimension($col)->setAutoSize(true); + } + $lastRow = $row - 1; + $sheet->setAutoFilter("A4:E{$lastRow}"); + // Download file + $fileName = "Laporan Survei {$startDate->format('Y-m-d')} sampai {$endDate->format('Y-m-d')} ". '.xlsx'; + $writer = new Xlsx($spreadsheet); + + // Output ke browser + header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header('Cache-Control: max-age=0'); + + $writer->save('php://output'); + exit; + } +} diff --git a/app/Models/Karyawan.php b/app/Models/Karyawan.php new file mode 100644 index 0000000..7a3a0d4 --- /dev/null +++ b/app/Models/Karyawan.php @@ -0,0 +1,16 @@ +hasMany(OrderDetail::class, 'order_id')->with('paketMenu', 'menu'); + return $this->hasMany(OrderDetail::class, 'order_id')->with('masterMcu', 'menu'); } } diff --git a/app/Models/OrderDetail.php b/app/Models/OrderDetail.php index 6560000..e75af14 100644 --- a/app/Models/OrderDetail.php +++ b/app/Models/OrderDetail.php @@ -15,7 +15,7 @@ class OrderDetail extends Model 'modified_at', 'statusenabled', 'master_menu_id', - 'paket_mcu_id', + 'menu_mcu_id', 'harga_satuan', 'jumlah', 'tgl_antar', @@ -24,13 +24,14 @@ class OrderDetail extends Model 'status_order', 'karbohidrat_id', 'catatan', - 'jam_layanan' + 'jam_layanan', + 'total_kalori' ]; public function menu(){ - return $this->belongsTo(Menu::class, 'master_menu_id', 'master_menu_id')->select('master_menu_id', 'nama_menu', 'foto'); + return $this->belongsTo(Menu::class, 'master_menu_id', 'master_menu_id')->select('master_menu_id', 'nama_menu', 'foto', 'apakah_someday', 'apakah_mcu'); } public function karbohidrat(){ return $this->belongsTo(Karbohidrat::class, 'karbohidrat_id', 'karbohidrat_id')->select('karbohidrat_id', 'nama_karbohidrat', 'nilai_kalori'); @@ -38,4 +39,7 @@ class OrderDetail extends Model public function order(){ return $this->belongsTo(Order::class, 'order_id', 'order_id'); } + public function masterMcu(){ + return $this->belongsTo(MasterMcu::class, 'menu_mcu_id', 'menu_mcu_id'); + } } diff --git a/app/Models/Survey.php b/app/Models/Survey.php new file mode 100644 index 0000000..ff55e61 --- /dev/null +++ b/app/Models/Survey.php @@ -0,0 +1,25 @@ +belongsTo(Order::class, 'no_order', 'no_order')->select('no_order', 'nama_pemesan'); + } +} diff --git a/app/Models/UnitInstalasi.php b/app/Models/UnitInstalasi.php new file mode 100644 index 0000000..a9fe49e --- /dev/null +++ b/app/Models/UnitInstalasi.php @@ -0,0 +1,16 @@ +by($request->ip()); + }); + Blade::component('dashboard.pesanan.components.modalExport', 'modalExport'); Blade::component('dashboard.pesanan.components.infoPesanan', 'infoPesanan'); + if ($this->app->environment('production')) { + URL::forceScheme('https'); + } } } diff --git a/composer.json b/composer.json index ceae8c3..4375997 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "require": { "php": "^8.2", "barryvdh/laravel-dompdf": "^3.1", + "barryvdh/laravel-snappy": "^1.0", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", "phpoffice/phpspreadsheet": "^4.5" diff --git a/composer.lock b/composer.lock index 4bf5e89..e0b5412 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "696ae0d1187bc1634529f1760a11ffd0", + "content-hash": "9d83b6a45b530b893999cf984c08fde5", "packages": [ { "name": "barryvdh/laravel-dompdf", @@ -83,6 +83,84 @@ ], "time": "2025-02-13T15:07:54+00:00" }, + { + "name": "barryvdh/laravel-snappy", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-snappy.git", + "reference": "5b8668e4a54be630973fd309b4cb1abe75a8afbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/5b8668e4a54be630973fd309b4cb1abe75a8afbb", + "reference": "5b8668e4a54be630973fd309b4cb1abe75a8afbb", + "shasum": "" + }, + "require": { + "illuminate/filesystem": "^9|^10|^11|^12", + "illuminate/support": "^9|^10|^11|^12", + "knplabs/knp-snappy": "^1.4.4", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^7|^8|^9|^10" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "PDF": "Barryvdh\\Snappy\\Facades\\SnappyPdf", + "SnappyImage": "Barryvdh\\Snappy\\Facades\\SnappyImage" + }, + "providers": [ + "Barryvdh\\Snappy\\ServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Snappy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Snappy PDF/Image for Laravel", + "keywords": [ + "image", + "laravel", + "pdf", + "snappy", + "wkhtmltoimage", + "wkhtmltopdf" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-snappy/issues", + "source": "https://github.com/barryvdh/laravel-snappy/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-02-24T15:20:06+00:00" + }, { "name": "brick/math", "version": "0.13.1", @@ -1365,6 +1443,73 @@ ], "time": "2025-02-03T10:55:03+00:00" }, + { + "name": "knplabs/knp-snappy", + "version": "v1.5.1", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/snappy.git", + "reference": "3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7", + "reference": "3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0||^3.0", + "symfony/process": "^5.0||^6.0||^7.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.0", + "pedrotroller/php-cs-custom-fixer": "^2.19", + "phpstan/phpstan": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Knp\\Snappy\\": "src/Knp/Snappy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KNP Labs Team", + "homepage": "http://knplabs.com" + }, + { + "name": "Symfony Community", + "homepage": "http://github.com/KnpLabs/snappy/contributors" + } + ], + "description": "PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.", + "homepage": "http://github.com/KnpLabs/snappy", + "keywords": [ + "knp", + "knplabs", + "pdf", + "snapshot", + "thumbnail", + "wkhtmltopdf" + ], + "support": { + "issues": "https://github.com/KnpLabs/snappy/issues", + "source": "https://github.com/KnpLabs/snappy/tree/v1.5.1" + }, + "time": "2025-01-06T16:53:26+00:00" + }, { "name": "laravel/framework", "version": "v12.20.0", diff --git a/config/database.php b/config/database.php index c3004ca..6f02fa6 100644 --- a/config/database.php +++ b/config/database.php @@ -16,7 +16,7 @@ return [ | */ - 'default' => env('DB_CONNECTION', 'sqlite'), + 'default' => env('DB_CONNECTION', 'pgsql'), /* |-------------------------------------------------------------------------- @@ -152,6 +152,28 @@ return [ 'timezone' => env('APP_TIMEZONE', 'utc' ), ], + 'dbKaryawan' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST_KARYAWAN', '127.0.0.1'), + 'port' => env('DB_PORT_KARYAWAN', '3306'), + 'database' => env('DB_DATABASE_KARYAWAN', 'laravel'), + 'username' => env('DB_USERNAME_KARYAWAN', 'root'), + 'password' => env('DB_PASSWORD_KARYAWAN', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + 'timezone' => env('APP_TIMEZONE', 'utc' ), + ], + + + ], /* diff --git a/config/snappy.php b/config/snappy.php new file mode 100644 index 0000000..cc28fbc --- /dev/null +++ b/config/snappy.php @@ -0,0 +1,52 @@ + [ + 'enabled' => true, + 'binary' => env('WKHTML_PDF_BINARY', '/usr/local/bin/wkhtmltopdf'), + 'timeout' => false, + 'options' => [], + 'env' => [], + ], + + 'image' => [ + 'enabled' => true, + 'binary' => env('WKHTML_IMG_BINARY', '/usr/local/bin/wkhtmltoimage'), + 'timeout' => false, + 'options' => [], + 'env' => [], + ], + +]; diff --git a/env_prod b/env_prod index ce41865..5d2f816 100644 --- a/env_prod +++ b/env_prod @@ -1,9 +1,9 @@ APP_NAME=Laravel -APP_ENV=local +APP_ENV=production APP_KEY=base64:R54Pgs6qwWsP6eKZGCcHNd7rrsSSU0DsWSbFHwaT4Bc= APP_DEBUG=true APP_URL=http://127.0.0.1:8000/ -APP_TIMEZONE =Asia/Jakarta +APP_TIMEZONE=Asia/Jakarta APP_LOCALE=en APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US @@ -23,16 +23,16 @@ LOG_LEVEL=debug DB_CONNECTION_ORDER_GIZI= pgsql DB_HOST_ORDER_GIZI = 172.16.88.22 DB_PORT_ORDER_GIZI = 5432 -DB_DATABASE_ORDER_GIZI = order_gizi +DB_DATABASE_ORDER_GIZI = lms_mutu DB_USERNAME_ORDER_GIZI = simrs DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@ -DB_CONNECTION_ORDER_GIZI= pgsql -DB_HOST_ORDER_GIZI = 172.16.88.22 -DB_PORT_ORDER_GIZI = 5432 -DB_DATABASE_ORDER_GIZI = order_gizi -DB_USERNAME_ORDER_GIZI = simrs -DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@ +DB_CONNECTION_AUTH_KARYAWAN = pgsql +DB_HOST_KARYAWAN = psql1.rsabhk.lan +DB_PORT_KARYAWAN = 5432 +DB_DATABASE_KARYAWAN = rsab_hk_production +DB_USERNAME_KARYAWAN = postgres +DB_PASSWORD_KARYAWAN = postgres DB_CONNECTION_AUTH_DEV = pgsql DB_HOST_AUTH_DEV = 172.16.88.22 diff --git a/public/asset_guests/css/main.css b/public/asset_guests/css/main.css index 4e48dca..bc9731f 100644 --- a/public/asset_guests/css/main.css +++ b/public/asset_guests/css/main.css @@ -305,7 +305,7 @@ h6 { } .header .logo img { - max-height: 36px; + max-height: 60px; margin-right: 8px; } @@ -347,6 +347,10 @@ h6 { .header .navmenu { order: 3; } + .header .logo img { + max-height: 35px; + margin-right: 8px; + } } .scrolled .header { diff --git a/public/asset_guests/vendor/js/checkOrderHref.js b/public/asset_guests/vendor/js/checkOrderHref.js index 24f0faa..bf98f58 100644 --- a/public/asset_guests/vendor/js/checkOrderHref.js +++ b/public/asset_guests/vendor/js/checkOrderHref.js @@ -1,3 +1,6 @@ function checkOrderHref(){ window.location.href = '/check-order' } +function mcu(){ + window.location.href = '/order-mcu' +} diff --git a/public/assets/img/avatars/8.jpg b/public/assets/img/avatars/8.jpg new file mode 100644 index 0000000..1129ea7 Binary files /dev/null and b/public/assets/img/avatars/8.jpg differ diff --git a/public/cara_pesan/order_karyawan.png b/public/cara_pesan/order_karyawan.png new file mode 100644 index 0000000..037baaf Binary files /dev/null and b/public/cara_pesan/order_karyawan.png differ diff --git a/public/cara_pesan/order_keluarga_pasien.png b/public/cara_pesan/order_keluarga_pasien.png new file mode 100644 index 0000000..820f7ab Binary files /dev/null and b/public/cara_pesan/order_keluarga_pasien.png differ diff --git a/public/cara_pesan/order_masyarakat_umum.png b/public/cara_pesan/order_masyarakat_umum.png new file mode 100644 index 0000000..5299ae6 Binary files /dev/null and b/public/cara_pesan/order_masyarakat_umum.png differ diff --git a/public/gambar/1NLtrcy20GE5m8e.jpg b/public/gambar/1NLtrcy20GE5m8e.jpg new file mode 100644 index 0000000..1aea8f5 Binary files /dev/null and b/public/gambar/1NLtrcy20GE5m8e.jpg differ diff --git a/public/gambar/1VhHxJmuroGL7z6.jpg b/public/gambar/1VhHxJmuroGL7z6.jpg new file mode 100644 index 0000000..8d6d04c Binary files /dev/null and b/public/gambar/1VhHxJmuroGL7z6.jpg differ diff --git a/public/gambar/3Y3Ez9eazDjltwU.jpg b/public/gambar/3Y3Ez9eazDjltwU.jpg new file mode 100644 index 0000000..f2484da Binary files /dev/null and b/public/gambar/3Y3Ez9eazDjltwU.jpg differ diff --git a/public/gambar/608,577,598,602,606.pdf b/public/gambar/608,577,598,602,606.pdf new file mode 100644 index 0000000..c0481fa Binary files /dev/null and b/public/gambar/608,577,598,602,606.pdf differ diff --git a/public/gambar/6cphK0gBVbdDpy7.jpg b/public/gambar/6cphK0gBVbdDpy7.jpg new file mode 100644 index 0000000..f7d8215 Binary files /dev/null and b/public/gambar/6cphK0gBVbdDpy7.jpg differ diff --git a/public/gambar/BDyQv2C3ZJstYk5.jpg b/public/gambar/BDyQv2C3ZJstYk5.jpg new file mode 100644 index 0000000..98d1c32 Binary files /dev/null and b/public/gambar/BDyQv2C3ZJstYk5.jpg differ diff --git a/public/gambar/BcQLFyCRKbD7fGm.jpg b/public/gambar/BcQLFyCRKbD7fGm.jpg new file mode 100644 index 0000000..65c49f2 Binary files /dev/null and b/public/gambar/BcQLFyCRKbD7fGm.jpg differ diff --git a/public/gambar/BhVLQcmU0pVMzQ5.jpg b/public/gambar/BhVLQcmU0pVMzQ5.jpg new file mode 100644 index 0000000..524daf2 Binary files /dev/null and b/public/gambar/BhVLQcmU0pVMzQ5.jpg differ diff --git a/public/gambar/CXtFH1srSvubaRK.jpg b/public/gambar/CXtFH1srSvubaRK.jpg new file mode 100644 index 0000000..3bdccb2 Binary files /dev/null and b/public/gambar/CXtFH1srSvubaRK.jpg differ diff --git a/public/gambar/DA1gXOOK4cMnL65.jpg b/public/gambar/DA1gXOOK4cMnL65.jpg new file mode 100644 index 0000000..ce2830e Binary files /dev/null and b/public/gambar/DA1gXOOK4cMnL65.jpg differ diff --git a/public/gambar/DX8Ev2haNMqhqgq.jpg b/public/gambar/DX8Ev2haNMqhqgq.jpg new file mode 100644 index 0000000..37dc734 Binary files /dev/null and b/public/gambar/DX8Ev2haNMqhqgq.jpg differ diff --git a/public/gambar/EcyHylUTMAVohMF.jpg b/public/gambar/EcyHylUTMAVohMF.jpg new file mode 100644 index 0000000..8d6d04c Binary files /dev/null and b/public/gambar/EcyHylUTMAVohMF.jpg differ diff --git a/public/gambar/GaQjbwEteuivk8G.jpg b/public/gambar/GaQjbwEteuivk8G.jpg new file mode 100644 index 0000000..d2a5bea Binary files /dev/null and b/public/gambar/GaQjbwEteuivk8G.jpg differ diff --git a/public/gambar/Lh5maoUqSTSHPpk.jpg b/public/gambar/Lh5maoUqSTSHPpk.jpg new file mode 100644 index 0000000..ceff63d Binary files /dev/null and b/public/gambar/Lh5maoUqSTSHPpk.jpg differ diff --git a/public/gambar/MIBkGAo6Wsv5U8J.jpg b/public/gambar/MIBkGAo6Wsv5U8J.jpg new file mode 100644 index 0000000..a664e84 Binary files /dev/null and b/public/gambar/MIBkGAo6Wsv5U8J.jpg differ diff --git a/public/gambar/MonkDUcZnb2adsT.jpg b/public/gambar/MonkDUcZnb2adsT.jpg new file mode 100644 index 0000000..19b0722 Binary files /dev/null and b/public/gambar/MonkDUcZnb2adsT.jpg differ diff --git a/public/gambar/NWj9s7XJsEznf32.jpg b/public/gambar/NWj9s7XJsEznf32.jpg new file mode 100644 index 0000000..4acf3d8 Binary files /dev/null and b/public/gambar/NWj9s7XJsEznf32.jpg differ diff --git a/public/gambar/Nmq2csw3jlvDbFn.jpg b/public/gambar/Nmq2csw3jlvDbFn.jpg new file mode 100644 index 0000000..ff5288c Binary files /dev/null and b/public/gambar/Nmq2csw3jlvDbFn.jpg differ diff --git a/public/gambar/OfSOkI4v8QOFLDQ.jpg b/public/gambar/OfSOkI4v8QOFLDQ.jpg new file mode 100644 index 0000000..1fe92ed Binary files /dev/null and b/public/gambar/OfSOkI4v8QOFLDQ.jpg differ diff --git a/public/gambar/S1D5M5yyMNxmKWO.jpg b/public/gambar/S1D5M5yyMNxmKWO.jpg new file mode 100644 index 0000000..bb0f3de Binary files /dev/null and b/public/gambar/S1D5M5yyMNxmKWO.jpg differ diff --git a/public/gambar/T3ykjc5sLJCJ3ys.jpg b/public/gambar/T3ykjc5sLJCJ3ys.jpg new file mode 100644 index 0000000..2023f0c Binary files /dev/null and b/public/gambar/T3ykjc5sLJCJ3ys.jpg differ diff --git a/public/gambar/Ukd0oblLPOj2gGk.jpg b/public/gambar/Ukd0oblLPOj2gGk.jpg new file mode 100644 index 0000000..bb812ac Binary files /dev/null and b/public/gambar/Ukd0oblLPOj2gGk.jpg differ diff --git a/public/gambar/V47AjynduyGYBKJ.jpg b/public/gambar/V47AjynduyGYBKJ.jpg new file mode 100644 index 0000000..a1877fb Binary files /dev/null and b/public/gambar/V47AjynduyGYBKJ.jpg differ diff --git a/public/gambar/ZyRXajWB3BFyCIJ.jpg b/public/gambar/ZyRXajWB3BFyCIJ.jpg new file mode 100644 index 0000000..d7fdf6b Binary files /dev/null and b/public/gambar/ZyRXajWB3BFyCIJ.jpg differ diff --git a/public/gambar/bt6RNaVgLohDg74.jpg b/public/gambar/bt6RNaVgLohDg74.jpg new file mode 100644 index 0000000..20bfa61 Binary files /dev/null and b/public/gambar/bt6RNaVgLohDg74.jpg differ diff --git a/public/gambar/c8RrP9pmbFQ5wPd.jpg b/public/gambar/c8RrP9pmbFQ5wPd.jpg new file mode 100644 index 0000000..ab98a02 Binary files /dev/null and b/public/gambar/c8RrP9pmbFQ5wPd.jpg differ diff --git a/public/gambar/cG1OGeEi5XzhUOK.jpg b/public/gambar/cG1OGeEi5XzhUOK.jpg new file mode 100644 index 0000000..7d8f1d1 Binary files /dev/null and b/public/gambar/cG1OGeEi5XzhUOK.jpg differ diff --git a/public/gambar/clLvziFQZnHVnMq.jpg b/public/gambar/clLvziFQZnHVnMq.jpg new file mode 100644 index 0000000..891abf5 Binary files /dev/null and b/public/gambar/clLvziFQZnHVnMq.jpg differ diff --git a/public/gambar/cs79vVJJbFkAV1C.jpg b/public/gambar/cs79vVJJbFkAV1C.jpg new file mode 100644 index 0000000..03dee42 Binary files /dev/null and b/public/gambar/cs79vVJJbFkAV1C.jpg differ diff --git a/public/gambar/d8ASQ3mkBbAkjPR.jpg b/public/gambar/d8ASQ3mkBbAkjPR.jpg new file mode 100644 index 0000000..65c49f2 Binary files /dev/null and b/public/gambar/d8ASQ3mkBbAkjPR.jpg differ diff --git a/public/gambar/dAVbOJQeJnGogUg.jpg b/public/gambar/dAVbOJQeJnGogUg.jpg new file mode 100644 index 0000000..98d1c32 Binary files /dev/null and b/public/gambar/dAVbOJQeJnGogUg.jpg differ diff --git a/public/gambar/default.png b/public/gambar/default.png new file mode 100644 index 0000000..a4f6704 Binary files /dev/null and b/public/gambar/default.png differ diff --git a/public/gambar/iJCWE840NZ8CPrD.jpg b/public/gambar/iJCWE840NZ8CPrD.jpg new file mode 100644 index 0000000..126122d Binary files /dev/null and b/public/gambar/iJCWE840NZ8CPrD.jpg differ diff --git a/public/gambar/m0UEA7GZ3eqH6yZ.jpg b/public/gambar/m0UEA7GZ3eqH6yZ.jpg new file mode 100644 index 0000000..322ca31 Binary files /dev/null and b/public/gambar/m0UEA7GZ3eqH6yZ.jpg differ diff --git a/public/gambar/sKEpPVmmXHGH42e.jpg b/public/gambar/sKEpPVmmXHGH42e.jpg new file mode 100644 index 0000000..7502f24 Binary files /dev/null and b/public/gambar/sKEpPVmmXHGH42e.jpg differ diff --git a/public/gambar/sjFBBFhx2wpSuE8.jpg b/public/gambar/sjFBBFhx2wpSuE8.jpg new file mode 100644 index 0000000..c42d79b Binary files /dev/null and b/public/gambar/sjFBBFhx2wpSuE8.jpg differ diff --git a/public/gambar/teCc2Q88QGhBUQL.jpg b/public/gambar/teCc2Q88QGhBUQL.jpg new file mode 100644 index 0000000..7502f24 Binary files /dev/null and b/public/gambar/teCc2Q88QGhBUQL.jpg differ diff --git a/public/gambar/ui9A9mjwVaZq2hj.jpg b/public/gambar/ui9A9mjwVaZq2hj.jpg new file mode 100644 index 0000000..013d276 Binary files /dev/null and b/public/gambar/ui9A9mjwVaZq2hj.jpg differ diff --git a/public/gambar/vajeyxcmaRf6JR3.jpg b/public/gambar/vajeyxcmaRf6JR3.jpg new file mode 100644 index 0000000..f4729a6 Binary files /dev/null and b/public/gambar/vajeyxcmaRf6JR3.jpg differ diff --git a/public/gambar/yugmkzUNtvyoKXG.jpg b/public/gambar/yugmkzUNtvyoKXG.jpg new file mode 100644 index 0000000..bb812ac Binary files /dev/null and b/public/gambar/yugmkzUNtvyoKXG.jpg differ diff --git a/public/gambar/zc8vn0ZMLirPaAJ.jpg b/public/gambar/zc8vn0ZMLirPaAJ.jpg new file mode 100644 index 0000000..deacad0 Binary files /dev/null and b/public/gambar/zc8vn0ZMLirPaAJ.jpg differ diff --git a/public/js/checkout/action.js b/public/js/checkout/action.js index 2dc891d..3602fb6 100644 --- a/public/js/checkout/action.js +++ b/public/js/checkout/action.js @@ -1,8 +1,7 @@ - async function submitOrderToServer(){ const totalHarga = hitungTotalHarga(); - if (sessionStorage.getItem('order_id')) { + if (sessionStorage.getItem('order_id')) { currentStep = 2; showStep(currentStep); return; @@ -33,7 +32,12 @@ async function submitOrderToServer(){ } } catch (error) { console.error('message '+error); - alert('Terdapat kesalahan coba lagi nanti!') + Swal.fire({ + title: 'Gagal!', + text: 'Terdapat kesalahan coba lagi nanti!', + icon: 'error', + confirmButtonText: 'Tutup!' + }) } } @@ -65,6 +69,11 @@ async function submitOrderToServer(){ $("#checkoutFormFinal").on('submit', async function(e){ e.preventDefault() + const buttonSubmit = $(this).find('button[type="submit"]') + if(buttonSubmit.prop('disabled')) return; + buttonSubmit.prop('disabled', true) + .html('Memproses...') + const cara_pembayaran = document.getElementById('cara_pembayaran').value; const bukti_pembayaran = document.querySelector('input[name="bukti_pembayaran"]').value; @@ -74,6 +83,7 @@ async function submitOrderToServer(){ text: 'Silahkan upload bukti pembayaran jika metode yang dipakai transfer.', icon: 'warning', }) + buttonSubmit.prop('disabled', false).html('Selesaikan Pesanan'); return; } @@ -81,6 +91,12 @@ async function submitOrderToServer(){ const form = this; const formData = new FormData(form); + const clearSession = () => { + sessionStorage.removeItem('cart'); + sessionStorage.removeItem('checkout_biodata'); + sessionStorage.removeItem('order_id'); + sessionStorage.removeItem('time_order'); + }; try { const response = await fetch('/finish-checkout', { @@ -92,29 +108,41 @@ async function submitOrderToServer(){ }); const result = await response.json(); - if (result.status) { // ✅ Hapus sessionStorage di client - sessionStorage.removeItem('cart'); - sessionStorage.removeItem('checkout_biodata'); - sessionStorage.removeItem('order_id'); - sessionStorage.removeItem('time_order'); - + clearSession() Swal.fire({ - title: 'Pesanan Berhasil!', - text: 'Terima kasih, pesanan Anda sedang kami siapkan.', + title: 'Pesanan Berhasil!', icon: 'success', - confirmButtonText: 'Berhasil!', - confirmButtonColor: '#28a745' - }).then(() => { - window.location.href = "/success-page"; // kehalaman success - }); + iconColor: '#2e7d32', // Warna hijau Kemenkes + html: ` +

Terima kasih, pesanan Anda sedang kami siapkan.

+
+

Bantu Kami Meningkatkan Layanan:

+ + + + +
+ `, + showConfirmButton: false, + showCancelButton: false, + allowOutsideClick: false, + allowEscapeKey: false + }) } else { - sessionStorage.removeItem('cart'); - sessionStorage.removeItem('checkout_biodata'); - sessionStorage.removeItem('order_id'); - sessionStorage.removeItem('time_order'); - Swal.fire({ + clearSession() + Swal.fire({ title: 'Gagal!', text: result.message, icon: 'error', @@ -124,11 +152,14 @@ async function submitOrderToServer(){ }); } } catch (err) { - sessionStorage.removeItem('cart'); - sessionStorage.removeItem('checkout_biodata'); - sessionStorage.removeItem('order_id'); - sessionStorage.removeItem('time_order'); - console.error(err); - alert("Terjadi kesalahan saat mengirim data."); + clearSession() + Swal.fire({ + title: 'Gagal!', + text: "Terjadi kesalahan saat mengirim data.", + icon: 'error', + confirmButtonText: 'Tutup!' + }) + }finally{ + buttonSubmit.prop('disabled', false).html('Selesaikan Pesanan'); } }) diff --git a/public/js/checkout/index.js b/public/js/checkout/index.js index 8b67931..d3e8b1a 100644 --- a/public/js/checkout/index.js +++ b/public/js/checkout/index.js @@ -31,67 +31,82 @@ document.addEventListener('DOMContentLoaded', () => { // Setup button step document.querySelectorAll('.next-step').forEach(btn => { btn.addEventListener('click', async () => { + const btnLoad = btn; + btnLoad.disabled = true; + btnLoad.innerHTML = 'Memproses...'; let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - - if (cart.length === 0) { + try { + if (cart.length === 0) { window.location.href = "/"; return; } if (currentStep === 0){ - if(!validateStepOne()) return - isiKonfirmasi(); - currentStep++; showStep(currentStep); - }else if(currentStep === 1){ - const {isValid, errorMessage} =validateCartBeforeSubmit(); - if (!isValid) { - Swal.fire({ - title: 'Perhatian!', - text: errorMessage, - icon: 'warning', - confirmButtonText: 'Oke' - }) - return - } - let checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '{}'); - - if (!checkout_biodata.nama_pemesan) { - Swal.fire({ - title: 'Biodata Belum Terisi!', - text: 'Lakukan Pengisian biodata terlebih dahulu.', - icon: 'warning', - confirmButtonText: 'oke!', - }).then(() => { - window.location.href = "/checkout"; - }); - return - } - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - for (const item of cart) { - for (const p of item.pesanan) { - const result = validateTanggalPemesanan(item, p.tgl); - - if (!result.valid) { - alert(result.message); - return; // hentikan di sini, tidak lanjut - } + if(!validateStepOne()) return + isiKonfirmasi(); + currentStep++; showStep(currentStep); + }else if(currentStep === 1){ + const {isValid, errorMessage} =validateCartBeforeSubmit(); + if (!isValid) { + Swal.fire({ + title: 'Perhatian!', + text: errorMessage, + icon: 'warning', + confirmButtonText: 'Oke' + }) + return } - } + let checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '{}'); + + if (!checkout_biodata.nama_pemesan) { + Swal.fire({ + title: 'Biodata Belum Terisi!', + text: 'Lakukan Pengisian biodata terlebih dahulu.', + icon: 'warning', + confirmButtonText: 'oke!', + }).then(() => { + window.location.href = "/checkout"; + }); + return + } + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + // for (const item of cart) { + // for (const p of item.pesanan) { + // const result = validateTanggalPemesanan(item, p.tgl); + + // if (!result.valid) { + // Swal.fire({ + // title: 'Perhatian!', + // text: `${result.message}`, + // icon: 'warning', + // confirmButtonText: 'Oke' + // }) + // return; // hentikan di sini, tidak lanjut + // } + // } + // } - if (!sessionStorage.getItem('order_id')) { - await submitOrderToServer(); // async function simpan ke server + if (!sessionStorage.getItem('order_id')) { + await submitOrderToServer(); // async function simpan ke server - } + } - time_order = sessionStorage.getItem('time_order') - orderDate = new Date(time_order); - deadline = new Date(orderDate.getTime() + 10 * 60 * 1000) - updateCountdown() - currentStep++; - showStep(currentStep) - }else if(currentStep === 2){ - renderCartSummary() + time_order = sessionStorage.getItem('time_order') + orderDate = new Date(time_order); + deadline = new Date(orderDate.getTime() + 20 * 60 * 1000) + updateCountdown() + currentStep++; + showStep(currentStep) + }else if(currentStep === 2){ + renderCartSummary() + } + } catch (error) { + Swal.fire('Error', 'Terjadi kesalahan, silakan coba lagi.', 'error'); + }finally{ + btnLoad.disabled = false; + btnLoad.innerHTML = 'Selanjutnya'; } + }); }); @@ -137,7 +152,7 @@ document.addEventListener('DOMContentLoaded', () => { const selisihMs = now.getTime() - orderTime.getTime(); const selisihMenit = selisihMs / 1000 / 60; - if (selisihMenit > 10) { + if (selisihMenit > 20) { // Bersihkan session sessionStorage.removeItem('cart'); sessionStorage.removeItem('checkout_biodata'); @@ -162,7 +177,7 @@ document.addEventListener('DOMContentLoaded', () => { function updateCountdown(){ const now = new Date(); orderDate = new Date(time_order); - deadline = new Date(orderDate.getTime() + 10 * 60 * 1000) + deadline = new Date(orderDate.getTime() + 20 * 60 * 1000) const distance = deadline - now if(distance <= 0){ @@ -213,322 +228,462 @@ function showStep(index) { // ======================= function toggleCustomerFields() { const selected = $('input[name="jenis_customer"]:checked').val(); - if (selected === 'Karyawan RSAB Harapan Kita') { - $('.karyawan').show(); - $('.pasien, .umum').hide(); - } else if (selected === 'Keluarga Pasien / Penunggu Pasien') { - $('.pasien').show(); - $('.karyawan, .umum').hide(); - } else { - $('.umum').show(); - $('.karyawan, .pasien').hide(); + const $nama = $('#nama_pemesan'); + + // Sembunyikan semua section + $('.karyawan, .pasien, .umum').hide(); + + // Destroy jika sudah ada selectize + if ($nama[0] && $nama[0].selectize) { + $nama[0].selectize.destroy(); + } + switch (selected) { + case 'Karyawan RSAB Harapan Kita': + $('.karyawan').show(); + $nama.val('') + $nama.removeClass('form-control') + $("#help_nama_pemesan").removeClass('d-none') + $("#help_email_karyawan").removeClass('d-none') + selectKaryawan(); // inisialisasi ulang selectize + break; + case 'Karyawan RSAB Harapan Kita (Rapat Internal, Seminar /Pelatihan)': + $('.karyawan').show(); + $nama.val('') + $nama.removeClass('form-control') + $("#help_nama_pemesan").removeClass('d-none') + $("#help_email_karyawan").removeClass('d-none') + selectKaryawan(); // inisialisasi ulang selectize + break; + case 'Keluarga Pasien / Penunggu Pasien': + $('.pasien').show(); + $nama.addClass('form-control') + $("#help_nama_pemesan").addClass('d-none') + $("#help_email_karyawan").addClass('d-none') + break; + case 'Masyarakat Umum (Corporate)' : + $('.umum').show(); + $nama.addClass('form-control') + $("#help_nama_pemesan").addClass('d-none') + $("#help_email_karyawan").addClass('d-none') + $("#modalAttentionModeUmum").modal('show'); + break; + case 'Masyarakat Umum (Personal)' : + $('.umum').show(); + $nama.addClass('form-control') + $("#help_nama_pemesan").addClass('d-none') + $("#help_email_karyawan").addClass('d-none') + $("#modalAttentionModeUmum").modal('show'); + break; + default: } } - $('input[name="jenis_customer"]').on('change', toggleCustomerFields); toggleCustomerFields(); -if (typeof checkout_biodata === 'object') { - if (checkout_biodata.jenis_customer) { - $(`input[name="jenis_customer"][value="${checkout_biodata.jenis_customer}"]`).prop('checked', true); - } - if(checkout_biodata.jenis_kelamin){ - $(`input[name="jenis_kelamin"][value="${checkout_biodata.jenis_kelamin}"]`).prop('checked', true); - } - $('#nama_pemesan').val(checkout_biodata.nama_pemesan); - // $('#tanggal_lahir').val(checkout_biodata.tanggal_lahir); - $('#tinggi_badan').val(checkout_biodata.tinggi_badan); - $('#berat_badan').val(checkout_biodata.berat_badan); - $('#no_whatsapp').val(checkout_biodata.no_whatsapp); - $('#nama_pasien').val(checkout_biodata.nama_pasien); - $('#ruang_perawatan').val(checkout_biodata.ruang_perawatan); - $('#no_kamar').val(checkout_biodata.no_kamar); - $('#kelas_perawatan').val(checkout_biodata.kelas_perawatan); - $('#bagian_instalasi').val(checkout_biodata.bagian_instalasi); - $('#no_ekstensien').val(checkout_biodata.no_ekstensien); - $('#email').val(checkout_biodata.email); - $('#alamat').val(checkout_biodata.alamat); -} - -function isiKonfirmasi() { - const biodata = { - jenis_customer: $('input[name="jenis_customer"]:checked').val(), - nama_pemesan: $('#nama_pemesan').val(), - jenis_kelamin: $('input[name="jenis_kelamin"]:checked').val(), - // tanggal_lahir: $('#tanggal_lahir').val(), - tinggi_badan: $('#tinggi_badan').val(), - berat_badan: $('#berat_badan').val(), - no_whatsapp: $('#no_whatsapp').val(), - nama_pasien: $('#nama_pasien').val(), - ruang_perawatan: $('#ruang_perawatan').val(), - no_kamar: $('#no_kamar').val(), - kelas_perawatan: $('#kelas_perawatan').val(), - bagian_instalasi: $('#bagian_instalasi').val(), - no_ekstensien: $('#no_ekstensien').val(), - email: $('#email').val(), - alamat: $('#alamat').val(), - }; - - sessionStorage.setItem('checkout_biodata', JSON.stringify(biodata)); - checkout_biodata = biodata; - renderCartSummary(); -} - -// ======================= -// FUNGSI CART / PESANAN -// ======================= -function renderCartSummary() { - const container = document.getElementById('checkout_cart_summary'); - container.innerHTML = ''; - let totalKeseluruhan = 0; - const carts = JSON.parse(sessionStorage.getItem('cart') || '[]'); - - carts.forEach((item) => { - const pesananList = Array.isArray(item.pesanan) ? item.pesanan : []; - let pesananHTML = ''; - const harga = checkout_biodata.jenis_customer === 'Karyawan RSAB Harapan Kita' - ? item.harga_karyawan || 0 - : item.harga_public || 0; - const itemTotal = pesananList.reduce((sum, p) => sum + (p.jumlah * harga), 0); - - if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") { - $('#karyawan').addClass('d-none'); - $('#pasien').removeClass('d-none'); - } else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") { - $('#karyawan').removeClass('d-none'); - $('#pasien').addClass('d-none'); - } else { - $('#karyawan').addClass('d-none'); - $('#pasien').addClass('d-none'); + if (typeof checkout_biodata === 'object') { + if (checkout_biodata.jenis_customer) { + $(`input[name="jenis_customer"][value="${checkout_biodata.jenis_customer}"]`).prop('checked', true); } - - - totalKeseluruhan += itemTotal; - pesananList.forEach((p, i) => { - const selectedDate = new Date(p.tgl); - const now = new Date(); - const isToday = selectedDate.toDateString() === now.toDateString(); - const jam = now.getHours(); - const disableSiang = isToday && jam >= 10; - const disableSore = isToday && jam >= 13; - const countDate = pesananList.length; - - if(checkout_biodata.jenis_customer === 'Karyawan RSAB Harapan Kita'){ - $("#karywan").re + if(checkout_biodata.jenis_kelamin){ + $(`input[name="jenis_kelamin"][value="${checkout_biodata.jenis_kelamin}"]`).prop('checked', true); } - pesananHTML += ` -
-
- - -
- -
- - -
- -
- - - ${item.apakah_someday ? `` : ` -
- -
`} - - -
- -
- - -
-
- - - -
-
- - -
- ${countDate > 1 - ? `` - : '' - } -
- -
-
- - `; - }); - - const itemHTML = ` -
-
- -
- ${item.nama_menu} -
- -
- -
-
${item.nama_menu}
-
Rp ${parseInt(harga).toLocaleString('id-ID')}
- ${item.deskripsi ? `

${item.deskripsi}

` : ''} -
- ${item.apakah_someday - ? 'Tersedia setiap hari (Senin - Minggu)' - : (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia')} -
-
- Menu: ${item.apakah_someday ? 'Sameday' : 'Menu Normal'} -
- ${item.kalori - ? `
Kalori: ${item.kalori} kkal
` - : ''} -
Silahkan isi tanggal pemesanan, pilih karbohidrat dan catatan pemesanan (opsional) yang diinginkan
- ${pesananHTML} - -
- - -
Total: Rp ${itemTotal.toLocaleString('id-ID')}
-
-
-
-
-
- `; - - container.insertAdjacentHTML('beforeend', itemHTML); - pesananList.forEach((p, i) => initFlatpickrTersedia(item, i)); - }); - - container.insertAdjacentHTML('beforeend', ` -
-
-
Total Keseluruhan: Rp ${totalKeseluruhan.toLocaleString('id-ID')}
-
- `); - - document.getElementById('no_order_price').textContent = 'Rp ' + totalKeseluruhan.toLocaleString('id-ID'); -} - -// ======================= -// EVENT HANDLER FIELD -// ======================= -function onJumlahChange(itemId, index) { - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .jumlah-input`); - if (!isNaN(input.value)) { - cart.find(item => item.id === itemId).pesanan[index].jumlah = parseInt(input.value); - sessionStorage.setItem('cart', JSON.stringify(cart)); - isiKonfirmasi(); - } -} - -function onTanggalChange(itemId, index) { - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .tanggal-input`); - cart.find(item => item.id === itemId).pesanan[index].tgl = input.value; - sessionStorage.setItem('cart', JSON.stringify(cart)); - renderCartSummary(); -} - -function onKarbohidratChange(itemId, index){ - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .karbohidrat-input`); - cart.find(item => item.id === itemId).pesanan[index].karbohidrat_id = parseInt(input.value); - sessionStorage.setItem('cart', JSON.stringify(cart)); - renderCartSummary(); -} - -function onKategoriChange(itemId, index, isToday) { - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - const selectEl = document.querySelector(`.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']`); - const kategori = selectEl.value; - let now = new Date(); - let jam = now.getHours(); - - if (kategori === "Makan Siang" && isToday && jam >= 10) { - batasLewat = true; - alert("Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00."); - } else if (kategori === "Makan Sore" && isToday && jam >= 15) { - batasLewat = true; - alert("Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00."); + if(checkout_biodata.jenis_customer !== 'Karyawan RSAB Harapan Kita'){ + $('#nama_pemesan').val(checkout_biodata.nama_pemesan); + } + // $('#tanggal_lahir').val(checkout_biodata.tanggal_lahir); + $('#tinggi_badan').val(checkout_biodata.tinggi_badan); + $('#berat_badan').val(checkout_biodata.berat_badan); + $('#no_whatsapp').val(checkout_biodata.no_whatsapp); + $('#nama_pasien').val(checkout_biodata.nama_pasien); + $('#ruang_perawatan').val(checkout_biodata.ruang_perawatan); + $('#no_kamar').val(checkout_biodata.no_kamar); + $('#kelas_perawatan').val(checkout_biodata.kelas_perawatan); + $('#bagian_instalasi').val(checkout_biodata.bagian_instalasi); + $('#no_ekstensien').val(checkout_biodata.no_ekstensien); + $('#email').val(checkout_biodata.email); + $('#alamat').val(checkout_biodata.alamat); } - if (batasLewat) { - // Kembalikan ke value sebelumnya - const previous = selectEl.dataset.previousValue || ''; - selectEl.value = previous; - return; - } - const item = cart.find(item => item.id === itemId); - if (item && item.pesanan && item.pesanan[index]) { - item.pesanan[index].kategoriPemesanan = kategori; - sessionStorage.setItem('cart', JSON.stringify(cart)); + function isiKonfirmasi() { + const biodata = { + jenis_customer: $('input[name="jenis_customer"]:checked').val(), + nama_pemesan: $('#nama_pemesan').val(), + jenis_kelamin: $('input[name="jenis_kelamin"]:checked').val(), + id_karyawan: $('#id_karyawan').val(), + tinggi_badan: $('#tinggi_badan').val(), + berat_badan: $('#berat_badan').val(), + no_whatsapp: $('#no_whatsapp').val(), + nama_pasien: $('#nama_pasien').val(), + ruang_perawatan: $('#ruang_perawatan').val(), + no_kamar: $('#no_kamar').val(), + kelas_perawatan: $('#kelas_perawatan').val(), + bagian_instalasi: $('#bagian_instalasi').val(), + no_ekstensien: $('#no_ekstensien').val(), + email: $('#email').val(), + alamat: $('#alamat').val(), + }; + + sessionStorage.setItem('checkout_biodata', JSON.stringify(biodata)); + checkout_biodata = biodata; renderCartSummary(); } -} + + async function getServerTime() { + const res = await fetch('/server-time'); + const data = await res.json(); + return new Date(data.now); + } + + + // ======================= + // FUNGSI CART / PESANAN + // ======================= + function renderCartSummary() { + const container = document.getElementById('checkout_cart_summary'); + container.innerHTML = ''; + let totalKeseluruhan = 0; + const carts = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const checkout_biodata = JSON.parse(sessionStorage.getItem('checkout_biodata') || '[]'); + + carts.forEach((item) => { + const pesananList = Array.isArray(item.pesanan) ? item.pesanan : []; + let pesananHTML = ''; + const harga = checkout_biodata.jenis_customer === 'Karyawan RSAB Harapan Kita' + ? item.harga_karyawan || 0 + : item.harga_public || 0; + const itemTotal = pesananList.reduce((sum, p) => sum + (p.jumlah * harga), 0); + + if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") { + $('#karyawan').removeClass('d-none'); + $('#pasien').addClass('d-none'); + $('#umum').addClass('d-none'); + } else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") { + $('#karyawan').addClass('d-none'); + $('#pasien').removeClass('d-none'); + $('#umum').addClass('d-none'); + } else { + $('#karyawan').addClass('d-none'); + $('#pasien').addClass('d-none'); + $('#umum').removeClass('d-none'); + } + + + totalKeseluruhan += itemTotal; + pesananList.forEach((p, i) => { + const selectedDate = new Date(p.tgl); + const now = new Date(); + const isToday = selectedDate.toDateString() === now.toDateString(); + const jam = now.getHours(); + const disableSiang = isToday && jam >= 10; + const disableSore = isToday && jam >= 13; + const countDate = pesananList.length; + + + pesananHTML += ` +
+
+ + +
+ +
+ + +
+ +
+ + + ${item.apakah_someday ? `` : ` +
+ +
`} + + +
+ +
+ + +
+
+ + + + +
+
+ + +
+ ${countDate > 1 + ? `` + : '' + } +
+ ${item.kalori + ? `
Total Kalori: ${p?.resultKalori ? p?.resultKalori : item?.kalori} kal
` + : ''} +
+
+ + `; + }); + + const itemHTML = ` +
+ +
+ +
+ ${item.nama_menu} +
+ +
+ +
+ +

${item.nama_menu}

+ + +
+ ${checkout_biodata?.jenis_customer === "Karyawan RSAB Harapan Kita" + ? 'Harga Karyawan' + : 'Harga' + } + Rp ${parseInt(harga).toLocaleString('id-ID')} +
+ + + ${item?.kalori ? `
Kalori: ${item.kalori} kal
` : ''} + + + ${item.deskripsi ? `

${item.deskripsi}

` : ''} + + +
+
+ + ${item.apakah_someday + ? 'Tersedia setiap hari (Senin – Minggu)' + : (item.tgl_tersedia ? `Tersedia pada tanggal: ${item.tgl_tersedia}` : 'Tidak ada info tanggal tersedia') + } +
+
+ + ${item.apakah_someday ? 'Sameday' : 'Menu Normal'} +
+
+ + +
+ Petunjuk: Isi tanggal pemesanan, pilih karbohidrat, dan catatan tambahan (opsional). +
+ + + ${pesananHTML} + + +
+ + +
+ Total: Rp ${itemTotal.toLocaleString('id-ID')} +
+
+
+
+
+
+ `; + + container.insertAdjacentHTML('beforeend', itemHTML); + pesananList.forEach((p, i) => initFlatpickrTersedia(item, i)); + }); + + container.insertAdjacentHTML('beforeend', ` +
+
+
Total Keseluruhan: Rp ${totalKeseluruhan.toLocaleString('id-ID')}
+
+ `); + + document.getElementById('no_order_price').textContent = 'Rp ' + totalKeseluruhan.toLocaleString('id-ID'); + } + + // ======================= + // EVENT HANDLER FIELD + // ======================= + function onJumlahChange(itemId, index) { + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .jumlah-input`); + if (!isNaN(input.value)) { + cart.find(item => item.id === itemId).pesanan[index].jumlah = parseInt(input.value); + sessionStorage.setItem('cart', JSON.stringify(cart)); + isiKonfirmasi(); + } + } + function ymdLocal(date) { + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, "0"); + const d = String(date.getDate()).padStart(2, "0"); + return `${y}-${m}-${d}`; + } + + + async function onTanggalChange(itemId, index) { + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .tanggal-input`); + const serverDate = await getServerTime(); + const year = serverDate.getFullYear(); + const month = String(serverDate.getMonth() + 1).padStart(2, '0'); + const day = String(serverDate.getDate()).padStart(2, '0'); + + // const todayStr = ymdLocal(new Date()); + const todayStr = `${year}-${month}-${day}` + const isToday = input.value === todayStr; + + cart.find(item => item.id === itemId).pesanan[index].tgl = input.value; + sessionStorage.setItem('cart', JSON.stringify(cart)); + const selectEl = document.querySelector( + `.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']` + ); + if (!selectEl) return; + const next = selectEl.value; + if (!isKategoriMasihDibuka(next, isToday)) { + cart.find(item => item.id === itemId).pesanan[index].kategoriPemesanan = null; + sessionStorage.setItem("cart", JSON.stringify(cart)); + // Tampilkan alert & revert ke sebelumnya + const msg = + next === "Makan Siang" + ? "Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00." + : "Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00."; + + Swal.fire({ title: "Perhatian!", text: msg, icon: "warning" }).then(() => { + selectEl.value = ""; + }); + } + renderCartSummary(); + } + + function onKarbohidratChange(itemId, index, el, kalori){ + const selectedOption = el.options[el.selectedIndex]; + const kaloriOption = parseInt(selectedOption.getAttribute('data-kalori')) || 0; + + const kaloriMenuInt = kalori || 0; + + const totalKalori = kaloriOption + kaloriMenuInt; + const kaloriEl = document.getElementById(`kalori_${itemId}_${index}`); + + if (kaloriEl) { + kaloriEl.textContent = totalKalori ; + } + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const input = document.querySelector(`div[data-item-id='${itemId}'][data-index='${index}'] .karbohidrat-input`); + cart.find(item => item.id === itemId).pesanan[index].karbohidrat_id = parseInt(input.value); + cart.find(item => item.id === itemId).pesanan[index].resultKalori = totalKalori; + sessionStorage.setItem('cart', JSON.stringify(cart)); + } + + function onKategoriChange(itemId, index, isToday) { + const selectEl = document.querySelector( + `.kategori-pemesanan-input[data-item-id='${itemId}'][data-index='${index}']` + ); + if (!selectEl) return; + const next = selectEl.value; + + // Validasi batas waktu + let cart = JSON.parse(sessionStorage.getItem("cart") || "[]"); + const item = cart.find((it) => it.id === itemId); + if (!isKategoriMasihDibuka(next, isToday)) { + + item.pesanan[index].kategoriPemesanan = null; + sessionStorage.setItem("cart", JSON.stringify(cart)); + + // Tampilkan alert & revert ke sebelumnya + const msg = + next === "Makan Siang" + ? "Pemesanan Makan Siang hanya bisa dilakukan sebelum jam 10:00." + : "Pemesanan Makan Sore hanya bisa dilakukan sebelum jam 13:00."; + + Swal.fire({ title: "Perhatian!", text: msg, icon: "warning" }).then(() => { + selectEl.value = ""; + }); + return; + }else{ + if (item && item.pesanan && item.pesanan[index]) { + item.pesanan[index].kategoriPemesanan = next; + sessionStorage.setItem("cart", JSON.stringify(cart)); + // update nilai previous + selectEl.dataset.previousValue = next; + // rerender ringkasan + if (typeof renderCartSummary === "function") renderCartSummary(); + } + } + } + + function isKategoriMasihDibuka(kategori, isToday) { + if (!isToday) return true; // pesanan untuk hari lain bebas + const jam = new Date().getHours(); + const cutoff = { "Makan Siang": 10, "Makan Sore": 15 }; + return cutoff[kategori] ? jam < cutoff[kategori] : true; + } + // ======================= @@ -548,19 +703,19 @@ function addOrderDate(itemId, sore) { } } -function removeOrderDate(itemId, index, count) { - let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); - const item = cart.find(i => i.id === itemId); + function removeOrderDate(itemId, index, count) { + let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); + const item = cart.find(i => i.id === itemId); - if(count == 1){ - cart = cart.filter(i => i.id !== itemId); - sessionStorage.setItem('cart', JSON.stringify(cart)); - }else if(item && Array.isArray(item.pesanan) && item.pesanan.length > index) { - item.pesanan.splice(index, 1); - sessionStorage.setItem('cart', JSON.stringify(cart)); + if(count == 1){ + cart = cart.filter(i => i.id !== itemId); + sessionStorage.setItem('cart', JSON.stringify(cart)); + }else if(item && Array.isArray(item.pesanan) && item.pesanan.length > index) { + item.pesanan.splice(index, 1); + sessionStorage.setItem('cart', JSON.stringify(cart)); + } + renderCartSummary(); } - renderCartSummary(); -} function removeCartItem(itemId){ @@ -570,105 +725,105 @@ function removeOrderDate(itemId, index, count) { renderCartSummary() } -// validasi step one dan sebelum submit -function validateStepOne() { - const jenisCustomer = document.querySelector('input[name="jenis_customer"]:checked'); - const jenisKelamin = document.querySelector('input[name="jenis_kelamin"]:checked'); - const namaPemesan = document.getElementById('nama_pemesan').value.trim(); - const noWA = document.getElementById('no_whatsapp').value.trim(); - const email = document.getElementById('email').value.trim(); + // validasi step one dan sebelum submit + function validateStepOne() { + const jenisCustomer = document.querySelector('input[name="jenis_customer"]:checked'); + const jenisKelamin = document.querySelector('input[name="jenis_kelamin"]:checked'); + const namaPemesan = document.getElementById('nama_pemesan').value.trim(); + const noWA = document.getElementById('no_whatsapp').value.trim(); + const email = document.getElementById('email').value.trim(); - if (!jenisCustomer) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan pilih jenis customer.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - - if (!namaPemesan) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan isi nama pemesan.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - - if (!jenisKelamin) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan pilih jenis kelamin.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - - if (!noWA) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan isi nomor WhatsApp.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - if (!email) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan isi email terlebih dahulu.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - - // Validasi tambahan sesuai jenis customer - const selected = jenisCustomer.value; - if (selected === 'Karyawan RSAB Harapan Kita') { - const bagian = document.getElementById('bagian_instalasi').value.trim(); - if (!bagian) { - Swal.fire({ - title: 'Perhatian!', - text: 'Silakan lengkapi data karyawan.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false; - } - } else if (selected === 'Keluarga Pasien / Penunggu Pasien') { - const namaPasien = document.getElementById('nama_pasien').value.trim(); - const ruang = document.getElementById('ruang_perawatan').value; - const noKamar = document.getElementById('no_kamar').value.trim(); - const kelas = document.getElementById('kelas_perawatan').value; - if (!namaPasien || !ruang || !noKamar || !kelas) { + if (!jenisCustomer) { Swal.fire({ - title: 'Perhatian!', - text: 'Silakan lengkapi data pasien.', - icon: 'warning', - confirmButtonText: 'Oke' - }) + title: 'Perhatian!', + text: 'Silakan pilih jenis customer.', + icon: 'warning', + confirmButtonText: 'Oke' + }) return false; } - }else if(selected === "Masyarakat Umum"){ - const alamat = document.getElementById('alamat').value; - if(!alamat){ - Swal.fire({ - title: 'Perhatian!', - text: 'Silahkan lengkapi alamat.', - icon: 'warning', - confirmButtonText: 'Oke' - }) - return false - } - } - return true; -} + if (!namaPemesan) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan isi nama pemesan.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + + if (!jenisKelamin) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan pilih jenis kelamin.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + + if (!noWA) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan isi nomor WhatsApp.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + if (!email) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan isi email terlebih dahulu.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + + // Validasi tambahan sesuai jenis customer + const selected = jenisCustomer.value; + if (selected === 'Karyawan RSAB Harapan Kita') { + const bagian = document.getElementById('bagian_instalasi').value.trim(); + if (!bagian) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan lengkapi data karyawan.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + } else if (selected === 'Keluarga Pasien / Penunggu Pasien') { + const namaPasien = document.getElementById('nama_pasien').value.trim(); + const ruang = document.getElementById('ruang_perawatan').value; + const noKamar = document.getElementById('no_kamar').value.trim(); + const kelas = document.getElementById('kelas_perawatan').value; + if (!namaPasien || !ruang || !noKamar || !kelas) { + Swal.fire({ + title: 'Perhatian!', + text: 'Silakan lengkapi data pasien.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false; + } + }else if(selected === "Masyarakat Umum"){ + const alamat = document.getElementById('alamat').value; + if(!alamat){ + Swal.fire({ + title: 'Perhatian!', + text: 'Silahkan lengkapi alamat.', + icon: 'warning', + confirmButtonText: 'Oke' + }) + return false + } + } + + return true; + } function validateCartBeforeSubmit() { @@ -679,8 +834,6 @@ function validateCartBeforeSubmit() { cart.forEach((item, index) => { const pesananList = item.pesanan || []; pesananList.forEach((pesanan, i) => { - console.log(!pesanan.karbohidrat_id, !item?.apakah_someday); - if (!pesanan.tgl) { isValid = false; errorMessage = `Tanggal belum diisi pada item "${item.nama_menu}" (baris ${i + 1})`; @@ -708,7 +861,6 @@ function hitungTotalHarga(){ cart.forEach(item => { const harga = biodata.jenis_customer === "Karyawan RSAB Harapan Kita" ? item.harga_karyawan : item.harga_public || 0 - const itemTotal = item.pesanan?.reduce((sum, p) => sum + (p.jumlah * harga), 0); total += itemTotal }) @@ -720,20 +872,42 @@ function hitungTotalHarga(){ function copyNoRek() { const text = document.getElementById('noRekText').innerText; navigator.clipboard.writeText(text).then(() => { - alert("Nomor rekening berhasil disalin: " + text); + Swal.fire({ + icon: 'success', + title: 'Disalin!', + text: 'Nomor rekening berhasil disalin: ' + text, + showConfirmButton: false, + timer: 1500 + }); }).catch(err => { console.error('Gagal menyalin: ', err); - alert("Gagal menyalin teks."); + Swal.fire({ + icon: 'warning', + text: 'Gagal menyalin teks: ' + text, + showConfirmButton: false, + timer: 2000 + }); }); } function copyNoOrder() { const text = document.getElementById('no_order_display').innerText; navigator.clipboard.writeText(text).then(() => { - alert("Nomor order berhasil disalin: " + text); + Swal.fire({ + icon: 'success', + title: 'Disalin!', + text: 'Nomor order berhasil disalin: ' + text, + showConfirmButton: false, + timer: 1500 + }); }).catch(err => { console.error('Gagal menyalin: ', err); - alert("Gagal menyalin teks."); + Swal.fire({ + icon: 'warning', + text: 'Gagal menyalin teks: ' + text, + showConfirmButton: false, + timer: 2000 + }); }); } @@ -770,12 +944,13 @@ function initFlatpickrTersedia(item, i) { dayNumbers.forEach(day => { const dayStr = String(day).padStart(2, '0'); const fullDateStr = `${year}-${month}-${dayStr}`; - const fullDate = new Date(`${fullDateStr}T00:00:00`); + const fullDate = new Date(`${fullDateStr}T13:00:00`); // Jika bukan menu someday, cek aturan H-1 dan jam batas if (item.apakah_someday) { availableDates.push(fullDateStr); } else { + const selisihHari = Math.floor((fullDate - now) / (1000 * 60 * 60 * 24)); if (selisihHari >= 1 || (selisihHari === 1 && !lewatBatasNormal)) { availableDates.push(fullDateStr); @@ -788,7 +963,7 @@ function initFlatpickrTersedia(item, i) { let minTanggal = 'today'; - // Jika item adalah someday dan waktu sekarang sudah lewat 13:00 + // Jika item adalah someday dan waktu sekarang sudah lewat 13:00 if (item?.apakah_someday && totalMenitFlatSekarang >= 13 * 60) { const besok = new Date(now); besok.setDate(now.getDate() + 1); @@ -800,10 +975,11 @@ function initFlatpickrTersedia(item, i) { dateFormat: "Y-m-d", ...(item?.apakah_someday ? {minDate: minTanggal} : {enable:availableDates}), defaultDate: item.pesanan[i]?.tgl || null, + disableMobile: true, onChange: function(selectedDates, dateStr) { onTanggalChange(item.id, i, dateStr); } - }); + }); } @@ -816,13 +992,12 @@ function increment(itemId, index) { function decrement(itemId, index) { const input = document.getElementById(`jumlah-${itemId}-${index}`); let current = parseInt(input.value || "0"); - console.log(current); if (current > 1) { input.value = current - 1; onJumlahChange(itemId, index); }else{ - return + return; } } @@ -857,10 +1032,12 @@ function validateTanggalPemesanan(item, tglDipilih) { const batasWaktu = 13 * 60; const tglSekarang = now.toISOString().split("T")[0]; + // console.log(totalMenit, batasWaktu); + if (item.apakah_someday && totalMenit >= batasWaktu && tglDipilih === tglSekarang) { return { valid: false, - message: `Maaf, Anda tidak bisa memilih hari ini (${tglDipilih}) untuk menu sameday karena sudah lewat jam 13:00` + message: `Maaf, Anda tidak bisa memilih ini (${tglDipilih}) untuk menu sameday karena sudah lewat dari batas jam pemesanan` }; } @@ -892,7 +1069,6 @@ document.getElementById('submitNote').addEventListener('click', function(e){ const noted = $("#note_order").val() const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); const item =cart.find(item => item.id === id) - console.log(id, index, item); if(item && item.pesanan && item.pesanan[index]){ item.pesanan[index].catatan = noted @@ -907,3 +1083,86 @@ document.getElementById('submitNote').addEventListener('click', function(e){ }) } }); + + +function selectKaryawan(){ + const $el = $('#nama_pemesan'); + + // 1. destroy jika sudah ada + if ($el[0] && $el[0].selectize) { + $el[0].selectize.destroy(); + } + $el.selectize({ + valueField: 'label', // sama dengan labelField + labelField: 'label', + searchField: ['label'], + create: function(input) { + return { + label: input, + value: input + }; + }, + createOnBlur: true, + placeholder: "Cari nama karyawan...", + maxItems: 1, + load: function (query, callback) { + $.ajax({ + url: '/karyawan', + data: { search: query }, + success: res => callback(res.data || []), + error: () => callback([]) + }); + }, + render: { + option: (item, escape) => + `
${escape(item.label)}
`, + item: (item, escape) => `
${escape(item.label)}
` + } + }); +} + +selectUnitInstalasi() +function selectUnitInstalasi(){ + const bagian_instalasi = $('#bagian_instalasi'); + + // 1. destroy jika sudah ada + if (bagian_instalasi[0] && bagian_instalasi[0].selectize) { + bagian_instalasi[0].selectize.destroy(); + } + bagian_instalasi.selectize({ + valueField: 'label', + labelField: 'label', + searchField: ['label'], + create: false, + sortField: [], + placeholder: "Cari unit instalasi...", + maxItems:1, + load: function (query, callback) { + $.ajax({ + url: '/unit-instalasi', + data: { search: query }, + success: function (response) { + if (response.error === 0 && Array.isArray(response.data)) { + callback(response.data); + } else { + callback(); + } + }, + error: function () { + callback(); + } + }); + }, + render: { + option: function (item, escape) { + + return `
+
${escape(item.label)}
+
`; + }, + item: function (item, escape) { + return `
${escape(item?.label)}
`; + } + } + }); +} diff --git a/public/js/laporan_pesanan/action.js b/public/js/laporan_pesanan/action.js index 06d4579..d9bc4cb 100644 --- a/public/js/laporan_pesanan/action.js +++ b/public/js/laporan_pesanan/action.js @@ -10,13 +10,15 @@ function fetchDetailOrder(order_id){
-
+
Foto Menu
-
-

Nama Menu: ${detail?.menu?.nama_menu || '-'}

+
+

Nama Menu: ${detail?.menu?.nama_menu || detail?.master_mcu?.nama_mcu}

Jumlah: ${detail?.jumlah || 0}

-

Tanggal Pesan: ${detail?.tgl_antar || 0}

+ ${detail?.total_kalori ? `

Total Kalori: ${detail?.total_kalori } kal

` : ''} + +

Tanggal Antar: ${detail?.tgl_antar || 0}

Harga: Rp ${parseInt(detail?.harga_satuan || 0).toLocaleString('id-ID')}

Status Pesanan:

-

Catatan : ${detail?.catatan || '-'}

+ ${detail?.catatan ? `

Catatan : ${detail?.catatan || '-'}

` : ''}
@@ -69,12 +71,12 @@ function fetchDetailOrder(order_id){

Alamat: ${data.alamat || '-'}

- ` : ` + ` : data?.jenis_customer === 'Karyawan RSAB Harapan Kita' ?`

Bagian / Instalasi: ${data.bagian_instalasi}

Ekstensien: ${data.no_ekstensien || '-'}

- ` + ` : '' }
@@ -92,7 +94,7 @@ function fetchDetailOrder(order_id){
${data.status_order} - +
diff --git a/public/js/laporan_pesanan/dt.js b/public/js/laporan_pesanan/dt.js index c56b06b..7fc5b7e 100644 --- a/public/js/laporan_pesanan/dt.js +++ b/public/js/laporan_pesanan/dt.js @@ -161,7 +161,10 @@ }, { title: "Kategori Customer", - field: 'jenis_customer', + formatter: function(value, row){ + + return row?.nama_institusi ? row?.nama_institusi + ' (MCU)': row?.jenis_customer; + }, sortable: true, }, { diff --git a/public/js/menu/action.js b/public/js/menu/action.js index b70d2a3..7da9f4b 100644 --- a/public/js/menu/action.js +++ b/public/js/menu/action.js @@ -222,8 +222,9 @@ document.getElementById('formMasterMenu').addEventListener('submit', function(e) const allFormSetsBeforSubmit = document.querySelectorAll('.form-set'); for (let i = 0; i < allFormSetsBeforSubmit.length; i++) { - const checkSiang = allFormSetsBeforSubmit[i].querySelector(`input[name="data[${i}][apakah_menu_siang]"]`); - const checkSore = allFormSetsBeforSubmit[i].querySelector(`input[name="data[${i}][apakah_menu_sore]"]`); + + const checkSiang = allFormSetsBeforSubmit[i].querySelector(`input[name*="[apakah_menu_siang]"]`); + const checkSore = allFormSetsBeforSubmit[i].querySelector(`input[name*="[apakah_menu_sore]"]`); if (!checkSiang?.checked && !checkSore?.checked) { e.preventDefault(); diff --git a/public/js/menu/dt.js b/public/js/menu/dt.js index 4970ad5..6277073 100644 --- a/public/js/menu/dt.js +++ b/public/js/menu/dt.js @@ -91,7 +91,9 @@ }, { title:"Nama Menu", - field:"nama_menu", + formatter:function(value, row){ + return row?.kalori[0]?.nilai_kalori ? row?.nama_menu + ' ' + '(' + row?.kalori[0]?.nilai_kalori + ' kal)' : row?.nama_menu + }, width: 300 }, { diff --git a/public/js/order_guest/checkout.js b/public/js/order_guest/checkout.js index e253792..80043e2 100644 --- a/public/js/order_guest/checkout.js +++ b/public/js/order_guest/checkout.js @@ -94,18 +94,6 @@ let orderIndex = 0; $('#cartTotal').text('Rp ' + total.toLocaleString('id-ID')); } - - - - - - - - - - - - function renderCartTotalOnly() { const cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); let total = 0; diff --git a/public/js/order_guest/functions.js b/public/js/order_guest/functions.js index 1039734..403271a 100644 --- a/public/js/order_guest/functions.js +++ b/public/js/order_guest/functions.js @@ -9,24 +9,34 @@ $(document).ready(function(){ fetchMenu(filterState) - $('#tabJenisMenu .nav-link').on('click', function(e){ + $('#tabJenisMenu .btn').on('click', function(e) { e.preventDefault(); - const jenis = $(this).data('filter') - $('#tabJenisMenu .nav-link').removeClass('active text-success').addClass('text-black'); + const jenis = $(this).data('filter'); - $(this).closest('.nav-link').removeClass('text-black').addClass('active text-success'); + // reset semua button jadi outline-success + $('#tabJenisMenu .btn') + .removeClass('btn-success active') + .addClass('btn-outline-success'); + // set button yang dipilih jadi active + $(this) + .removeClass('btn-outline-success') + .addClass('btn-success active'); + + // reset datepicker & label datePicker.clear(); - document.getElementById('tanggalTerpilihLabel').classList.add('d-none'); // Sembunyikan label - document.getElementById('tanggalTerpilihLabel').textContent = ''; - document.getElementById('resetTanggal').classList.add('d-none'); - filterState.jenis_menu = jenis - fetchMenu(filterState) - }) + $('#tanggalTerpilihLabel').addClass('d-none').text(''); + $('#resetTanggal').addClass('d-none'); + + // set filter state + filterState.jenis_menu = jenis; + fetchMenu(filterState); + }); + $(".alert-link").on('click', function(e){ e.preventDefault(); - $('#tabJenisMenu .nav-link').removeClass('active text-success').addClass('text-black'); - $('#tabJenisMenu .nav-link[data-filter="konsultasi" ]').removeClass('text-black').addClass('active text-success'); + $('#tabJenisMenu .btn').removeClass('btn-success active').addClass('btn-outline-success'); + $('#tabJenisMenu .btn[data-filter="konsultasi" ]').removeClass('btn-outline-success').addClass('btn-success active'); if (typeof datePicker !== 'undefined') { datePicker.clear(); @@ -51,6 +61,8 @@ $(document).ready(function(){ fetchMenu(filterState) }, 300) }) + + }) function changePerPage(select) { diff --git a/public/js/order_guest/index.js b/public/js/order_guest/index.js index 6aad180..d1f8433 100644 --- a/public/js/order_guest/index.js +++ b/public/js/order_guest/index.js @@ -3,14 +3,152 @@ if (cart.length > 0) { $('#floatingCartButton').removeClass('d-none'); $('#menuBtn').removeClass('d-none'); - } + } + + }); - + function openImageModal(imageSrc, title) { + document.getElementById('modalImage').src = imageSrc; + document.getElementById('imageModalLabel').textContent = title; + $('#imageModal').modal('show'); + } function fetchMenu(filter = {}) { const containerGuest = $("#order_guest_id"); $("#tanggal-filter").removeClass('d-none'); + if (filter.jenis_menu === "cara_pesan") { + $("#tanggal-filter").addClass('d-none'); + const cara_pesan = [ + { + type: "Karyawan RSAB Harapan Kita", + gambar: "/cara_pesan/order_karyawan.png", + color: "success" + }, + { + type: "Keluarga Pasien / Penunggu Pasien", + gambar: "/cara_pesan/order_keluarga_pasien.png", + color: "success" + }, + { + type: "Masyarakat Umum", + gambar: "/cara_pesan/order_masyarakat_umum.png", + color: "success" + } + ]; + + let html = ` +
+
+

Cara Pemesanan

+
+ +
+ `; + + cara_pesan.forEach((cara, index) => { + html += ` +
+
+
+
+
+ + ${cara.type} + +
+
+
${cara.type}
+ Panduan pemesanan +
+ +
+
+ `; + }); + + + html += ` +
+
+ + + + + + `; + containerGuest.html(html); + + GLightbox({ + selector: '.glightbox', + touchNavigation: true, + loop: true, + zoomable: true, + autoplayVideos: true + }); + return + } + let params = new URLSearchParams({ page: filter.page || 1, @@ -40,12 +178,11 @@ if(filter.jenis_menu === "konsultasi"){ const jk = res.data|| []; - console.log(jk); $("#tanggal-filter").addClass('d-none'); let html = `
-

+

Jadwal Konsultasi

@@ -147,6 +284,11 @@ --soft-gray: #f8f9fa; --charcoal: #2d3436; } + .text-gradient { + background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + } .bg-gradient-primary { background: linear-gradient(135deg, var(--mint-dark) 0%, var(--mint) 100%); } @@ -202,6 +344,7 @@ `); } + let html = '
'; for (const [label, list] of Object.entries(groups)) { let scheduleInfo = ''; @@ -227,6 +370,7 @@
`; list?.forEach(menu => { + html += ` + + + + +
CATERING RSAB HARAPAN KITA
+
No Order : {{ $label?->order?->no_order ?? 'xxxxxx' }}
+ + + @if($label->order?->jenis_customer === 'MCU') + + + + + @endif + + + + + + @if($label?->order?->jenis_customer === "Keluarga Pasien / Penunggu Pasien") + + + + + @elseif($label?->order?->jenis_customer === "Karyawan RSAB Harapan Kita") + + + + + @endif + + @if ($label?->order?->nama_institusi) + + + + + @endif + + + + + @if($label->total_kalori) + + @endif + + + + + + @if ($label?->order?->alamat) + + + + + @endif + +
Tanggal Pemeriksaan + : {{ $label?->tgl_antar ? \Carbon\Carbon::parse($label->tgl_antar)->translatedFormat('d F Y') : '-' }} +
{{ $label->order?->jenis_customer !== 'MCU' ? 'Nama Pemesan' : 'Nama Pasien'}} + {{ $label?->order?->jenis_customer === "Keluarga Pasien / Penunggu Pasien" ? '/ Pasien' : ''}} + : + + {{ $label?->order?->nama_pemesan }} {{ $label?->order?->jenis_customer === "Keluarga Pasien / Penunggu Pasien" ? '/ ' . $label?->order?->nama_pasien : ''}} + +
Ruang Perawatan/No Kamar: + + {{ $label?->order?->ruang_perawatan ?? '-'}} / {{ $label?->order?->no_kamar_perawatan ?? '-'}} + +
Bagian/No Ekstensien : + + {{ $label?->order?->bagian_instalasi ?? '-'}} / {{ $label?->order?->no_ekstensien ?? '-'}} + +
Nama Institusi: + + {{ $label?->order?->nama_institusi }} + + +
{{ $label->order?->jenis_customer !== 'MCU' ? 'Pesanan' : 'Jenis MCU'}} + : + + {{ $label?->masterMcu?->nama_mcu ?? $label?->menu?->nama_menu }} + +
Total Kalori: {{ $label->total_kalori }}
Catatan: + + {{ $label?->catatan ?? '-' }} +
Tanggal Produksi: {{ $label?->tgl_antar ? \Carbon\Carbon::parse($label->tgl_antar)->translatedFormat('d F Y') : '-' }}
No. Telp: {{ $label?->order?->no_wa ?? '-' }}
Alamat: + + {{ $label?->order?->alamat }} + + +
+ + + + + diff --git a/resources/views/dashboard/label/multi.blade.php b/resources/views/dashboard/label/multi.blade.php new file mode 100644 index 0000000..7dfbc19 --- /dev/null +++ b/resources/views/dashboard/label/multi.blade.php @@ -0,0 +1,5 @@ +@foreach ($orderDetail as $label) +
last) style="page-break-after: always;" @endif> + @include('dashboard.label.index', ['label' => $label]) +
+@endforeach diff --git a/resources/views/dashboard/layouts/main.blade.php b/resources/views/dashboard/layouts/main.blade.php index 8a7ee3c..e0c9e4c 100644 --- a/resources/views/dashboard/layouts/main.blade.php +++ b/resources/views/dashboard/layouts/main.blade.php @@ -19,7 +19,7 @@ - + @@ -41,7 +41,7 @@ - + {{-- flatcpicker css --}} diff --git a/resources/views/dashboard/master/menu/modal/detail.blade.php b/resources/views/dashboard/master/menu/modal/detail.blade.php index d9713a8..83f9b1d 100644 --- a/resources/views/dashboard/master/menu/modal/detail.blade.php +++ b/resources/views/dashboard/master/menu/modal/detail.blade.php @@ -12,6 +12,7 @@ + Foto Menu
diff --git a/resources/views/dashboard/partials/footer.blade.php b/resources/views/dashboard/partials/footer.blade.php index 93458ca..8db6006 100644 --- a/resources/views/dashboard/partials/footer.blade.php +++ b/resources/views/dashboard/partials/footer.blade.php @@ -6,7 +6,7 @@ document.write(new Date().getFullYear()); , made with by - TIM SIMRS + TIM SIMRS
diff --git a/resources/views/dashboard/partials/sidenav.blade.php b/resources/views/dashboard/partials/sidenav.blade.php index 2f9be18..3ccb79c 100644 --- a/resources/views/dashboard/partials/sidenav.blade.php +++ b/resources/views/dashboard/partials/sidenav.blade.php @@ -77,7 +77,7 @@ @@ -109,6 +109,14 @@
Laporan Pesanan
+ + + {{--