partial update transaction work with stock product

This commit is contained in:
2025-06-24 19:42:19 +07:00
parent 33502e905d
commit c3233ea6b2
20 changed files with 3432 additions and 239 deletions

View File

@@ -0,0 +1,498 @@
// Global variables
let workId,
indexUrl,
storeUrl,
stockPredictionUrl,
csrfToken,
table,
baseUrl,
showUrlTemplate,
updateUrlTemplate,
destroyUrlTemplate;
$(document).ready(function () {
// Get URLs from hidden inputs
workId = $('input[name="work_id"]').val();
indexUrl = $('input[name="index_url"]').val();
storeUrl = $('input[name="store_url"]').val();
stockPredictionUrl = $('input[name="stock_prediction_url"]').val();
csrfToken = $('input[name="csrf_token"]').val();
baseUrl = $('input[name="base_url"]').val();
showUrlTemplate = $('input[name="show_url_template"]').val();
updateUrlTemplate = $('input[name="update_url_template"]').val();
destroyUrlTemplate = $('input[name="destroy_url_template"]').val();
console.log("Initialized with:", {
workId,
indexUrl,
storeUrl,
stockPredictionUrl,
csrfToken: csrfToken ? "Set" : "Not set",
baseUrl,
showUrlTemplate,
updateUrlTemplate,
destroyUrlTemplate,
});
// Set up CSRF token for all AJAX requests
$.ajaxSetup({
headers: {
"X-CSRF-TOKEN": csrfToken,
},
});
// Initialize Select2
$("#product_id").select2({
placeholder: "-- Pilih Produk --",
allowClear: true,
width: "100%",
dropdownParent: $("#workProductModal"),
language: {
noResults: function () {
return "Tidak ada hasil yang ditemukan";
},
searching: function () {
return "Mencari...";
},
},
});
table = $("#workProductsTable").DataTable({
processing: true,
serverSide: true,
ajax: {
url: indexUrl,
data: function (d) {
console.log("DataTables request data:", d);
return d;
},
error: function (xhr, error, thrown) {
console.error("DataTables error:", xhr, error, thrown);
},
},
columns: [
{ data: "product_code", name: "product_code" },
{ data: "product_name", name: "product_name" },
{ data: "product_category", name: "product_category" },
{ data: "unit", name: "unit" },
{
data: "quantity_required",
name: "quantity_required",
className: "text-right",
},
{ data: "notes", name: "notes" },
{
data: "action",
name: "action",
orderable: false,
searchable: false,
className: "text-center",
width: "auto",
render: function (data, type, row) {
return data;
},
},
],
pageLength: 25,
responsive: true,
autoWidth: false,
columnDefs: [
{
targets: -1, // Action column
className: "text-center",
width: "auto",
orderable: false,
},
],
});
// Add Work Product
$("#addWorkProduct").click(function () {
$("#workProductForm")[0].reset();
$("#work_product_id").val("");
$("#modalHeading").text("Tambah Produk");
$("#workProductModal").modal("show");
// Reset Select2
$("#product_id").val("").trigger("change");
});
// Modal close events
$("#workProductModal").on("hidden.bs.modal", function () {
$("#workProductForm")[0].reset();
$("#work_product_id").val("");
// Reset Select2
$("#product_id").val("").trigger("change");
});
$("#stockPredictionModal").on("hidden.bs.modal", function () {
$("#stockPredictionContent").html("");
$("#prediction_quantity").val(1);
});
// Manual modal close handlers for better compatibility
$(document).on("click", '[data-dismiss="modal"]', function () {
console.log("Modal dismiss clicked");
$(this).closest(".modal").modal("hide");
});
// Close button click handler
$(document).on("click", ".modal .close", function () {
console.log("Modal close button clicked");
$(this).closest(".modal").modal("hide");
});
// Modal backdrop click handler
$(document).on("click", ".modal", function (e) {
if (e.target === this) {
console.log("Modal backdrop clicked");
$(this).modal("hide");
}
});
// ESC key handler for modals
$(document).on("keydown", function (e) {
if (e.keyCode === 27) {
console.log("ESC key pressed");
$(".modal.show").modal("hide");
}
});
// Force close modal function
window.closeModal = function (modalId) {
console.log("Force closing modal:", modalId);
$("#" + modalId).modal("hide");
};
// Additional modal close handlers
$(document).on(
"click",
'.btn-secondary[data-dismiss="modal"]',
function () {
console.log("Secondary button clicked");
$(this).closest(".modal").modal("hide");
}
);
// Bootstrap 4/5 compatible modal close
$(document).on("click", '.btn[data-dismiss="modal"]', function () {
console.log("Button with data-dismiss clicked");
$(this).closest(".modal").modal("hide");
});
// Alternative close button selector
$(document).on("click", ".modal-footer .btn-secondary", function () {
console.log("Footer secondary button clicked");
$(this).closest(".modal").modal("hide");
});
// Bootstrap 5 fallback
$(document).on("click", '[data-bs-dismiss="modal"]', function () {
console.log("Bootstrap 5 dismiss clicked");
$(this).closest(".modal").modal("hide");
});
// Generic secondary button in modal
$(document).on("click", ".modal .btn-secondary", function () {
console.log("Generic secondary button clicked");
$(this).closest(".modal").modal("hide");
});
// Show Stock Prediction
$("#showStockPrediction").click(function () {
console.log("Show stock prediction clicked");
loadStockPrediction();
$("#stockPredictionModal").modal("show");
});
// Apply prediction button
$("#applyPrediction").click(function () {
console.log("Apply prediction clicked");
loadStockPrediction();
});
// Submit Form
$("#workProductForm").submit(function (e) {
e.preventDefault();
let formData = $(this).serialize();
let workProductId = $("#work_product_id").val();
let url, method;
if (workProductId) {
// Update
const currentUpdateUrlTemplate =
updateUrlTemplate ||
$('input[name="update_url_template"]').val();
url = currentUpdateUrlTemplate.replace(":id", workProductId);
method = "PUT";
} else {
// Create
url = storeUrl;
method = "POST";
}
$.ajax({
url: url,
method: method,
data: formData,
success: function (response) {
$("#workProductModal").modal("hide");
table.ajax.reload();
if (typeof Swal !== "undefined") {
Swal.fire({
icon: "success",
title: "Berhasil!",
text: response.message,
timer: 2000,
showConfirmButton: false,
});
} else {
alert("Berhasil: " + response.message);
}
},
error: function (xhr) {
console.error("Error saving work product:", xhr);
let errors = xhr.responseJSON.errors || {};
let message = xhr.responseJSON.message || "Terjadi kesalahan";
if (typeof Swal !== "undefined") {
Swal.fire({
icon: "error",
title: "Error!",
text: message,
});
} else {
alert("Error: " + message);
}
},
});
});
function loadStockPrediction() {
let quantity = $("#prediction_quantity").val();
// Validate quantity
if (!quantity || quantity < 1) {
$("#stockPredictionContent").html(
'<div class="alert alert-warning">Masukkan jumlah pekerjaan yang valid (minimal 1).</div>'
);
return;
}
// Show loading state
$("#stockPredictionContent").html(
'<div class="text-center"><i class="fa fa-spinner fa-spin" style="display: inline-block; width: 16px; height: 16px; border: 2px solid #f3f3f3; border-top: 2px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite;"></i> Memuat data...</div>'
);
// Add timeout for loading state
let loadingTimeout = setTimeout(function () {
$("#stockPredictionContent").html(
'<div class="text-center"><i class="fa fa-spinner fa-spin" style="display: inline-block; width: 16px; height: 16px; border: 2px solid #f3f3f3; border-top: 2px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite;"></i> Memuat data... (mungkin memakan waktu beberapa saat)</div>'
);
}, 2000);
$.ajax({
url: stockPredictionUrl,
method: "GET",
data: { quantity: quantity },
timeout: 10000, // 10 second timeout
success: function (response) {
clearTimeout(loadingTimeout);
let html = "";
if (response.data.length === 0) {
html =
'<div class="alert alert-info">Belum ada produk yang dikonfigurasi untuk pekerjaan ini.</div>';
} else {
html =
'<div class="table-responsive"><table class="table table-bordered">';
html +=
"<thead><tr><th>Produk</th><th>Qty per Pekerjaan</th><th>Total Dibutuhkan</th><th>Catatan</th></tr></thead><tbody>";
response.data.forEach(function (item) {
html += "<tr>";
html +=
"<td>" +
item.product_code +
" - " +
item.product_name +
"</td>";
html +=
'<td class="text-right">' +
item.quantity_per_work +
" " +
item.unit +
"</td>";
html +=
'<td class="text-right"><strong>' +
item.total_quantity_needed +
" " +
item.unit +
"</strong></td>";
html += "<td>" + (item.notes || "-") + "</td>";
html += "</tr>";
});
html += "</tbody></table></div>";
}
$("#stockPredictionContent").html(html);
},
error: function (xhr, status, error) {
clearTimeout(loadingTimeout);
console.error(
"Error loading stock prediction:",
xhr,
status,
error
);
let errorMessage = "Gagal memuat prediksi stock.";
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage = xhr.responseJSON.message;
} else if (status === "timeout") {
errorMessage = "Request timeout. Silakan coba lagi.";
} else if (status === "error") {
errorMessage =
"Terjadi kesalahan jaringan. Silakan coba lagi.";
}
$("#stockPredictionContent").html(
'<div class="alert alert-danger">' + errorMessage + "</div>"
);
},
});
}
});
// Edit Work Product - Using delegated event for dynamic content
$(document).on("click", ".btn-edit-work-product", function () {
let id = $(this).data("id");
editWorkProduct(id);
});
function editWorkProduct(id) {
// Get URL template from hidden input if not available globally
const currentShowUrlTemplate =
showUrlTemplate || $('input[name="show_url_template"]').val();
let url = currentShowUrlTemplate.replace(":id", id);
console.log("Edit URL:", url);
console.log("Work ID:", workId, "Product ID:", id);
console.log("Hidden inputs:", {
work_id: $('input[name="work_id"]').val(),
show_url_template: $('input[name="show_url_template"]').val(),
});
$.ajax({
url: url,
method: "GET",
success: function (response) {
console.log("Edit response:", response);
let data = response.data;
$("#work_product_id").val(data.id);
$("#product_id").val(data.product_id).trigger("change");
$("#quantity_required").val(data.quantity_required);
$("#notes").val(data.notes);
$("#modalHeading").text("Edit Produk");
$("#workProductModal").modal("show");
},
error: function (xhr) {
console.error("Error fetching work product:", xhr);
console.error("Response:", xhr.responseText);
console.error("Status:", xhr.status);
console.error("URL attempted:", url);
if (typeof Swal !== "undefined") {
Swal.fire({
icon: "error",
title: "Error!",
text: "Gagal mengambil data produk",
});
} else {
alert("Error: Gagal mengambil data produk");
}
},
});
}
// Delete Work Product - Using delegated event for dynamic content
$(document).on("click", ".btn-delete-work-product", function () {
let id = $(this).data("id");
deleteWorkProduct(id);
});
function deleteWorkProduct(id) {
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Hapus Produk?",
text: "Data yang dihapus tidak dapat dikembalikan!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#3085d6",
confirmButtonText: "Ya, Hapus!",
cancelButtonText: "Batal",
}).then((result) => {
if (result.isConfirmed) {
performDelete(id);
}
});
} else {
if (
confirm("Hapus Produk? Data yang dihapus tidak dapat dikembalikan!")
) {
performDelete(id);
}
}
}
function performDelete(id) {
// Get URL template and csrfToken from hidden input if not available globally
const currentDestroyUrlTemplate =
destroyUrlTemplate || $('input[name="destroy_url_template"]').val();
const currentCsrfToken = csrfToken || $('input[name="csrf_token"]').val();
let url = currentDestroyUrlTemplate.replace(":id", id);
console.log("Delete URL:", url);
console.log("Work ID:", workId, "Product ID:", id);
$.ajax({
url: url,
method: "DELETE",
data: {
_token: currentCsrfToken,
},
success: function (response) {
console.log("Delete response:", response);
$("#workProductsTable").DataTable().ajax.reload();
if (typeof Swal !== "undefined") {
Swal.fire({
icon: "success",
title: "Berhasil!",
text: response.message,
timer: 2000,
showConfirmButton: false,
});
} else {
alert("Berhasil: " + response.message);
}
},
error: function (xhr) {
console.error("Error deleting work product:", xhr);
console.error("Response:", xhr.responseText);
console.error("Status:", xhr.status);
console.error("URL attempted:", url);
if (typeof Swal !== "undefined") {
Swal.fire({
icon: "error",
title: "Error!",
text: "Gagal menghapus produk",
});
} else {
alert("Error: Gagal menghapus produk");
}
},
});
}

