on progress

This commit is contained in:
JokoPrasetio 2025-07-28 23:37:51 +07:00
parent 80548af3a7
commit b9b22a2848
10 changed files with 234 additions and 20 deletions

View File

@ -107,7 +107,8 @@ class CustomerController extends Controller
private static function dataPaketMenuOrder($search = null, $perPage){
$query = DB::connection('dbOrderGizi')->table('public.master_paket_menu as mpn')->where('mpn.statusenabled', true);
$query = DB::connection('dbOrderGizi')->table('public.master_paket_menu as mpn')
->where('mpn.statusenabled', true);
if(!empty($search)){
$query->where('mpn.nama_paket', 'ILIKE', '%' . $search . '%');
@ -121,11 +122,13 @@ class CustomerController extends Controller
'mpn.harga_karyawan',
'mpn.harga_keluarga_pasien',
'mpn.deskripsi',
'mpn.status'
'mpn.status',
'dmph.detail_menu_paket_harian_id',
'dmph.tgl_harian'
)->paginate($perPage);
$paketMenuIds = collect($paginated->items())->pluck('master_paket_menu_id')->toArray();
dd($paketMenuIds);
$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')

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\Order;
use App\Models\OrderDetail;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -22,8 +23,45 @@ class PesananController extends Controller
public function getDataPending(){
$data = Order::where('statusenabled', true)->get();
return $data;
$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)
->select(
'o.order_id',
'o.no_order',
'o.nama_pemesan',
'o.jenis_customer',
'o.total_harga',
'o.status_order',
'o.bukti_pembayaran',
'o.note_dibatalkan',
'od.status_order as detail_status_order'
)->get()->groupBy('order_id');
$grouped = $orders->map(function($items){
$first = $items->first();
$totalDetail = $items->count();
$selesaiDetail = $items->where('detail_status_order', 'Selesai')->count();
$progress = $totalDetail > 0 ? round(($selesaiDetail / $totalDetail) * 100) : 0;
return [
'order_id' => $first->order_id,
'no_order' => $first->no_order,
'nama_pemesan' => $first->nama_pemesan,
'jenis_customer' => $first->jenis_customer,
'total_harga' => $first->total_harga,
'status_order' => $first->status_order,
'bukti_pembayaran' => $first->bukti_pembayaran,
'progress' => $progress,
'total_detail' => $totalDetail,
'selesai_detail' => $selesaiDetail,
'note_dibatalkan' => $first->note_dibatalkan,
];
})->values();
return response()->json([
'status' => true,
'rows' => $grouped->values(),
'total' => $grouped->count()
]);
}
public function actionOrder(Request $request, string $order_id){
@ -88,6 +126,18 @@ class PesananController extends Controller
return response()->json($data);
}
public function updateDetailStatusOrder($order_detail_id){
$orderDetail = OrderDetail::where('order_detail_id', $order_detail_id)->first();
$payload = [
'status_order' => 'Selesai',
'modified_at' => Carbon::now(),
];
$orderDetail->update($payload);
return response()->json([
'status' => true,
]);
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@ -139,6 +139,7 @@ document.getElementById('formActionApproveBillingOrder').addEventListener('submi
});
function approveProgress(e){
function approveProgress(order_id){
new bootstrap.Modal(modalActionProgressOrder).show();
fetchDetailOrder(order_id)
}

View File

@ -0,0 +1,144 @@
function fetchDetailOrder(order_id){
fetch(`/dashboard/pending/action-progress-order/${order_id}`)
.then(res => res.json())
.then(res => {
const data = res;
document.getElementById('pesanan_container').innerHTML =''
// Generate HTML untuk order_detail
const detailHTML = (data?.order_detail || []).map(detail => {
return `
<div class="col-md-12 mb-3">
<div class="card shadow-sm">
<div class="row g-0">
<div class="col-md-5 d-flex align-items-center p-2">
<img src="/gambar/${detail?.menu?.foto || 'default.jpg'}" alt="Foto Menu" class="img-fluid rounded shadow" style="max-height: 120px; width: auto;">
</div>
<div class="col-md-5 p-2">
<p class="mb-1">Nama Menu: <strong>${detail?.menu?.nama_menu || '-'}</strong></p>
<p class="mb-1">Jumlah: <span>${detail?.jumlah || 0}</span></p>
<p class="mb-1">Tanggal Pesan: <span>${detail?.tgl_antar || 0}</span></p>
<p class="mb-1">Harga: <strong>Rp ${parseInt(detail?.harga_satuan || 0).toLocaleString('id-ID')}</strong></p>
<p class="mb-1">Status Pesanan:
<span class="badge text-dark ${detail?.status_order === 'Selesai' ? 'bg-success' : 'bg-warning'}"
id="status_badge_${detail.order_detail_id}">
${detail?.status_order}
</span>
</p>
</div>
<div class="form-check form-switch mt-2">
<input class="form-check-input status-switch" type="checkbox"
id="switch_status_${detail.order_detail_id}"
data-id="${detail.order_detail_id}"
${detail.status_order === 'Selesai' ? 'checked' : ''} ${detail.status_order === 'Selesai' ? 'disabled' : ''}>
<label class="form-check-label " for="switch_status_${detail.order_detail_id}">
${detail.status_order === 'Selesai' ? `Selesai` : 'Tandai sebagai Selesai'}
</label>
</div>
</div>
</div>
</div>
`;
}).join('');
const html = `
<div class="row mt-3">
<!-- Bagian Kiri: Gambar Bukti Pembayaran -->
<div class="col-md-4 text-center mb-3 mb-md-0">
<img src="/storage/${data.bukti_pembayaran || 'gambar/default.jpg'}" alt="Bukti Pembayaran" class="img-fluid rounded shadow" style="max-height: 170px; width: auto;">
</div>
<!-- Bagian Kanan: Informasi Pemesan -->
<div class="col-md-8">
<div class="mb-2">
<h5 class="mb-0">Nama Pemesan: <span class="text-primary" id="nama_pemesan">${data.nama_pemesan}</span></h5>
<small class="text-muted">Jenis Customer: <span id="jenis_customer">${data.jenis_customer}</span></small>
</div>
<div class="mb-2">
<p class="mb-1">No Order: <strong id="no_order">${data.no_order}</strong></p>
<p class="mb-1">Type Pembayaran: <strong id="no_order">${data.cara_pembayaran}</strong></p>
<p class="mb-1">Tanggal Pembayaran: <span id="tgl_pembayaran">${data.tgl_pembayaran || '-'}</span></p>
<p class="mb-1">Total Harga: <strong id="total_harga">Rp ${parseInt(data.total_harga).toLocaleString('id-ID')}</strong></p>
</div>
<div class="mt-3">
<label class="form-label">Status Saat Ini:</label>
<span class="badge text-dark ${data?.status_order === 'Lunas' ? 'bg-success' : 'bg-warning'}" id="status_order">${data.status_order}</span>
</div>
</div>
</div>
<hr class="my-4">
<div class="row">
${detailHTML}
</div>
`;
document.getElementById('pesanan_container').innerHTML = html;
document.querySelectorAll('.status-switch').forEach(el => {
el.addEventListener('change', function () {
const id = this.dataset.id;
const isChecked = this.checked;
const newStatus = isChecked ? 'Selesai' : 'Pending';
// Update badge UI
const badge = document.getElementById(`status_badge_${id}`);
if (badge) {
badge.innerText = newStatus;
badge.className = `badge text-dark ${isChecked ? 'bg-success' : 'bg-warning'}`;
}
// Kirim ke backend
fetch(`/dashboard/pending/update-detail-status/${id}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value
},
body: JSON.stringify({ status_order: newStatus })
})
.then(res => res.json())
.then(res => {
el.disabled = true;
datatablePending.bootstrapTable('refresh')
showToast('Status berhasil diperbarui!');
})
.catch(err => {
console.error('Gagal update status:', err);
});
});
});
})
.catch(err => {
document.getElementById('pesanan_container').innerHTML = '<p class="text-danger">Terjadi kesalahan saat memuat data.</p>';
console.error(err);
});
}
// Tambah listener untuk semua switch
function showToast(message, isError = false) {
const toastId = `toast_${Date.now()}`;
const toastHTML = `
<div id="${toastId}" class="toast align-items-center text-white ${isError ? 'bg-danger' : 'bg-success'} border-0 show" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">${message}</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
`;
const container = document.getElementById('toastContainer');
container.insertAdjacentHTML('beforeend', toastHTML);
// Hapus toast setelah 3 detik
setTimeout(() => {
const toast = document.getElementById(toastId);
if (toast) toast.remove();
}, 3000);
}

View File

@ -83,7 +83,7 @@
} else if (status === "Menunggu Konfirmasi Pembayaran") {
badgeClass = 'bg-primary';
} else if (status === "Lunas" || status === "Sudah Bayar") {
badgeClass = 'bg-success';
badgeClass = 'bg-success text-dark';
} else if(status === "Dibatalkan"){
badgeClass = 'bg-danger';
}
@ -99,6 +99,24 @@
},
{
title: "Status Pesanan",
formatter: function(value, row) {
const progress = parseInt(row.progress) || 0;
const total = row.total_detail || 0;
const selesai = row.selesai_detail || 0;
return `
<div class="text-center">
<div class="progress" style="height: 18px;">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${progress}%;"
aria-valuenow="${progress}" aria-valuemin="0" aria-valuemax="100">
${progress}%
</div>
</div>
<small class="text-muted">${selesai} / ${total} selesai</small>
</div>
`;
},
sortable: true,
},
{

View File

@ -104,6 +104,7 @@
</div>
<!-- Overlay -->
<div id="toastContainer" class="position-fixed top-0 end-0 p-3" style="z-index: 9999;"></div>
<div class="layout-overlay layout-menu-toggle"></div>
</div>
<!-- / Layout wrapper -->

View File

@ -25,4 +25,5 @@
<script src="{{ ver('/js/pesanan_pending/_init.js') }}"></script>
<script src="{{ ver('/js/pesanan_pending/dt.js') }}"></script>
<script src="{{ ver('/js/pesanan_pending/action.js') }}"></script>
<script src="{{ ver('/js/pesanan_pending/action_progres_order.js') }}"></script>
@endsection

View File

@ -13,22 +13,17 @@
<form method="POST" id="formActionProgressOrder">
@csrf
@method('put')
<div class="modal-body ">
<div class="container">
<div class="row mt-3">
<div class="col-md-4 text-center mb-3 mb-md-0">
<img alt="Foto Menu" id="cathering_order_photo" lass="img-fluid rounded shadow" style="max-height: 170px; width: auto;">
</div>
<div class="col-md-8">
</div>
</div>
</div>
</div>
<div class="modal-body">
<div class="container" id="pesanan_container"></div>
<!-- Tempatkan ini di layout HTML -->
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Setujui</button>
</div>
</form>

View File

@ -37,7 +37,8 @@ Route::group(['middleware' => ['auth']], function(){
Route::get('datatable/pending', [PesananController::class, 'getDataPending']);
Route::put('/pending/action/{order_id}', [PesananController::class, 'actionOrder']);
Route::put('/pending/action-billing/{order_id}', [PesananController::class, 'actionOrderViaBilling']);
Route::get('/action/progress-order/{order_id}', [PesananController::class, 'getDataOrderDetail']);
Route::get('/pending/action-progress-order/{order_id}', [PesananController::class, 'getDataOrderDetail']);
Route::post('/pending/update-detail-status/{order_id}', [PesananController::class, 'updateDetailStatusOrder']);
});