partial update create mutations workflow

This commit is contained in:
2025-06-12 15:10:51 +07:00
parent a5e1348436
commit 1a01efb1b5
33 changed files with 560 additions and 12994 deletions

View File

@@ -1,5 +1,6 @@
$(document).ready(function () {
let productIndex = 1;
let originalProductOptions = ""; // Store original product options
// Initialize Select2
$(".select2").select2({
@@ -7,6 +8,12 @@ $(document).ready(function () {
allowClear: true,
});
// Store original product options on page load
const firstSelect = $(".product-select").first();
if (firstSelect.length > 0) {
originalProductOptions = firstSelect.html();
}
// Prevent same dealer selection
$("#from_dealer_id, #to_dealer_id").on("change", function () {
const fromDealerId = $("#from_dealer_id").val();
@@ -26,12 +33,12 @@ $(document).ready(function () {
const newRow = createProductRow(productIndex);
$("#products-tbody").append(newRow);
// Initialize Select2 for new row
// Initialize Select2 for new row after it's added to DOM
const newSelect = $(
`#products-tbody tr[data-index="${productIndex}"] .product-select`
);
newSelect.select2({
placeholder: "Pilih Produk...",
placeholder: "Pilih...",
allowClear: true,
});
@@ -100,18 +107,14 @@ $(document).ready(function () {
});
function createProductRow(index) {
// Get product options from the existing select
const existingSelect = $(".product-select").first();
const productOptions = existingSelect.html();
return `
<tr class="product-row" data-index="${index}">
<td>
<select name="products[${index}][product_id]" class="form-control select2 product-select" required>
${productOptions}
<select name="products[${index}][product_id]" class="form-control product-select" required>
${originalProductOptions}
</select>
</td>
<td>
<td class="text-center">
<span class="available-stock text-muted">-</span>
</td>
<td>
@@ -123,12 +126,7 @@ $(document).ready(function () {
placeholder="0"
required>
</td>
<td>
<input type="text"
name="products[${index}][notes]"
class="form-control"
placeholder="Catatan produk (opsional)">
</td>
<td>
<button type="button" class="btn btn-danger btn-sm remove-product">
<i class="la la-trash"></i>
@@ -152,9 +150,6 @@ $(document).ready(function () {
$(this)
.find('input[name*="quantity_requested"]')
.attr("name", `products[${index}][quantity_requested]`);
$(this)
.find('input[name*="notes"]')
.attr("name", `products[${index}][notes]`);
});
productIndex = $(".product-row").length;
}

View File

@@ -28,12 +28,12 @@ $(document).ready(function () {
{
data: "from_dealer",
name: "fromDealer.name",
width: "15%",
width: "13%",
},
{
data: "to_dealer",
name: "toDealer.name",
width: "15%",
width: "13%",
},
{
data: "requested_by",
@@ -57,117 +57,17 @@ $(document).ready(function () {
name: "action",
orderable: false,
searchable: false,
width: "15%",
width: "20%",
className: "text-center",
},
],
order: [[2, "desc"]], // Order by created_at desc
pageLength: 10,
responsive: true,
language: {
processing: "Memuat data...",
lengthMenu: "Tampilkan _MENU_ data per halaman",
zeroRecords: "Data tidak ditemukan",
info: "Menampilkan _START_ sampai _END_ dari _TOTAL_ data",
infoEmpty: "Menampilkan 0 sampai 0 dari 0 data",
infoFiltered: "(difilter dari _MAX_ total data)",
},
});
// Handle Receive Button Click
$(document).on("click", ".btn-receive", function () {
var mutationId = $(this).data("id");
$("#receiveModal" + mutationId).modal("show");
});
// Handle Approve Button Click
$(document).on("click", ".btn-approve", function () {
var mutationId = $(this).data("id");
// Load mutation details via AJAX
$.ajax({
url: "/warehouse/mutations/" + mutationId + "/details",
type: "GET",
beforeSend: function () {
$("#mutation-details" + mutationId).html(
'<div class="text-center">' +
'<div class="spinner-border" role="status">' +
'<span class="sr-only">Loading...</span>' +
"</div>" +
"<p>Memuat detail produk...</p>" +
"</div>"
);
},
success: function (response) {
var detailsHtml = "<h6>Detail Produk:</h6>";
detailsHtml += '<div class="table-responsive">';
detailsHtml += '<table class="table table-sm">';
detailsHtml += "<thead>";
detailsHtml += "<tr>";
detailsHtml += "<th>Produk</th>";
detailsHtml += "<th>Diminta</th>";
detailsHtml += "<th>Disetujui</th>";
detailsHtml += "<th>Stock Tersedia</th>";
detailsHtml += "</tr>";
detailsHtml += "</thead>";
detailsHtml += "<tbody>";
response.details.forEach(function (detail, index) {
detailsHtml += "<tr>";
detailsHtml += "<td>" + detail.product.name + "</td>";
detailsHtml +=
"<td>" +
parseFloat(detail.quantity_requested).toLocaleString() +
"</td>";
detailsHtml += "<td>";
detailsHtml +=
'<input type="number" name="details[' +
detail.id +
'][quantity_approved]" ';
detailsHtml += 'class="form-control form-control-sm" ';
detailsHtml += 'value="' + detail.quantity_requested + '" ';
detailsHtml +=
'min="0" max="' +
Math.min(
detail.quantity_requested,
detail.available_stock
) +
'" ';
detailsHtml += 'step="0.01" required>';
detailsHtml += "</td>";
detailsHtml +=
"<td>" +
parseFloat(detail.available_stock).toLocaleString() +
"</td>";
detailsHtml += "</tr>";
});
detailsHtml += "</tbody>";
detailsHtml += "</table>";
detailsHtml += "</div>";
$("#mutation-details" + mutationId).html(detailsHtml);
},
error: function () {
$("#mutation-details" + mutationId).html(
'<div class="alert alert-danger">Gagal memuat detail produk</div>'
);
},
});
$("#approveModal" + mutationId).modal("show");
});
// Handle other button clicks
$(document).on("click", ".btn-reject", function () {
var mutationId = $(this).data("id");
$("#rejectModal" + mutationId).modal("show");
});
$(document).on("click", ".btn-complete", function () {
var mutationId = $(this).data("id");
$("#completeModal" + mutationId).modal("show");
});
// Modal event handlers are now handled by Bootstrap 5 data attributes
// No need for manual modal show/hide handlers
// Handle Cancel Button Click with SweetAlert
$(document).on("click", ".btn-cancel", function () {
@@ -240,7 +140,7 @@ $(document).ready(function () {
.html("Memproses...");
});
// Auto-calculate approved quantity based on available stock
// Validate quantity approved in receive modal
$(document).on("input", 'input[name*="quantity_approved"]', function () {
var maxValue = parseFloat($(this).attr("max"));
var currentValue = parseFloat($(this).val());
@@ -250,7 +150,7 @@ $(document).ready(function () {
$(this).addClass("is-invalid");
if (!$(this).siblings(".invalid-feedback").length) {
$(this).after(
'<div class="invalid-feedback">Jumlah melebihi stock yang tersedia</div>'
'<div class="invalid-feedback">Quantity tidak boleh melebihi yang diminta</div>'
);
}
} else {

View File

@@ -1,4 +1,9 @@
$(document).ready(function () {
$(".select2").select2({
placeholder: "Pilih...",
allowClear: true,
});
// Fungsi untuk mengambil data stok
function fetchStockData() {
const dealerId = $("#dealer").val();

View File

@@ -1,29 +1,28 @@
<div class="btn-group btn-group-sm" role="group">
<!-- View Button -->
<a href="{{ route('mutations.show', $row->id) }}"
class="btn btn-sm btn-clean btn-icon btn-icon-md"
title="Lihat Detail">
<i class="la la-eye"></i>
class="btn btn-sm btn-outline-info me-1">
Detail
</a>
@if($row->status->value === 'sent')
<!-- Receive Button (untuk dealer tujuan) -->
@if(auth()->user()->dealer_id == $row->to_dealer_id)
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-receive"
class="btn btn-sm btn-outline-primary btn-receive me-1"
data-id="{{ $row->id }}"
title="Terima Mutasi">
<i class="la la-download text-primary"></i>
data-bs-toggle="modal"
data-bs-target="#receiveModal{{ $row->id }}">
Terima
</button>
@endif
<!-- Cancel Button (untuk pengirim) -->
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-cancel"
data-id="{{ $row->id }}"
title="Batalkan Mutasi">
<i class="la la-ban text-warning"></i>
class="btn btn-sm btn-outline-warning btn-cancel me-1"
data-id="{{ $row->id }}">
Batal
</button>
@endif
@endif
@@ -32,20 +31,22 @@
<!-- Approve Button (untuk pengirim atau admin) -->
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-approve"
class="btn btn-sm btn-outline-success btn-approve me-1"
data-id="{{ $row->id }}"
title="Setujui Mutasi">
<i class="la la-check text-success"></i>
data-bs-toggle="modal"
data-bs-target="#approveModal{{ $row->id }}">
Setujui
</button>
@endif
<!-- Reject Button (untuk pengirim atau admin) -->
@if(auth()->user()->dealer_id == $row->from_dealer_id || auth()->user()->hasRole('admin'))
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-reject"
class="btn btn-sm btn-outline-danger btn-reject me-1"
data-id="{{ $row->id }}"
title="Tolak Mutasi">
<i class="la la-times text-danger"></i>
data-bs-toggle="modal"
data-bs-target="#rejectModal{{ $row->id }}">
Tolak
</button>
@endif
@endif
@@ -54,20 +55,20 @@
<!-- Complete/Receive Button -->
@can('complete-mutation')
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-complete"
class="btn btn-sm btn-outline-primary btn-complete me-1"
data-id="{{ $row->id }}"
title="Terima & Selesaikan Mutasi">
<i class="la la-check-circle text-primary"></i>
data-bs-toggle="modal"
data-bs-target="#completeModal{{ $row->id }}">
Selesaikan
</button>
@endcan
<!-- Cancel Button -->
@can('edit-mutation')
<button type="button"
class="btn btn-sm btn-clean btn-icon btn-icon-md btn-cancel"
data-id="{{ $row->id }}"
title="Batalkan Mutasi">
<i class="la la-ban text-warning"></i>
class="btn btn-sm btn-outline-warning btn-cancel me-1"
data-id="{{ $row->id }}">
Batal
</button>
@endcan
@endif
@@ -75,53 +76,71 @@
@if(in_array($row->status->value, ['pending', 'approved']) && auth()->user()->id === $row->requested_by)
<!-- Edit Button (only for creator and if still pending/approved) -->
<a href="{{ route('mutations.edit', $row->id) }}"
class="btn btn-sm btn-clean btn-icon btn-icon-md"
title="Edit Mutasi">
<i class="la la-edit text-info"></i>
</a>
@endif
@if($row->status->value === 'completed')
<!-- Print Button -->
<a href="{{ route('mutations.print', $row->id) }}"
class="btn btn-sm btn-clean btn-icon btn-icon-md"
target="_blank"
title="Cetak Laporan">
<i class="la la-print text-info"></i>
class="btn btn-sm btn-outline-secondary me-1">
Edit
</a>
@endif
</div>
<!-- Modal untuk Approve -->
<div class="modal fade" id="approveModal{{ $row->id }}" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal fade" id="approveModal{{ $row->id }}" tabindex="-1" aria-labelledby="approveModalLabel{{ $row->id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Setujui Mutasi</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
<h5 class="modal-title" id="approveModalLabel{{ $row->id }}">Setujui Mutasi</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('mutations.approve', $row->id) }}" method="POST" class="approve-form">
@csrf
<div class="modal-body">
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Anda akan menyetujui mutasi yang telah diterima oleh <strong>{{ $row->toDealer->name }}</strong>.
</div>
<div class="form-group">
<label>Catatan Persetujuan</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Opsional: tambahkan catatan..."></textarea>
</div>
<!-- Detail produk akan dimuat via AJAX -->
<div id="mutation-details{{ $row->id }}">
<div class="text-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
<p>Memuat detail produk...</p>
</div>
<h6>Detail Produk yang Diterima:</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Produk</th>
<th width="20%" class="text-center">Qty Diminta</th>
<th width="20%" class="text-center">Qty Diterima</th>
<th width="30%">Catatan</th>
</tr>
</thead>
<tbody>
@foreach($row->mutationDetails as $detail)
<tr>
<td>{{ $detail->product->name }}</td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center">
<span class="font-weight-bold {{ $detail->quantity_approved < $detail->quantity_requested ? 'text-warning' : 'text-success' }}">
{{ number_format($detail->quantity_approved, 2) }}
</span>
@if($detail->quantity_approved < $detail->quantity_requested)
<small class="text-muted d-block">
(Kurang {{ number_format($detail->quantity_requested - $detail->quantity_approved, 2) }})
</small>
@endif
</td>
<td>
<small class="text-muted">{{ $detail->notes ?: '-' }}</small>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<p class="text-muted">Setelah disetujui, stock akan siap untuk dipindahkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-success">Setujui Mutasi</button>
</div>
</form>
@@ -130,14 +149,12 @@
</div>
<!-- Modal untuk Reject -->
<div class="modal fade" id="rejectModal{{ $row->id }}" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal fade" id="rejectModal{{ $row->id }}" tabindex="-1" aria-labelledby="rejectModalLabel{{ $row->id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Tolak Mutasi</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
<h5 class="modal-title" id="rejectModalLabel{{ $row->id }}">Tolak Mutasi</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('mutations.reject', $row->id) }}" method="POST">
@csrf
@@ -151,7 +168,7 @@
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-danger">Tolak Mutasi</button>
</div>
</form>
@@ -160,14 +177,12 @@
</div>
<!-- Modal untuk Receive -->
<div class="modal fade" id="receiveModal{{ $row->id }}" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal fade" id="receiveModal{{ $row->id }}" tabindex="-1" aria-labelledby="receiveModalLabel{{ $row->id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Terima Mutasi</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
<h5 class="modal-title" id="receiveModalLabel{{ $row->id }}">Terima Mutasi</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('mutations.receive', $row->id) }}" method="POST">
@csrf
@@ -175,11 +190,55 @@
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Anda akan menerima mutasi dari <strong>{{ $row->fromDealer->name }}</strong>.
</div>
<p>Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
<div class="form-group">
<label>Catatan Penerimaan</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Catatan kondisi barang saat diterima (opsional)"></textarea>
</div>
<h6>Detail Produk yang Diterima:</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Produk</th>
<th width="15%" class="text-center">Qty Diminta</th>
<th width="15%" class="text-center">Qty Diterima</th>
<th width="35%">Catatan Produk</th>
</tr>
</thead>
<tbody>
@foreach($row->mutationDetails as $index => $detail)
<tr>
<td>{{ $detail->product->name }}</td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center">
<input type="number"
name="products[{{ $detail->id }}][quantity_approved]"
class="form-control form-control-sm text-center"
value="{{ $detail->quantity_requested }}"
min="0"
max="{{ $detail->quantity_requested }}"
step="0.01"
required>
</td>
<td>
<input type="text"
name="products[{{ $detail->id }}][notes]"
class="form-control form-control-sm"
placeholder="Catatan kondisi produk saat diterima">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Terima</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Terima Mutasi</button>
</div>
</form>
</div>
@@ -187,14 +246,12 @@
</div>
<!-- Modal untuk Complete -->
<div class="modal fade" id="completeModal{{ $row->id }}" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal fade" id="completeModal{{ $row->id }}" tabindex="-1" aria-labelledby="completeModalLabel{{ $row->id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Selesaikan Mutasi</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
<h5 class="modal-title" id="completeModalLabel{{ $row->id }}">Selesaikan Mutasi</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{{ route('mutations.complete', $row->id) }}" method="POST">
@csrf
@@ -205,7 +262,7 @@
<p>Apakah Anda yakin ingin menyelesaikan mutasi ini? Tindakan ini tidak dapat dibatalkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Selesaikan</button>
</div>
</form>

View File

@@ -65,11 +65,6 @@
</div>
</div>
<div class="form-group">
<label for="notes">Catatan</label>
<textarea name="notes" id="notes" class="form-control" rows="3" placeholder="Catatan untuk mutasi ini (opsional)">{{ old('notes') }}</textarea>
</div>
<div class="kt-separator kt-separator--border-dashed kt-separator--space-lg"></div>
<div class="form-group">
@@ -84,24 +79,23 @@
<table class="table table-bordered" id="products-table">
<thead>
<tr>
<th width="35%">Produk</th>
<th width="15%">Stock Tersedia</th>
<th width="15%">Quantity</th>
<th width="25%">Catatan</th>
<th width="10%">Aksi</th>
<th width="40%">Produk</th>
<th width="20%">Stock Tersedia</th>
<th width="25%">Quantity</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody id="products-tbody">
<tr class="product-row" data-index="0">
<td>
<select name="products[0][product_id]" class="form-control select2 product-select" required>
<select name="products[0][product_id]" class="form-control product-select select2" required>
<option value="">Pilih Produk</option>
@foreach($products as $product)
<option value="{{ $product->id }}">{{ $product->name }}</option>
@endforeach
</select>
</td>
<td>
<td class="text-center">
<span class="available-stock text-muted">-</span>
</td>
<td>
@@ -113,12 +107,7 @@
placeholder="0"
required>
</td>
<td>
<input type="text"
name="products[0][notes]"
class="form-control"
placeholder="Catatan produk (opsional)">
</td>
<td>
<button type="button" class="btn btn-danger btn-sm remove-product" disabled>
<i class="la la-trash"></i>
@@ -133,19 +122,18 @@
<div class="alert alert-info">
<i class="la la-info-circle"></i>
<strong>Informasi:</strong>
Mutasi akan dibuat dengan status "Menunggu Persetujuan" dan memerlukan approval sebelum stock dipindahkan.
Mutasi akan dikirim ke dealer tujuan. Catatan dapat ditambahkan saat dealer tujuan menerima mutasi.
</div>
</div>
<div class="kt-portlet__foot">
<div class="kt-form__actions kt-form__actions--right">
<button type="submit" class="btn btn-primary" id="submit-btn">
Simpan Mutasi
</button>
<button type="button" class="btn btn-secondary" onclick="window.history.back()">
Batal
</button>
<button type="submit" class="btn btn-primary" id="submit-btn">
<i class="la la-save"></i>
Simpan Mutasi
</button>
</div>
</div>
</form>

View File

@@ -15,8 +15,7 @@
<div class="kt-portlet__head-wrapper">
<div class="kt-portlet__head-actions">
<a href="{{ route('mutations.create') }}" class="btn btn-bold btn-label-brand btn--sm">
<i class="la la-plus"></i>
Tambah Mutasi
Tambah
</a>
</div>
</div>

View File

@@ -102,38 +102,43 @@
</div>
<div class="kt-portlet__body">
<div class="table-responsive">
<table class="table table-bordered table-hover">
<table class="table table-bordered table-hover mutation-detail-table">
<thead>
<tr>
<th>No.</th>
<th>Nama Produk</th>
<th>Jumlah Diminta</th>
<th>Jumlah Disetujui</th>
<th>Status Approval</th>
<th>Catatan</th>
<th width="5%">No.</th>
<th width="25%">Nama Produk</th>
<th width="15%" class="text-center">Jumlah Diminta</th>
<th width="15%" class="text-center">Jumlah Disetujui</th>
<th width="15%" class="text-center">Status Approval</th>
<th width="25%">Catatan</th>
</tr>
</thead>
<tbody>
@foreach($mutation->mutationDetails as $index => $detail)
<tr>
<td>{{ $index + 1 }}</td>
<td class="text-center">{{ $index + 1 }}</td>
<td>{{ $detail->product->name }}</td>
<td>{{ number_format($detail->quantity_requested, 2) }}</td>
<td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center">
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
{{ number_format($detail->quantity_approved ?? 0, 2) }}
@else
<span class="text-muted">Belum ditentukan</span>
@endif
</td>
<td>
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
<span class="kt-badge kt-badge--{{ $detail->approval_status_color }} kt-badge--pill">
{{ $detail->approval_status }}
</span>
@else
<span class="kt-badge kt-badge--secondary kt-badge--pill">Menunggu</span>
@endif
<td class="text-center">
@php
$textColorClass = match($detail->approval_status_color) {
'success' => 'text-success',
'warning' => 'text-warning',
'danger' => 'text-danger',
'info' => 'text-info',
default => 'text-muted'
};
@endphp
<span class="font-weight-bold {{ $textColorClass }}">
{{ $detail->approval_status }}
</span>
</td>
<td>{{ $detail->notes ?? '-' }}</td>
</tr>
@@ -141,9 +146,9 @@
</tbody>
<tfoot>
<tr class="kt-font-bold">
<td colspan="2">Total</td>
<td>{{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }}</td>
<td>
<td colspan="2" class="text-right">Total</td>
<td class="text-center">{{ number_format($mutation->mutationDetails->sum('quantity_requested'), 2) }}</td>
<td class="text-center">
@if($mutation->status->value === 'received' || $mutation->status->value === 'approved' || $mutation->status->value === 'completed')
{{ number_format($mutation->mutationDetails->sum('quantity_approved'), 2) }}
@else
@@ -165,8 +170,7 @@
<div class="col-lg-12">
@if($mutation->status->value === 'sent' && auth()->user()->dealer_id == $mutation->to_dealer_id)
<!-- Receive Button for destination dealer -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#receiveModal">
<i class="la la-download"></i>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#receiveModal{{ $mutation->id }}">
Terima Mutasi
</button>
@endif
@@ -174,12 +178,10 @@
@if($mutation->status->value === 'received' && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
<!-- Approve Button for sender or admin -->
<button type="button" class="btn btn-success btn-approve" data-id="{{ $mutation->id }}">
<i class="la la-check"></i>
Setujui Mutasi
</button>
<!-- Reject Button for sender or admin -->
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#rejectModal">
<i class="la la-times"></i>
Tolak Mutasi
</button>
@endif
@@ -187,7 +189,6 @@
@if($mutation->status->value === 'approved')
<!-- Complete Button -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#completeModal">
<i class="la la-check-circle"></i>
Selesaikan Mutasi
</button>
@endif
@@ -195,18 +196,11 @@
@if($mutation->canBeCancelled() && (auth()->user()->dealer_id == $mutation->from_dealer_id || auth()->user()->hasRole('admin')))
<!-- Cancel Button -->
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#cancelModal">
<i class="la la-ban"></i>
Batalkan Mutasi
</button>
@endif
@if($mutation->status->value === 'completed')
<!-- Print Button -->
<a href="{{ route('mutations.print', $mutation->id) }}" class="btn btn-info" target="_blank">
<i class="la la-print"></i>
Cetak Laporan
</a>
@endif
</div>
</div>
</div>
@@ -217,8 +211,8 @@
<!-- Modals -->
@if($mutation->status->value === 'sent' && auth()->user()->dealer_id == $mutation->to_dealer_id)
<!-- Receive Modal -->
<div class="modal fade" id="receiveModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal fade" id="receiveModal{{ $mutation->id }}" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Terima Mutasi</h5>
@@ -232,11 +226,55 @@
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Anda akan menerima mutasi dari <strong>{{ $mutation->fromDealer->name }}</strong>.
</div>
<p>Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
<div class="form-group">
<label>Catatan Penerimaan</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Catatan kondisi barang saat diterima (opsional)"></textarea>
</div>
<h6>Detail Produk yang Diterima:</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Produk</th>
<th width="15%" class="text-center">Qty Diminta</th>
<th width="15%" class="text-center">Qty Diterima</th>
<th width="35%">Catatan Produk</th>
</tr>
</thead>
<tbody>
@foreach($mutation->mutationDetails as $index => $detail)
<tr>
<td>{{ $detail->product->name }}</td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center">
<input type="number"
name="products[{{ $detail->id }}][quantity_approved]"
class="form-control form-control-sm text-center"
value="{{ $detail->quantity_requested }}"
min="0"
max="{{ $detail->quantity_requested }}"
step="0.01"
required>
</td>
<td>
<input type="text"
name="products[{{ $detail->id }}][notes]"
class="form-control form-control-sm"
placeholder="Catatan kondisi produk saat diterima">
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<p class="text-muted">Setelah menerima, mutasi akan menunggu persetujuan dari pengirim sebelum stock dipindahkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-primary">Ya, Terima</button>
<button type="submit" class="btn btn-primary">Ya, Terima Mutasi</button>
</div>
</form>
</div>
@@ -258,20 +296,51 @@
<form action="{{ route('mutations.approve', $mutation->id) }}" method="POST" class="approve-form">
@csrf
<div class="modal-body">
<div class="alert alert-info">
<strong>Konfirmasi!</strong> Anda akan menyetujui mutasi yang telah diterima oleh <strong>{{ $mutation->toDealer->name }}</strong>.
</div>
<div class="form-group">
<label>Catatan Persetujuan</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Opsional: tambahkan catatan..."></textarea>
</div>
<!-- Detail produk akan dimuat via AJAX -->
<div id="mutation-details{{ $mutation->id }}">
<div class="text-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
<p>Memuat detail produk...</p>
</div>
<h6>Detail Produk yang Diterima:</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Produk</th>
<th width="20%" class="text-center">Qty Diminta</th>
<th width="20%" class="text-center">Qty Diterima</th>
<th width="30%">Catatan</th>
</tr>
</thead>
<tbody>
@foreach($mutation->mutationDetails as $detail)
<tr>
<td>{{ $detail->product->name }}</td>
<td class="text-center">{{ number_format($detail->quantity_requested, 2) }}</td>
<td class="text-center">
<span class="font-weight-bold {{ $detail->quantity_approved < $detail->quantity_requested ? 'text-warning' : 'text-success' }}">
{{ number_format($detail->quantity_approved, 2) }}
</span>
@if($detail->quantity_approved < $detail->quantity_requested)
<small class="text-muted d-block">
(Kurang {{ number_format($detail->quantity_requested - $detail->quantity_approved, 2) }})
</small>
@endif
</td>
<td>
<small class="text-muted">{{ $detail->notes ?: '-' }}</small>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<p class="text-muted">Setelah disetujui, stock akan siap untuk dipindahkan.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
@@ -372,71 +441,41 @@
@endif
@endsection
@section('styles')
<style>
/* Custom CSS for mutation detail table alignment */
.mutation-detail-table {
table-layout: fixed;
}
.mutation-detail-table th,
.mutation-detail-table td {
vertical-align: middle;
}
.mutation-detail-table .text-center {
text-align: center !important;
}
/* Ensure proper alignment in approval modal */
.approve-form .form-control.text-center {
text-align: center;
}
</style>
@endsection
@section('javascripts')
<script>
$(document).ready(function() {
// Handle Approve Button Click
$(document).on('click', '.btn-approve', function() {
var mutationId = $(this).data('id');
// Load mutation details via AJAX
$.ajax({
url: '/warehouse/mutations/' + mutationId + '/details',
type: 'GET',
beforeSend: function() {
$('#mutation-details' + mutationId).html(
'<div class="text-center">' +
'<div class="spinner-border" role="status">' +
'<span class="sr-only">Loading...</span>' +
'</div>' +
'<p>Memuat detail produk...</p>' +
'</div>'
);
},
success: function(response) {
var detailsHtml = '<h6>Detail Produk:</h6>';
detailsHtml += '<div class="table-responsive">';
detailsHtml += '<table class="table table-sm">';
detailsHtml += '<thead>';
detailsHtml += '<tr>';
detailsHtml += '<th>Produk</th>';
detailsHtml += '<th>Diminta</th>';
detailsHtml += '<th>Disetujui</th>';
detailsHtml += '<th>Stock Tersedia</th>';
detailsHtml += '</tr>';
detailsHtml += '</thead>';
detailsHtml += '<tbody>';
response.details.forEach(function(detail, index) {
detailsHtml += '<tr>';
detailsHtml += '<td>' + detail.product.name + '</td>';
detailsHtml += '<td>' + parseFloat(detail.quantity_requested).toLocaleString() + '</td>';
detailsHtml += '<td>';
detailsHtml += '<input type="number" name="details[' + detail.id + '][quantity_approved]" ';
detailsHtml += 'class="form-control form-control-sm" ';
detailsHtml += 'value="' + detail.quantity_requested + '" ';
detailsHtml += 'min="0" max="' + Math.min(detail.quantity_requested, detail.available_stock) + '" ';
detailsHtml += 'step="0.01" required>';
detailsHtml += '</td>';
detailsHtml += '<td>' + parseFloat(detail.available_stock).toLocaleString() + '</td>';
detailsHtml += '</tr>';
});
detailsHtml += '</tbody>';
detailsHtml += '</table>';
detailsHtml += '</div>';
$('#mutation-details' + mutationId).html(detailsHtml);
},
error: function() {
$('#mutation-details' + mutationId).html('<div class="alert alert-danger">Gagal memuat detail produk</div>');
}
});
$('#approveModal' + mutationId).modal('show');
});
// Auto-calculate approved quantity based on available stock
// Validate quantity approved in receive modal
$(document).on('input', 'input[name*="quantity_approved"]', function() {
var maxValue = parseFloat($(this).attr('max'));
var currentValue = parseFloat($(this).val());
@@ -445,7 +484,7 @@ $(document).ready(function() {
$(this).val(maxValue);
$(this).addClass('is-invalid');
if (!$(this).siblings('.invalid-feedback').length) {
$(this).after('<div class="invalid-feedback">Jumlah melebihi stock yang tersedia</div>');
$(this).after('<div class="invalid-feedback">Quantity tidak boleh melebihi yang diminta</div>');
}
} else {
$(this).removeClass('is-invalid');

View File

@@ -32,7 +32,7 @@
$oldDealer = old('dealer');
$dealerValue = is_array($oldDealer) ? '' : $oldDealer;
@endphp
<select name="dealer" id="dealer" class="form-control @error('dealer') is-invalid @enderror" required>
<select name="dealer" id="dealer" class="form-control select2 @error('dealer') is-invalid @enderror" required>
<option value="">Pilih Dealer</option>
@foreach($dealers as $dealer)
<option value="{{ $dealer->id }}" {{ $dealerValue == $dealer->id ? 'selected' : '' }}>
@@ -202,5 +202,5 @@
@endsection
@section('javascripts')
<script src="{{ asset('js/warehouse_management/opnames/create.js') }}"></script>
<script src="{{ mix('js/warehouse_management/opnames/create.js') }}"></script>
@endsection