order_gizi/app/Http/Controllers/CustomerController.php

640 lines
26 KiB
PHP

<?php
namespace App\Http\Controllers;
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',
'mcu' => false,
];
return view('guest.index', $payload);
}
public function dataOrder(){
$search = request('search');
$jenis_menu = request('jenis_menu');
$perPage = request()->get('per_page', 50);
$tanggal_awal = (int) request('tanggal_awal');
$tanggal_akhir = (int) request('tanggal_akhir');
if($jenis_menu === "konsultasi"){
return self::konsultasi();
}else{
return self::menuOrder($search, $jenis_menu, $perPage, $tanggal_awal, $tanggal_akhir);
}
}
private static function menuOrder($search = null, $jenis_menu = null, $perPage, $tanggal_awal = null, $tanggal_akhir = null)
{
$payloadHari = [];
if (!empty($tanggal_awal) && !empty($tanggal_akhir)) {
if ($tanggal_awal > 0 && $tanggal_akhir >= $tanggal_awal) {
$payloadHari = range($tanggal_awal, $tanggal_akhir);
}
}
$menuIdTanggalValid = [];
if (!empty($payloadHari)) {
$menuIdTanggalValid = DB::connection('dbOrderGizi')
->table('public.detail_menu_paket_harian')
->whereIn('tgl_harian', $payloadHari)
->pluck('master_menu_id')
->unique()
->toArray();
}
// Step 2: Query menu
$menuQuery = DB::connection('dbOrderGizi')
->table('public.master_menu as mn')
->where(['mn.statusenabled' => true, 'mn.status' => true]);
if (!empty($jenis_menu)) {
$menuQuery->where('mn.jenis_menu', 'ILIKE', '%' . $jenis_menu . '%');
}
if (!empty($search)) {
$menuQuery->where('mn.nama_menu', 'ILIKE', '%' . $search . '%');
}
$menuQuery->where(function ($q) use ($menuIdTanggalValid, $payloadHari) {
if (!empty($menuIdTanggalValid)) {
// Jika ada filter tanggal: tampilkan menu sesuai tanggal atau yang someday
$q->whereIn('mn.master_menu_id', $menuIdTanggalValid)
->orWhere('mn.apakah_someday', true);
}else if($payloadHari){
$q->where('mn.apakah_someday', true);
}
// Jika TIDAK ada tanggal, tidak perlu where apapun — biarkan tampil semua menu
});
// }
$menuItems = $menuQuery->select(
'mn.master_menu_id',
'mn.nama_menu',
'mn.foto',
'mn.jenis_menu',
'mn.harga_public',
'mn.harga_karyawan',
'mn.harga_keluarga_pasien',
'mn.status',
'mn.deskripsi',
'mn.apakah_someday',
'mn.apakah_menu_siang',
'mn.apakah_menu_sore',
)->get();
$menuIds = $menuItems->pluck('master_menu_id')->toArray();
if (empty($menuIds)) {
return self::emptyMenuResponse($perPage);
}
// Step 3: Relasi data tambahan
$klasifikasi = DB::connection('dbOrderGizi')
->table('public.klasifikasi_menu_diet as kmd')
->join('public.kategori_diet as kd', 'kd.kategori_diet_id', '=', 'kmd.kategori_diet_id')
->whereIn('kmd.master_menu_id', $menuIds)
->select('kmd.master_menu_id', 'kd.kategori_diet_id', 'kd.nama_kategori_diet')
->get()
->groupBy('master_menu_id');
$dmph = DB::connection('dbOrderGizi')
->table('public.detail_menu_paket_harian as dmph')
->whereIn('dmph.master_menu_id', $menuIds)
->select('dmph.master_menu_id', 'dmph.tgl_harian')
->get()
->groupBy('master_menu_id');
$kkal = DB::connection('dbOrderGizi')
->table('public.klasifikasi_menu_kalori as kmk')
->join('public.kalori as k', 'k.kalori_id', 'kmk.kalori_id')
->whereIn('kmk.master_menu_id', $menuIds)
->select('kmk.master_menu_id', 'k.kalori_id', 'k.nilai_kalori')
->get()
->groupBy('master_menu_id');
function buildGroupLabel($tglList, $isSomeday){
if($isSomeday) return 'Menu Sameday';
if(empty($tglList)) return '-';
$days = collect($tglList)
->map(fn($t) => substr($t, -2))
->unique()
->sort()
->values();
// Jika semua tanggal memiliki digit terakhir yang sama, gabungkan
$tanggal = implode(',', $days->toArray());
return 'Menu Normal Tersedia Tanggal ' . $tanggal;
}
// Step 4: Transform response
$enriched = $menuItems->map(function ($menu) use ($klasifikasi, $dmph, $kkal) {
$tglList = isset($dmph[$menu->master_menu_id]) ? collect($dmph[$menu->master_menu_id])->pluck('tgl_harian')->toArray() : [];
$groupLabel = buildGroupLabel($tglList, $menu->apakah_someday);
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,
'harga_karyawan' => $menu->harga_karyawan,
'harga_keluarga_pasien' => $menu->harga_keluarga_pasien,
'status' => $menu->status,
'deskripsi' => $menu->deskripsi,
'apakah_someday' => $menu->apakah_someday,
'apakah_menu_sore' => $menu->apakah_menu_sore,
'apakah_menu_siang' => $menu->apakah_menu_siang,
'group_label' => $groupLabel,
'klasifikasiMenu' => isset($klasifikasi[$menu->master_menu_id]) ? $klasifikasi[$menu->master_menu_id]->map(function ($item) {
return [
'kategori_diet_id' => $item->kategori_diet_id,
'nama_kategori_diet' => $item->nama_kategori_diet,
];
})->values() : [],
'dmph' => isset($dmph[$menu->master_menu_id]) ? $dmph[$menu->master_menu_id]->map(function ($item) {
return [
'tgl_harian' => $item->tgl_harian
];
})->values() : [],
'kalori' => isset($kkal[$menu->master_menu_id]) ? $kkal[$menu->master_menu_id]->map(function ($item) {
return [
'nilai_kalori' => $item->nilai_kalori,
];
})->values() : [],
];
});
// Urutkan: someday → tgl_harian terdekat
$sorted = $enriched->sortBy(function ($menu) {
$besok = now()->addDay()->day;
$isSomeday = $menu['apakah_someday'] ? 0 : 1;
if ($menu['apakah_someday']) {
return [0, 0];
}
$tglTerdekat = collect($menu['dmph'])->pluck('tgl_harian')
->map(function ($tgl) use ($besok) {
if ($tgl == $besok) {
return 0; // Besok paling awal
}
return $tgl > $besok ? $tgl : $tgl + 31;
})
->sort()
->first() ?? 99;
return [$isSomeday, $tglTerdekat];
})->values();
// Paginate manual (setelah sort)
$total = $sorted->count();
$currentPage = request()->get('page', 1);
$offset = ($currentPage - 1) * $perPage;
$pagedData = $sorted->slice($offset, $perPage)->values();
return response()->json([
'status' => true,
'message' => 'Berhasil mendapatkan data',
'data' => [
'data' => $pagedData,
'current_page' => (int) $currentPage,
'last_page' => (int) ceil($total / $perPage),
'per_page' => (int) $perPage,
'total' => $total,
]
]);
}
private static function emptyMenuResponse($perPage)
{
return response()->json([
'status' => true,
'message' => 'Tidak ada menu ditemukan',
'data' => [
'data' => [],
'current_page' => 1,
'last_page' => 1,
'per_page' => $perPage,
'total' => 0,
]
]);
}
private static function konsultasi(){
$data = JadwalKonsul::where('statusenabled', true)->with('tglAvailable')->get();
return response()->json([
'status' => true,
'message' => 'Berhasil mendapatkan data',
'data' => $data
]);
}
public function checkout(){
$karbohidrat = Karbohidrat::where('statusenabled', true)->select('karbohidrat_id', 'nama_karbohidrat', 'nilai_kalori')->get();
$payload = [
'title' => 'Checkout ',
'karbohidrat' => $karbohidrat,
'mcu' => false,
];
return view('guest.checkout.checkout_payment', $payload);
}
public function submitCheckout(){
$dataCart = request()->input('cartResult');
$biodataResult = request()->input('biodataResult');
$totalHarga = request()->input('totalHarga');
DB::connection('dbOrderGizi')->beginTransaction();
try {
$jenisCustomer = $biodataResult['jenis_customer'];
$today = now()->toDateString();
$jumlahHariIni = Order::whereDate('entry_at', $today)->count();
$urutan = $jumlahHariIni + 1;
$noOrder = 'TX/CT/GIZI/' . now()->year .'/'. now()->month .'/' . now()->day .'/' . Str::random(6) .'/' . str_pad($urutan, 4, '0', STR_PAD_LEFT);
$payloadOrder = [
'no_order' => $noOrder,
'jenis_customer' => $jenisCustomer,
'nama_pemesan' => $biodataResult['nama_pemesan'],
'jenis_kelamin' => $biodataResult['jenis_kelamin'],
// 'tanggal_lahir' => $biodataResult['tanggal_lahir'],
'no_wa' => $biodataResult['no_whatsapp'],
'tinggi_badan' => $biodataResult['tinggi_badan'],
'berat_badan' => $biodataResult['berat_badan'],
'total_harga' => $totalHarga,
'status_order' => "Belum Bayar",
'email' => $biodataResult['email'],
'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 = [
'order_id' => $order->order_id,
'harga_satuan' => $jenisCustomer === "Karyawan RSAB Harapan Kita" ? $cart['harga_karyawan'] : $cart['harga_public'],
'status_order' => "Pending"
];
foreach ($cart['pesanan'] as $value) {
$payloadOrderDetail['jumlah'] = $value['jumlah'];
$payloadOrderDetail['tgl_antar'] = $value['tgl'];
$payloadOrderDetail['type'] = $value['kategoriPemesanan'];
$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){
try {
Mail::to($order->email)->send(new NotifikasiCustomer($order->nama_pemesan, $order->no_order, $order->total_harga));
} catch (\Throwable $th) {
//throw $th;
}
}
DB::connection('dbOrderGizi')->commit();
return response()->json([
'status' => true,
'data' => $order,
'entry_at' => Carbon::now(),
'message' => 'Data berhasil disimpan'
]);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Data gagal disimpan ' . $th->getMessage()
]);
}
}
public function finishCheckout(){
DB::connection('dbOrderGizi')->beginTransaction();
try {
$noOrder = request('no_order_result');
$medical_record = request('medical_record');
$evidence = request()->file('bukti_pembayaran');
$caraPembayaran = request('cara_pembayaran');
$order = Order::where('no_order', $noOrder)->first();
// Simpan file ke storage
if (!$order) {
return response()->json(['status' => false, 'message' => 'Nomor order tidak ditemukan'], 404);
}
$entryAt = Carbon::parse($order->entry_at)->copy()->addMinutes(10);
if(Carbon::now()->gt($entryAt)){
return response()->json(['status' => false, 'message' => 'Waktu pembayaran sudah habis, lakukan pemesanan ulang'],403);
}
$payload = [
'tgl_pembayaran' => Carbon::now()
];
if($caraPembayaran === "transfer"){
if (!$evidence) {
return response()->json(['status' => false, 'message' => 'Bukti pembayaran wajib diunggah'], 422);
}
$path = $evidence->store('bukti_pembayaran', 'public');
$payload['bukti_pembayaran'] = $path;
$payload['cara_pembayaran'] = 'Transfer';
$payload['status_order'] = 'Menunggu Konfirmasi Pembayaran';
}else{
$payload['cara_pembayaran'] = 'Billing';
$payload['status_order'] = 'Menunggu Konfirmasi Pembayaran Via Billing';
$payload['medical_record'] = $medical_record ?? null;
}
// Update data order
$order->update($payload);
if($order->email){
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::connection('dbOrderGizi')->commit();
session()->flash('payment_success', true);
session()->flash('no_order', $noOrder);
return response([
'status' => true,
'message' => 'Terima kasih atas pesanan Anda. Mohon tunggu, kami sedang memprosesnya'
], 200);
return back()->with('success', 'Bukti pembayaran berhasil diunggah.');
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response([
'status' => false,
'message' => 'Gagal melakukan pesanan!'
], 500);
}
}
public function success(){
if(!session()->has('payment_success')){
return redirect('/');
}
$payload = [
'title' => 'Berhasil Melakukan Pembayaran ',
'no_order' => session('no_order'),
'mcu' => false,
];
return view('guest.success_page', $payload);
}
public function checkOrder(){
$payload = [
'title' => 'Check Order',
'mcu' => false,
];
return view('guest.check_order.index', $payload);
}
public function searchOrder(){
$noOrder = request('no_order');
$order = DB::connection('dbOrderGizi')
->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.*',
'od.order_detail_id',
'od.jumlah',
'od.tgl_antar',
'od.harga_satuan',
'od.status_order as status_order_detail',
'od.catatan',
'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();
if ($order->isEmpty()) {
return response()->json([
'status' => false,
'message' => 'Pesanan tidak ditemukan'
], 404);
}
$data = $order->first();
$result = [
'order_id' => $data->order_id,
'nama_pemesan' => $data->nama_pemesan,
'jenis_kelamin' => $data->jenis_kelamin,
'tgl_pesanan' => $data->entry_at,
'tgl_pembayaran' => $data->tgl_pembayaran,
'bukti_bayar' => $data->bukti_pembayaran,
'cara_pembayaran' => $data->cara_pembayaran,
'status_order' => $data->status_order,
'total_harga' => $data->total_harga,
'no_order' => $data->no_order,
'jenis_customer' => $data->jenis_customer,
'no_wa' => $data->no_wa,
// pasien
'nama_pasien' => $data->nama_pasien,
'kelas_perawatan' => $data->kelas_perawatan,
'no_kamar_perawatan' => $data->no_kamar_perawatan,
'ruang_perawatan' => $data->ruang_perawatan,
// 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 ?? '-',
'total_kalori' => $item->total_kalori,
'type' => $item->type,
'jam_layanan' => $item->jam_layanan,
// tambahkan field tambahan jika diperlukan
];
})->values(),
];
return response()->json([
'status' => true,
'data' => $result,
], 200);
}
public function indexMcu(){
$paketMcu = MasterMcu::where('statusenabled', true)->get();
$data = [
'title' => 'Order Gizi MCU',
'paketMcu' => $paketMcu,
'mcu' => true,
];
return view('guest.mcu.index', $data);
}
public function storeMcu(){
try {
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 = [
'email' => request('email') ?? null,
'nama_pemesan' => request('nama_pemesan'),
'jenis_customer' => 'MCU',
'medical_record' => request('no_mr'),
'jenis_kelamin' => request('jenis_kelamin'),
'no_order' => $noOrder,
'no_wa' => request('no_hp') ?? null,
'tinggi_badan' => request('tinggi_badan') ?? null,
'berat_badan' => request('berat_badan') ?? null,
'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'),
'status_order' =>'Pending',
'harga_satuan' => $priceMcu ? $priceMcu->harga : null,
];
OrderDetail::create($payloadDetail);
DB::connection('dbOrderGizi')->commit();
session()->flash('success_mcu', true);
session()->flash('no_order', $noOrder);
return response()->json([
'status' => true,
'message' => 'Pesanan Berhasil diproses'
]);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Pesanan gagal diproses ' . $th->getMessage()
]);
}
}
public function successMcu(){
if(!session()->has('success_mcu')){
return redirect('/order-mcu');
}
$payload = [
'title' => 'Berhasil Melakukan Pesanan ',
'no_order' => session('no_order'),
'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]);
}
}