View File

@@ -1,104 +1,221 @@
// Global variables
let ajaxUrl, storeUrl, table;
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
});
var table = $('#kt_table').DataTable({
processing: true,
serverSide: true,
ajax: $("input[name='ajax_url']"),
columns: [
{data: 'category_name', name: 'c.name'},
{data: 'name', name: 'w.name'},
{data: 'shortname', name: 'w.shortname'},
{data: 'desc', name: 'w.desc'},
{data: 'action', name: 'action', orderable: false, searchable: false},
]
$(document).ready(function () {
// Get URLs from hidden inputs
ajaxUrl = $('input[name="ajax_url"]').val();
storeUrl = $('input[name="store_url"]').val();
// Initialize DataTable
table = $("#kt_table").DataTable({
processing: true,
serverSide: true,
ajax: {
url: ajaxUrl,
},
columns: [
{ data: "category_name", name: "c.name" },
{ data: "name", name: "w.name" },
{ data: "shortname", name: "w.shortname" },
{ data: "desc", name: "w.desc" },
{
data: "action",
name: "action",
orderable: false,
searchable: false,
className: "text-center",
width: "auto",
render: function (data, type, row) {
return data;
},
},
],
responsive: true,
autoWidth: false,
columnDefs: [
{
targets: -1, // Action column
className: "text-center",
width: "auto",
orderable: false,
},
],
});
// Initialize Select2
$("#category_id").select2({
placeholder: "-- Pilih Kategori --",
allowClear: true,
width: "100%",
dropdownParent: $("#workModal"),
language: {
noResults: function () {
return "Tidak ada hasil yang ditemukan";
},
searching: function () {
return "Mencari...";
},
},
});
// Modal close handlers
$(document).on("click", '[data-dismiss="modal"]', function () {
$(this).closest(".modal").modal("hide");
});
$(document).on("click", ".modal .close", function () {
$(this).closest(".modal").modal("hide");
});
$(document).on("click", ".modal", function (e) {
if (e.target === this) {
$(this).modal("hide");
}
});
$(document).on("keydown", function (e) {
if (e.keyCode === 27) {
$(".modal.show").modal("hide");
}
});
// Bootstrap 5 fallback
$(document).on("click", '[data-bs-dismiss="modal"]', function () {
$(this).closest(".modal").modal("hide");
});
// Alternative close button selectors
$(document).on("click", ".btn-secondary", function () {
if ($(this).closest(".modal").length) {
$(this).closest(".modal").modal("hide");
}
});
// Force close function
window.closeModal = function (modalId) {
$("#" + modalId).modal("hide");
};
// Modal hidden event
$("#workModal").on("hidden.bs.modal", function () {
$("#workForm").trigger("reset");
$("#category_id").val("").trigger("change");
$('#workForm input[name="_method"]').remove();
});
// Add Work
$("#addWork").click(function () {
$("#workModal").modal("show");
let form_action = storeUrl;
$("#workForm").attr("action", form_action);
$("#workForm input[name='_method']").remove();
$("#workForm").attr("data-form", "store");
$("#workForm").trigger("reset");
$("#workForm textarea[name='desc']").val("");
// Reset Select2
$("#category_id").val("").trigger("change");
});
// Submit Form
$("#workForm").submit(function (e) {
e.preventDefault();
let dataForm = $("#workForm").attr("data-form");
if (dataForm == "store") {
$.ajax({
url: $("#workForm").attr("action"),
type: "POST",
data: $("#workForm").serialize(),
success: function (res) {
$("#workModal").modal("hide");
$("#workForm").trigger("reset");
$("#category_id").val("").trigger("change");
table.ajax.reload();
Swal.fire({
icon: "success",
title: "Berhasil!",
text: "Data pekerjaan berhasil disimpan.",
timer: 2000,
showConfirmButton: false,
});
},
});
} else if (dataForm == "update") {
$.ajax({
url: $("#workForm").attr("action"),
type: "POST",
data: $("#workForm").serialize(),
success: function (res) {
$("#workModal").modal("hide");
$("#workForm").trigger("reset");
$("#category_id").val("").trigger("change");
table.ajax.reload();
Swal.fire({
icon: "success",
title: "Berhasil!",
text: "Data pekerjaan berhasil diupdate.",
timer: 2000,
showConfirmButton: false,
});
},
});
}
});
});
$("#addWork").click(function() {
$("#workModal").modal("show")
let form_action = $("input[name='store_url']").val()
$("#workForm").attr('action', form_action)
$("#workForm input[name='_method']").remove()
$("#workForm").attr('data-form', 'store')
$("#workForm").trigger("reset")
$("#workForm textarea[name='desc']").val("")
})
// Global functions for edit and delete
function destroyWork(id) {
let action = $("#destroyWork"+id).attr("data-action")
let action = $("#destroyWork" + id).attr("data-action");
Swal.fire({
title: 'Hapus Pekerjaan?',
title: "Hapus Pekerjaan?",
text: "Anda tidak akan bisa mengembalikannya!",
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#dedede',
confirmButtonText: 'Hapus'
confirmButtonColor: "#d33",
cancelButtonColor: "#dedede",
confirmButtonText: "Hapus",
}).then((result) => {
if (result.value) {
$.ajax({
url: action,
type: 'POST',
type: "POST",
data: {
_token: $('meta[name="csrf-token"]').attr('content'),
_method: 'DELETE'
_token: $('meta[name="csrf-token"]').attr("content"),
_method: "DELETE",
},
success: function(res) {
success: function (res) {
Swal.fire(
'Dealer Dihapus!'
)
table.ajax.reload()
}
})
"Berhasil!",
"Pekerjaan berhasil dihapus.",
"success"
);
if (table) {
table.ajax.reload();
}
},
});
}
})
});
}
function editWork(id) {
let form_action = $("#editWork"+id).attr("data-action")
let edit_url = $("#editWork"+id).attr("data-url")
$("#workModal").modal("show")
$("#workForm").append('<input type="hidden" name="_method" value="PUT">')
$("#workForm").attr('action', form_action)
$("#workForm").attr('data-form', 'update')
$.get(edit_url, function(res) {
$("#workForm input[name='name']").val(res.data.name)
$("#workForm input[name='shortname']").val(res.data.shortname)
$("#workForm textarea[name='desc']").html(res.data.desc)
$("#workForm option[value='"+ res.data.category_id +"']").prop('selected', true);
})
let form_action = $("#editWork" + id).attr("data-action");
let edit_url = $("#editWork" + id).attr("data-url");
$("#workModal").modal("show");
$("#workForm").append('<input type="hidden" name="_method" value="PUT">');
$("#workForm").attr("action", form_action);
$("#workForm").attr("data-form", "update");
$.get(edit_url, function (res) {
$("#workForm input[name='name']").val(res.data.name);
$("#workForm input[name='shortname']").val(res.data.shortname);
$("#workForm textarea[name='desc']").html(res.data.desc);
$("#workForm select[name='category_id']")
.val(res.data.category_id)
.trigger("change");
});
}
$(document).ready(function () {
$("#workForm").submit(function(e) {
e.preventDefault();
let dataForm = $("#workForm").attr('data-form')
if(dataForm == 'store') {
$.ajax({
url: $('#workForm').attr("action"),
type: 'POST',
data: $('#workForm').serialize(),
success: function(res) {
$("#workModal").modal("hide")
$('#workForm').trigger("reset")
table.ajax.reload()
}
})
}else if(dataForm == 'update') {
$.ajax({
url: $('#workForm').attr("action"),
type: 'POST',
data: $('#workForm').serialize(),
success: function(res) {
$("#workModal").modal("hide")
$('#workForm').trigger("reset")
table.ajax.reload()
}
})
}
})
});