action approval & reject sudah siap

This commit is contained in:
JokoPrasetio 2025-07-24 15:35:32 +07:00
parent 55aa4456f3
commit 39b362a838
12 changed files with 243 additions and 50 deletions

View File

@ -3,7 +3,9 @@
namespace App\Http\Controllers;
use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class PesananController extends Controller
{
@ -24,6 +26,36 @@ class PesananController extends Controller
return $data;
}
public function actionOrder(Request $request, string $order_id){
DB::connection('dbOrderGizi')->beginTransaction();
try {
$order = Order::where('order_id', $order_id)->first();
$action = $request->query('action');
$payload = [
'pegawai_id_confirm_order' => auth()->user()->id,
'pegawai_name_confirm_order' => auth()->user()->full_name,
'pegawai_at_confirm_order' => Carbon::now(),
'status_order' => $action ?? 'Dibatalkan',
];
if(!$action){
$payload['note_dibatalkan'] = request('note_dibatalkan');
}
$order->update($payload);
DB::connection('dbOrderGizi')->commit();
return response()->json([
'status' => true,
'message' => $action ? 'Konfirmasi Order Gizi telah disetujui!' : 'Konfirmasi Order Gizi telah dibatalkan'
]);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Gagal melakukan Konfirmasi Order Gizi'
]);
//throw $th;
}
}
/**
* Show the form for creating a new resource.
*/

View File

@ -33,6 +33,7 @@ class Order extends Model
'tinggi_badan',
'berat_badan',
'ruang_perawatan',
'bagian_instalasi'
'bagian_instalasi',
'note_dibatalkan'
];
}

View File

@ -86,7 +86,7 @@ return [
*/
'batching' => [
'database' => env('DB_CONNECTION', 'sqlite'),
'database' => env('DB_CONNECTION_ORDER_GIZI', 'sqlite'),
'table' => 'job_batches',
],
@ -105,7 +105,7 @@ return [
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'sqlite'),
'database' => env('DB_CONNECTION_ORDER_GIZI', 'sqlite'),
'table' => 'failed_jobs',
],

View File

@ -120,3 +120,10 @@
background-color: #584ce0;
}
.swal2-container {
z-index: 9999 !important;
}
.swal2-backdrop-show {
z-index: 9998 !important;
}

View File

@ -1 +1,6 @@
const datatablePending = $("#datatablePesananPending")
const modalActionOrder = document.getElementById("modalActionOrder")
const formActionOrder = $("#formActionOrder")
const containerCancel = document.getElementById("note_dibatalkan")
const noteCancelTextArea = document.getElementById("textarea_note_dibatalkan")

View File

@ -0,0 +1,85 @@
function approveOrder(e) {
const data = $(e).data();
const form = document.getElementById('formActionOrder');
const img = document.getElementById('imageConfirmActionOrder');
$("#confirmActionOrder").text('Konfirmasi Pembayaran '+ data.nama_pemesan + ' / ' + data.no_order)
containerCancel.classList.add('d-none');
// Set gambar bukti bayar
if (data.bukti_bayar) {
img.src = `/storage/${data.bukti_bayar}`;
img.classList.remove('d-none');
} else {
img.classList.add('d-none');
img.src = '';
$("#tidak_ada_bukti_pembayaran").text('Pembayaran Menggunakan Billing')
}
// Set action form
form.setAttribute('action', `/dashboard/pending/action/${data.order_id}?action=Lunas`);
// Tampilkan modal
new bootstrap.Modal(modalActionOrder).show();
}
document.getElementById('formActionOrder').addEventListener('submit', function (e) {
e.preventDefault();
const form = this;
const actionUrl = form.getAttribute('action');
const formData = new FormData(form);
fetch(actionUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value,
},
body: formData
}).then(async (res) => {
const data = await res.json();
if (res.status) {
const handler = function () {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: data.message || 'Status berhasil diubah!',
timer: 2000,
showConfirmButton: false,
backdrop: true,
});
datatablePending.bootstrapTable('refresh');
modalActionOrder.removeEventListener('hidden.bs.modal', handler); // ✅ pakai DOM
};
modalActionOrder.addEventListener('hidden.bs.modal', handler); // ✅ pakai DOM
bootstrap.Modal.getInstance(modalActionOrder).hide(); // ✅ pakai instance
} else {
throw new Error(data.message || 'Terjadi kesalahan saat mengubah status.');
}
}).catch(err => {
console.error(err);
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message || 'Terjadi kesalahan pada server.',
});
});
});
function rejectOrder(e){
document.getElementById('imageConfirmActionOrder').classList.add('d-none')
containerCancel.classList.remove('d-none');
const data = $(e).data();
new bootstrap.Modal(modalActionOrder).show();
$("#confirmActionOrder").text('Batalkan Pembayaran '+ data.nama_pemesan + ' / ' + data.no_order)
formActionOrder.attr('action', `/dashboard/pending/action/${data.order_id}`);
$("#textarea_note_dibatalkan").val('')
}
noteCancelTextArea.addEventListener('input', function () {
this.style.height = 'auto'; // Reset height dulu
this.style.height = this.scrollHeight + 'px'; // Set height sesuai isi
});

