partial update create mutations

This commit is contained in:
2025-06-12 00:33:59 +07:00
parent 0b211915f1
commit a5e1348436
32 changed files with 2883 additions and 548 deletions

View File

@@ -0,0 +1,262 @@
$(document).ready(function () {
let productIndex = 1;
// Initialize Select2
$(".select2").select2({
placeholder: "Pilih...",
allowClear: true,
});
// Prevent same dealer selection
$("#from_dealer_id, #to_dealer_id").on("change", function () {
const fromDealerId = $("#from_dealer_id").val();
const toDealerId = $("#to_dealer_id").val();
if (fromDealerId && toDealerId && fromDealerId === toDealerId) {
$(this).val("").trigger("change");
alert("Dealer asal dan tujuan tidak boleh sama!");
}
// Update available stock when dealer changes
updateAllAvailableStock();
});
// Add new product row
$("#add-product").on("click", function () {
const newRow = createProductRow(productIndex);
$("#products-tbody").append(newRow);
// Initialize Select2 for new row
const newSelect = $(
`#products-tbody tr[data-index="${productIndex}"] .product-select`
);
newSelect.select2({
placeholder: "Pilih Produk...",
allowClear: true,
});
productIndex++;
updateRemoveButtons();
});
// Remove product row
$(document).on("click", ".remove-product", function () {
$(this).closest("tr").remove();
updateRemoveButtons();
reindexRows();
});
// Handle product selection change
$(document).on("change", ".product-select", function () {
const row = $(this).closest("tr");
const productId = $(this).val();
const fromDealerId = $("#from_dealer_id").val();
if (productId && fromDealerId) {
getAvailableStock(productId, fromDealerId, row);
} else {
row.find(".available-stock").text("-");
row.find(".quantity-input").attr("max", "");
}
});
// Validate quantity input
$(document).on("input", ".quantity-input", function () {
const maxValue = parseFloat($(this).attr("max"));
const currentValue = parseFloat($(this).val());
if (maxValue && currentValue > maxValue) {
$(this).val(maxValue);
$(this).addClass("is-invalid");
if (!$(this).siblings(".invalid-feedback").length) {
$(this).after(
'<div class="invalid-feedback">Quantity melebihi stock yang tersedia</div>'
);
}
} else {
$(this).removeClass("is-invalid");
$(this).siblings(".invalid-feedback").remove();
}
});
// Form submission
$("#mutation-form").on("submit", function (e) {
e.preventDefault();
if (!validateForm()) {
return false;
}
const submitBtn = $("#submit-btn");
const originalText = submitBtn.html();
submitBtn
.prop("disabled", true)
.html('<i class="la la-spinner la-spin"></i> Menyimpan...');
// Submit form
this.submit();
});
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>
</td>
<td>
<span class="available-stock text-muted">-</span>
</td>
<td>
<input type="number"
name="products[${index}][quantity_requested]"
class="form-control quantity-input"
min="0.01"
step="0.01"
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>
</button>
</td>
</tr>
`;
}
function updateRemoveButtons() {
const rows = $(".product-row");
$(".remove-product").prop("disabled", rows.length <= 1);
}
function reindexRows() {
$(".product-row").each(function (index) {
$(this).attr("data-index", index);
$(this)
.find('select[name*="product_id"]')
.attr("name", `products[${index}][product_id]`);
$(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;
}
function getAvailableStock(productId, dealerId, row) {
$.ajax({
url: "/warehouse/mutations/get-product-stock",
method: "GET",
data: {
product_id: productId,
dealer_id: dealerId,
},
beforeSend: function () {
row.find(".available-stock").html(
'<i class="la la-spinner la-spin"></i>'
);
},
success: function (response) {
const stock = parseFloat(response.current_stock);
row.find(".available-stock").text(stock.toLocaleString());
row.find(".quantity-input").attr("max", stock);
// Set max value message
if (stock <= 0) {
row.find(".available-stock")
.addClass("text-danger")
.removeClass("text-muted");
row.find(".quantity-input").attr("readonly", true).val("");
} else {
row.find(".available-stock")
.removeClass("text-danger")
.addClass("text-muted");
row.find(".quantity-input").attr("readonly", false);
}
},
error: function () {
row.find(".available-stock")
.text("Error")
.addClass("text-danger");
},
});
}
function updateAllAvailableStock() {
const fromDealerId = $("#from_dealer_id").val();
$(".product-row").each(function () {
const row = $(this);
const productId = row.find(".product-select").val();
if (productId && fromDealerId) {
getAvailableStock(productId, fromDealerId, row);
} else {
row.find(".available-stock").text("-");
row.find(".quantity-input").attr("max", "");
}
});
}
function validateForm() {
let isValid = true;
const fromDealerId = $("#from_dealer_id").val();
const toDealerId = $("#to_dealer_id").val();
// Check dealers
if (!fromDealerId) {
alert("Pilih dealer asal");
return false;
}
if (!toDealerId) {
alert("Pilih dealer tujuan");
return false;
}
if (fromDealerId === toDealerId) {
alert("Dealer asal dan tujuan tidak boleh sama");
return false;
}
// Check products
const productRows = $(".product-row");
if (productRows.length === 0) {
alert("Tambahkan minimal satu produk");
return false;
}
let hasValidProduct = false;
productRows.each(function () {
const productId = $(this).find(".product-select").val();
const quantity = $(this).find(".quantity-input").val();
if (productId && quantity && parseFloat(quantity) > 0) {
hasValidProduct = true;
}
});
if (!hasValidProduct) {
alert("Pilih minimal satu produk dengan quantity yang valid");
return false;
}
return isValid;
}
});

View File

@@ -0,0 +1,261 @@
$(document).ready(function () {
// Initialize DataTable
var table = $("#mutations-table").DataTable({
processing: true,
serverSide: true,
ajax: {
url: $("#mutations-table").data("url"),
type: "GET",
},
columns: [
{
data: "DT_RowIndex",
name: "DT_RowIndex",
orderable: false,
searchable: false,
width: "5%",
},
{
data: "mutation_number",
name: "mutation_number",
width: "12%",
},
{
data: "created_at",
name: "created_at",
width: "12%",
},
{
data: "from_dealer",
name: "fromDealer.name",
width: "15%",
},
{
data: "to_dealer",
name: "toDealer.name",
width: "15%",
},
{
data: "requested_by",
name: "requestedBy.name",
width: "12%",
},
{
data: "total_items",
name: "total_items",
width: "8%",
className: "text-center",
},
{
data: "status",
name: "status",
width: "12%",
className: "text-center",
},
{
data: "action",
name: "action",
orderable: false,
searchable: false,
width: "15%",
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");
});
// Handle Cancel Button Click with SweetAlert
$(document).on("click", ".btn-cancel", function () {
var mutationId = $(this).data("id");
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Batalkan Mutasi?",
text: "Apakah Anda yakin ingin membatalkan mutasi ini?",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#3085d6",
confirmButtonText: "Ya, Batalkan",
cancelButtonText: "Batal",
}).then((result) => {
if (result.isConfirmed) {
cancelMutation(mutationId);
}
});
} else {
if (confirm("Apakah Anda yakin ingin membatalkan mutasi ini?")) {
cancelMutation(mutationId);
}
}
});
function cancelMutation(mutationId) {
$.ajax({
url: "/warehouse/mutations/" + mutationId + "/cancel",
type: "POST",
data: {
_token: $('meta[name="csrf-token"]').attr("content"),
},
success: function (response) {
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Berhasil!",
text: "Mutasi berhasil dibatalkan",
icon: "success",
timer: 2000,
showConfirmButton: false,
});
} else {
alert("Mutasi berhasil dibatalkan");
}
table.ajax.reload();
},
error: function (xhr) {
var errorMsg =
xhr.responseJSON?.message || "Gagal membatalkan mutasi";
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Error!",
text: errorMsg,
icon: "error",
});
} else {
alert("Error: " + errorMsg);
}
},
});
}
// Handle form submissions with loading state
$(document).on("submit", ".approve-form", function () {
$(this)
.find('button[type="submit"]')
.prop("disabled", true)
.html("Memproses...");
});
// Auto-calculate approved quantity based on available stock
$(document).on("input", 'input[name*="quantity_approved"]', function () {
var maxValue = parseFloat($(this).attr("max"));
var currentValue = parseFloat($(this).val());
if (maxValue && currentValue > maxValue) {
$(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>'
);
}
} else {
$(this).removeClass("is-invalid");
$(this).siblings(".invalid-feedback").remove();
}
});
});