add backup file and autobackup code, partial update mutations receive on transation page

This commit is contained in:
2025-06-12 18:09:13 +07:00
parent 58578532cc
commit b04b8f88cb
9 changed files with 1276 additions and 21 deletions

View File

@@ -108,6 +108,62 @@ use Illuminate\Support\Facades\Auth;
.available-stock-mutasi {
font-weight: 600;
}
/* Styles for receive mutations table */
#receiveMutationsTable {
font-size: 14px;
}
#receiveMutationsTable th {
background-color: #f8f9fa;
font-weight: 600;
text-align: center;
vertical-align: middle;
}
#receiveMutationsTable td {
vertical-align: middle;
}
.btn-detail {
font-size: 12px;
padding: 4px 8px;
}
.status-badge {
font-size: 11px;
padding: 4px 8px;
border-radius: 12px;
font-weight: 600;
}
.mutation-detail-table {
font-size: 14px;
}
.mutation-detail-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.quantity-approved-input {
text-align: center;
font-weight: 600;
}
.quantity-approved-input.is-invalid {
border-color: #dc3545;
background-color: #fff5f5;
}
.mutation-detail-table textarea {
font-size: 12px;
resize: vertical;
}
.mutation-detail-table input {
font-size: 14px;
}
</style>
@endsection
@@ -487,6 +543,9 @@ use Illuminate\Support\Facades\Auth;
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#mutasi">Mutasi</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#penerimaan">Penerimaan Mutasi</a>
</li>
</ul>
<div class="tab-content mt-3">
@@ -655,6 +714,30 @@ use Illuminate\Support\Facades\Auth;
</div>
</form>
</div>
<!-- Tab Penerimaan Mutasi -->
<div class="tab-pane" id="penerimaan" role="tabpanel">
<div class="mt-3">
<h6 class="mb-3">Daftar Mutasi yang Perlu Diterima</h6>
<div class="table-responsive">
<table class="table table-bordered table-hover" id="receiveMutationsTable">
<thead class="thead-light">
<tr>
<th width="20%">No. Mutasi</th>
<th width="25%">Dealer Asal</th>
<th width="15%">Status</th>
<th width="10%">Total Item</th>
<th width="15%">Tanggal</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<!-- Data will be loaded via DataTables AJAX -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -668,6 +751,37 @@ use Illuminate\Support\Facades\Auth;
<input type="hidden" name="dealer_id" value="{{ $mechanic->dealer_id }}">
</div>
</div>
<!-- Modal Detail Mutasi -->
<div class="modal fade" id="mutationDetailModal" tabindex="-1" role="dialog" aria-labelledby="mutationDetailModalLabel">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="mutationDetailModalLabel">Detail & Penerimaan Mutasi</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form id="receiveMutationForm" action="" method="POST">
@csrf
<div class="modal-body">
<div id="mutationDetailContent">
<div class="text-center">
<i class="fa fa-spinner fa-spin fa-2x"></i>
<p class="mt-2">Memuat data...</p>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-success" id="receiveButton" style="display: none;">
<i class="fa fa-check"></i> Terima Mutasi
</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@section('javascripts')
@@ -1479,6 +1593,277 @@ use Illuminate\Support\Facades\Auth;
// Initialize DataTable for receive mutations
var receiveMutationsTable;
function initReceiveMutationsTable() {
if (receiveMutationsTable) {
receiveMutationsTable.destroy();
}
receiveMutationsTable = $('#receiveMutationsTable').DataTable({
processing: true,
serverSide: true,
ajax: {
url: '{{ route("mutations.get-pending-mutations") }}',
data: {
dealer_id: {{ $mechanic->dealer_id }}
}
},
columns: [
{data: 'mutation_number', name: 'mutation_number'},
{data: 'from_dealer', name: 'from_dealer'},
{data: 'status', name: 'status', orderable: false},
{data: 'total_items', name: 'total_items'},
{data: 'created_at', name: 'created_at'},
{data: 'action', name: 'action', orderable: false, searchable: false}
],
pageLength: 10,
responsive: true,
scrollX: true
});
}
// Show mutation detail modal
function showMutationDetail(mutationId) {
$('#mutationDetailModal').modal('show');
$('#mutationDetailContent').html(`
<div class="text-center">
<i class="fa fa-spinner fa-spin fa-2x"></i>
<p class="mt-2">Memuat data...</p>
</div>
`);
$('#receiveButton').hide();
// Load mutation detail via AJAX
$.ajax({
url: '{{ route("mutations.get-detail", ":id") }}'.replace(':id', mutationId),
method: 'GET',
success: function(response) {
if (response.success) {
renderMutationDetail(response.data);
} else {
$('#mutationDetailContent').html(`
<div class="alert alert-danger">
<i class="fa fa-exclamation-triangle"></i>
${response.message || 'Gagal memuat detail mutasi'}
</div>
`);
}
},
error: function(xhr) {
$('#mutationDetailContent').html(`
<div class="alert alert-danger">
<i class="fa fa-exclamation-triangle"></i>
Terjadi kesalahan saat memuat data
</div>
`);
}
});
}
// Render mutation detail in modal
function renderMutationDetail(mutation) {
var statusColor = mutation.status_color;
var statusLabel = mutation.status_label;
// Set form action URL
$('#receiveMutationForm').attr('action', '{{ route("mutations.receive", ":id") }}'.replace(':id', mutation.id));
// Build detail HTML
var detailHtml = `
<div class="row mb-3">
<div class="col-md-6">
<strong>No. Mutasi:</strong><br>
${mutation.mutation_number}
</div>
<div class="col-md-6">
<strong>Status:</strong><br>
<span class="font-weight-bold text-${statusColor}">${statusLabel}</span>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<strong>Dealer Asal:</strong><br>
${mutation.from_dealer.name}
</div>
<div class="col-md-6">
<strong>Tanggal:</strong><br>
${mutation.created_at_formatted}
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<strong>Diminta oleh:</strong><br>
${mutation.requested_by ? mutation.requested_by.name : '-'}
</div>
</div>
<hr>
<div class="row mb-3">
<div class="col-md-12">
<label for="mutationNotes"><strong>Catatan Penerimaan:</strong></label>
<textarea name="notes" id="mutationNotes" class="form-control" rows="3" placeholder="Masukkan catatan jika diperlukan..."></textarea>
</div>
</div>
<h6 class="mb-3">Detail Produk & Penerimaan:</h6>
<div class="table-responsive">
<table class="table table-bordered mutation-detail-table">
<thead>
<tr>
<th width="30%">Produk</th>
<th width="15%" class="text-center">Qty Diminta</th>
<th width="20%" class="text-center">Qty Disetujui</th>
<th width="35%">Catatan Produk</th>
</tr>
</thead>
<tbody>
`;
// Add product details with form inputs
if (mutation.mutation_details && mutation.mutation_details.length > 0) {
mutation.mutation_details.forEach(function(detail) {
detailHtml += `
<tr>
<td>${detail.product.name}</td>
<td class="text-center">
<span class="font-weight-bold text-info">${parseFloat(detail.quantity_requested).toFixed(2)}</span>
</td>
<td>
<input type="number"
name="products[${detail.id}][quantity_approved]"
class="form-control quantity-approved-input"
min="0"
max="${detail.quantity_requested}"
step="0.01"
value="${detail.quantity_requested}"
data-max="${detail.quantity_requested}"
placeholder="0.00">
</td>
<td>
<textarea name="products[${detail.id}][notes]"
class="form-control"
rows="2"
placeholder="Catatan untuk produk ini..."></textarea>
</td>
</tr>
`;
});
} else {
detailHtml += `
<tr>
<td colspan="4" class="text-center">Tidak ada detail produk</td>
</tr>
`;
}
detailHtml += `
</tbody>
</table>
</div>
<div class="alert alert-info">
<i class="fa fa-info-circle"></i>
<strong>Petunjuk:</strong>
Masukkan quantity yang disetujui untuk setiap produk. Quantity tidak boleh melebihi quantity yang diminta.
</div>
`;
$('#mutationDetailContent').html(detailHtml);
// Show receive button if mutation can be received
if (mutation.can_be_received) {
$('#receiveButton').show();
}
// Add validation for quantity inputs
$('.quantity-approved-input').on('input', function() {
var value = parseFloat($(this).val()) || 0;
var max = parseFloat($(this).data('max')) || 0;
if (value > max) {
$(this).addClass('is-invalid');
if (!$(this).siblings('.invalid-feedback').length) {
$(this).after('<div class="invalid-feedback">Quantity tidak boleh melebihi quantity yang diminta</div>');
}
} else {
$(this).removeClass('is-invalid');
$(this).siblings('.invalid-feedback').remove();
}
});
}
// Handle receive form submission
$('#receiveMutationForm').on('submit', function(e) {
e.preventDefault();
// Validate form
var hasInvalidInput = $('.quantity-approved-input.is-invalid').length > 0;
if (hasInvalidInput) {
Swal.fire({
type: 'error',
title: 'Validasi Gagal',
text: 'Perbaiki quantity yang tidak valid sebelum melanjutkan'
});
return false;
}
// Check if at least one product has quantity approved > 0
var hasApprovedQuantity = false;
$('.quantity-approved-input').each(function() {
if (parseFloat($(this).val()) > 0) {
hasApprovedQuantity = true;
return false; // break loop
}
});
if (!hasApprovedQuantity) {
Swal.fire({
type: 'warning',
title: 'Peringatan',
text: 'Minimal satu produk harus memiliki quantity yang disetujui'
});
return false;
}
if (typeof Swal !== 'undefined') {
Swal.fire({
title: 'Terima Mutasi?',
text: "Mutasi akan diterima dengan quantity dan catatan yang telah Anda masukkan",
type: 'question',
showCancelButton: true,
confirmButtonColor: '#28a745',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, Terima',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.value) {
// Set loading state
$('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...');
// Submit form
this.submit();
}
});
} else {
if (confirm('Terima mutasi dengan data yang telah dimasukkan?')) {
$('#receiveButton').prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Memproses...');
this.submit();
}
}
});
// Initialize table when tab is shown
$('a[href="#penerimaan"]').on('shown.bs.tab', function (e) {
setTimeout(function() {
initReceiveMutationsTable();
}, 100);
});
function createTransaction(form) {
let work_ids;
if(form == 'work') {