View File

@ -24,51 +24,49 @@
title: "Action",
field:'order_id',
formatter: function(value, row) {
const rowData = row; // jika butuh ID atau status dari baris
return `
<div class="d-flex flex-wrap gap-2 justify-content-center">
<button class="btn btn-sm btn-success" onclick="approveOrder('${rowData.id}')">
<i class="fa fa-check me-1"></i>
</button>
${row?.status_order === "Lunas" ? '' : `
<button class="btn btn-sm btn-danger" onclick="rejectOrder('${rowData.id}')">
let buttons = ''
if(row?.status_order === "Dibatalkan") return ''
if(row?.status_order === "Menunggu Konfirmasi Pembayaran"){
buttons += `
<button class="btn btn-sm btn-success me-2" onclick="approveOrder(this)" data-order_id="${row.order_id}" data-nama_pemesan="${row?.nama_pemesan}" data-no_order="${row?.no_order}" data-bukti_bayar="${row?.bukti_pembayaran}" data-jenis_customer="${row?.jenis_customer}">
<i class="fa fa-check me-1"></i>
</button>
`
}
if(row?.status_order !== "Lunas"){
buttons += `
<button class="btn btn-sm btn-danger me-2" onclick="rejectOrder(this)"
data-order_id="${row.order_id}" data-nama_pemesan="${row?.nama_pemesan}" data-no_order="${row?.no_order}" data-bukti_bayar="${row?.bukti_pembayaran}" data-jenis_customer="${row?.jenis_customer}">
<i class="fa fa-times me-1"></i>
</button>
<button class="btn btn-sm btn-warning text-dark" onclick="approveProgress('${rowData.id}')">
<i class="fa fa-utensils me-1"></i>
</button>
`}
</button>
`
}
if(row?.status_order === "Lunas"){
buttons += `
<button class="btn btn-sm btn-warning text-dark" onclick="approveProgress('${row.order_id}')">
<i class="fa fa-utensils me-1"></i>
</button>
`
}
return `
<div class="d-flex space-x">
${buttons}
</div>
`;
},
hozAlign: "center",
headerSort: false
}
},
{
title: "No.Order",
field:'no_order'
field:'no_order',
sortable: true,
},
{
title: "Pemesan",
field:'nama_pemesan',
},
{
title: "Kategori Customer",
field: 'jenis_customer'
},
{
title: "Total Harga Pesanan",
field:'total_harga',
formatter: function(value, row){
return 'Rp ' + parseInt(row.total_harga).toLocaleString('id-ID')
}
},
{
{
title: "Status Pembayaran",
field: 'status_order',
sortable: true,
formatter: function(value, row) {
const status = value;
let badgeClass = 'bg-secondary';
@ -78,12 +76,36 @@
badgeClass = 'bg-primary';
} else if (status === "Lunas" || status === "Sudah Bayar") {
badgeClass = 'bg-success';
} else if(status === "Dibatalkan"){
badgeClass = 'bg-danger';
}
return `<span class="badge ${badgeClass} px-3 py-1">${status}</span>`;
return `
<span class="badge ${badgeClass} px-3 py-1">${status}</span>
${status === 'Dibatalkan' && row.note_dibatalkan ? `
<div class="text-danger small mt-1">
<i class="fa fa-info-circle"></i> ${row.note_dibatalkan}
</div>
` : ''}
`;
}
},
{
title: "Pemesan",
field:'nama_pemesan',
sortable: true,
},
{
title: "Kategori Customer",
field: 'jenis_customer',
sortable: true,
},
{
title: "Total Harga Pesanan",
field:'total_harga',
formatter: function(value, row){
return 'Rp ' + parseInt(row.total_harga).toLocaleString('id-ID')
}
}
],
});

View File

@ -42,6 +42,8 @@
<!-- fontawosome CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Helpers -->
<script src="{{ ver('/assets/vendor/js/helpers.js') }}"></script>
@ -53,7 +55,7 @@
{{-- Bootstrap --}}
<script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.24.1/dist/bootstrap-table.min.js"></script>
{{-- Swal alert --}}
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
{{-- Toast js --}}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>

View File

@ -28,20 +28,20 @@
<li class="menu-header small text-uppercase">
<span class="menu-header-text">Master Data</span>
</li>
<li class="menu-item {{ Request::is('klasifikasi-menu') ? 'active' : '' }}">
<a href="/klasifikasi-menu" class="menu-link">
<li class="menu-item {{ Request::is('dashboard/klasifikasi-menu') ? 'active' : '' }}">
<a href="/dashboard/klasifikasi-menu" class="menu-link">
<i class="menu-icon tf-icons bx bx-dock-top"></i>
<div data-i18n="Account Settings">Klasifikasi Menu</div>
</a>
</li>
<li class="menu-item {{ Request::is('menu') ? 'active' : '' }}">
<a href="/menu" class="menu-link">
<li class="menu-item {{ Request::is('dashboard/menu') ? 'active' : '' }}">
<a href="/dashboard/menu" class="menu-link">
<i class="menu-icon tf-icons bx bx-dock-top"></i>
<div data-i18n="Account Settings">Master Menu</div>
</a>
</li>
<li class="menu-item {{ Request::is('paket-menu') ? 'active' : '' }}">
<a href="/paket-menu" class="menu-link">
<li class="menu-item {{ Request::is('dashboard/paket-menu') ? 'active' : '' }}">
<a href="/dashboard/paket-menu" class="menu-link">
<i class="menu-icon tf-icons bx bx-dock-top"></i>
<div data-i18n="Authentications">Master Paket Menu</div>
</a>
@ -49,7 +49,7 @@
<!-- Components -->
<li class="menu-header small text-uppercase"><span class="menu-header-text">Order</span></li>
<!-- Cards -->
<li class="menu-item">
<li class="menu-item {{ Request::is('dashboard/pending') ? 'active' : '' }}">
<a href="/dashboard/pending" class="menu-link">
<i class="menu-icon tf-icons bx bx-collection"></i>
<div data-i18n="Basic">Pesanan Pending</div>

View File

@ -18,6 +18,9 @@
</div>
</div>
@include('dashboard.pesanan.pending.modal.action')
<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>
@endsection

View File

@ -0,0 +1,36 @@
<!-- Modal -->
<div class="modal fade" id="modalActionOrder" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi <strong id="confirmActionOrder"></strong></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form method="POST" id="formActionOrder">
@csrf
@method('put')
<div class="modal-body ">
<div class="text-center">
<img src="" id="imageConfirmActionOrder" class="img-fluid rounded shadow-sm mb-3 d-none" style="max-height: 380px; width: auto;">
<span id="tidak_ada_bukti_pembayaran"></span>
</div>
<div id="note_dibatalkan">
<label>Catatan</label>
<textarea name="note_dibatalkan" id="textarea_note_dibatalkan" class="form-control" style="resize:none; overflow:hidden;"></textarea>
</div>
</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>
</div>
</div>
</div>

View File

@ -18,12 +18,12 @@ Route::post('/login', [AuthController::class, 'authanticate']);
Route::resource('/dashboard/menu', MenuController::class);
Route::group(['middleware' => ['auth']], function(){
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::group(['prefix' => 'dashboard'], function(){
Route::get('/', [DashboardController::class, 'index']);
Route::resource('/klasifikasi-menu', KlasifikasiMenuController::class);
Route::get('/pending', [PesananController::class, 'index']);
Route::get('datatable/pending', [PesananController::class, 'getDataPending']);
Route::put('/pending/action/{order_id}', [PesananController::class, 'actionOrder']);
});
Route::post('/logout', [AuthController::class, 'logout']);
});