fix opname default value, show different opname and hide system stock opname

This commit is contained in:
2025-07-03 13:55:49 +07:00
parent 9b3889ef1f
commit 0ef03fe7cb
8 changed files with 179 additions and 147 deletions

View File

@@ -739,22 +739,12 @@ use Illuminate\Support\Facades\Auth;
<div class="form-group">
<label>Tanggal Opname <small class="text-muted">(Default: Hari ini)</small></label>
<input type="text" name="opname_date" id="date-opname" class="form-control @error('opname_date') is-invalid @enderror" value="{{ old('opname_date', date('Y-m-d')) }}" placeholder="YYYY-MM-DD">
@error('opname_date')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
<input type="text" name="opname_date" id="date-opname" class="form-control" value="{{ old('opname_date', date('Y-m-d')) }}" placeholder="YYYY-MM-DD">
</div>
<div class="form-group">
<label>Keterangan</label>
<textarea name="description" class="form-control @error('description') is-invalid @enderror" rows="3" placeholder="Keterangan opname">{{ old('description') }}</textarea>
@error('description')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
<label>Keterangan <small class="text-muted">(Opsional)</small></label>
<textarea name="description" class="form-control" rows="3" placeholder="Keterangan opname (opsional)">{{ old('description') }}</textarea>
</div>
<!-- List Produk dengan Stock -->
@@ -764,9 +754,7 @@ use Illuminate\Support\Facades\Auth;
<tr>
<th class="text-center">Produk</th>
<th class="text-center">Dealer</th>
<th class="text-center">Stock Sistem</th>
<th class="text-center">Stock Fisik</th>
<th class="text-center">Selisih</th>
</tr>
</thead>
<tbody>
@@ -779,22 +767,11 @@ use Illuminate\Support\Facades\Auth;
<tr>
<td class="text-center">{{ $product->name }}</td>
<td class="text-center">{{ $mechanic->dealer_name }}</td>
<td class="text-center">
<span class="system-stock">{{ number_format($currentStock, 2) }}</span>
<td>
<input type="hidden" name="product_id[]" value="{{ $product->id }}">
<input type="hidden" name="dealer_id_stock[]" value="{{ $mechanic->dealer_id }}">
<input type="hidden" name="system_stock[]" value="{{ $currentStock }}">
</td>
<td>
<input type="number" class="form-control physical-stock @error('physical_stock.'.$loop->index) is-invalid @enderror" name="physical_stock[]" step="0.01" placeholder="0.00" data-system="{{ $currentStock }}" value="{{ old('physical_stock.'.$loop->index) }}">
@error('physical_stock.'.$loop->index)
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</td>
<td class="text-center">
<span class="difference text-bold">0.00</span>
<input type="number" class="form-control physical-stock" name="physical_stock[]" step="0.01" placeholder="0.00" data-system="{{ $currentStock }}" value="{{ old('physical_stock.'.$loop->index, '0.00') }}" min="0">
</td>
</tr>
@endforeach
@@ -806,6 +783,10 @@ use Illuminate\Support\Facades\Auth;
<button id="btn-save-opname" class="btn btn-warning btn-lg d-block w-100 mt-2">
Simpan Opname
</button>
<small class="text-muted d-block text-center mt-2">
<i class="fa fa-info-circle"></i>
Stock fisik yang kosong akan otomatis diisi dengan 0
</small>
</div>
</form>
</div>
@@ -1353,49 +1334,39 @@ use Illuminate\Support\Facades\Auth;
// Save current tab to localStorage
localStorage.setItem('activeTab', '#opname');
// Validate form
// Set default values for empty fields and validate
var hasValidStock = false;
var invalidRows = [];
$('.physical-stock').each(function(index) {
var value = $(this).val();
var row = $(this).closest('tr');
var productName = row.find('td:first').text().trim();
// Check if value is valid (including 0)
if (value !== '' && value !== null && value !== undefined) {
var numValue = parseFloat(value);
if (!isNaN(numValue) && numValue >= 0) {
hasValidStock = true;
// Ensure the value is properly formatted
$(this).val(numValue.toFixed(2));
} else {
invalidRows.push(productName + ' (nilai tidak valid)');
}
// Set default value to 0 if empty
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
value = '0.00';
}
// Validate and format the value
var numValue = parseFloat(value);
if (!isNaN(numValue) && numValue >= 0) {
hasValidStock = true;
// Ensure the value is properly formatted
$(this).val(numValue.toFixed(2));
} else {
// If invalid, set to 0
$(this).val('0.00');
hasValidStock = true; // Still consider valid since we set default
}
// Don't remove elements here - let them stay for re-editing
});
// Show error if no valid stock entries
// Always allow submission since we set defaults
if (!hasValidStock) {
// This should never happen now, but just in case
resetSubmitButton();
highlightInvalidFields();
Swal.fire({
icon: 'warning',
title: 'Peringatan',
text: 'Minimal harus ada satu produk dengan stock fisik yang diisi dengan benar!'
});
return false;
}
// Show error if there are invalid entries
if (invalidRows.length > 0) {
resetSubmitButton();
highlightInvalidFields();
Swal.fire({
icon: 'warning',
title: 'Data Tidak Valid',
text: 'Perbaiki data berikut: ' + invalidRows.join(', ')
text: 'Terjadi kesalahan dalam validasi data. Silakan coba lagi.'
});
return false;
}
@@ -1457,21 +1428,6 @@ use Illuminate\Support\Facades\Auth;
// Date format is already YYYY-MM-DD, no conversion needed
// Clean up empty rows before submit (remove hidden inputs for truly empty fields only)
$('.physical-stock').each(function() {
var value = $(this).val();
var row = $(this).closest('tr');
// Only remove hidden inputs if physical stock is truly empty (not 0)
// Keep 0 values as they are valid input
if (value === '' || value === null || value === undefined) {
row.find('input[name="product_id[]"]').remove();
row.find('input[name="dealer_id_stock[]"]').remove();
row.find('input[name="system_stock[]"]').remove();
// But keep the physical_stock input so it can be re-edited if form fails
}
});
// Submit form
this.submit();
})
@@ -1690,31 +1646,34 @@ use Illuminate\Support\Facades\Auth;
// Function to update product counter
function updateProductCounter() {
var filledProducts = 0;
var totalProducts = $('.physical-stock').length;
$('.physical-stock').each(function() {
var value = $(this).val();
// Count as filled if it's a valid number (including 0)
if (value !== '' && value !== null && value !== undefined && !isNaN(parseFloat(value)) && parseFloat(value) >= 0) {
filledProducts++;
}
});
// Update button text to show progress
// Update button text to show total products
var buttonText = 'Simpan Opname';
if (filledProducts > 0) {
buttonText += ` (${filledProducts}/${totalProducts} produk)`;
}
buttonText += ` (${totalProducts} produk)`;
if (!$('#btn-save-opname').hasClass('disabled')) {
$('#btn-save-opname').html(buttonText);
}
}
// Handle when input loses focus - don't auto-fill, let user decide
// Initialize default values for physical stock inputs
$(document).ready(function() {
$('.physical-stock').each(function() {
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
});
});
// Handle when input loses focus - set default if empty
$(document).on('blur', '.physical-stock', function() {
// Trigger calculation even for empty values
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
// Trigger calculation
$(this).trigger('input');
});
@@ -1725,28 +1684,12 @@ use Illuminate\Support\Facades\Auth;
updateProductCounter(); // Update with current counter
}
// Function to show field error highlighting
function highlightInvalidFields() {
$('.physical-stock').each(function() {
var value = $(this).val();
var $input = $(this);
if (value !== '' && value !== null && value !== undefined) {
var numValue = parseFloat(value);
if (isNaN(numValue) || numValue < 0) {
$input.addClass('is-invalid');
} else {
$input.removeClass('is-invalid');
}
} else {
$input.removeClass('is-invalid');
}
});
}
// Remove error styling when user starts typing
$(document).on('input', '.physical-stock', function() {
$(this).removeClass('is-invalid');
// Set default values when user leaves field empty
$(document).on('blur', '.physical-stock', function() {
var value = $(this).val();
if (value === '' || value === null || value === undefined) {
$(this).val('0.00');
}
});
// Remove invalid styling when user starts typing in required fields
@@ -1779,6 +1722,9 @@ use Illuminate\Support\Facades\Auth;
$('#date-opname').val(today);
}
// Initialize opname form
updateProductCounter();
// Initialize mutasi form
updateRemoveButtonsMutasi();
@@ -1935,7 +1881,10 @@ use Illuminate\Support\Facades\Auth;
} else if (successMessage.toLowerCase().includes('opname') || activeTab === 'opname') {
// Reset opname form after success
$('#opnameForm')[0].reset();
$('.physical-stock').val('').removeClass('is-invalid');
// Set default values for physical stock inputs
$('.physical-stock').each(function() {
$(this).val('0.00');
});
$('.difference').text('0.00').removeClass('text-success text-danger');
$("#btn-save-opname").attr("disabled", false);
$("#btn-save-opname").removeClass("disabled");
@@ -1963,6 +1912,12 @@ use Illuminate\Support\Facades\Auth;
$("#btn-save-opname").attr("disabled", false);
$("#btn-save-opname").removeClass("disabled");
$("#btn-save-opname").html('Simpan Opname');
// Set default values for physical stock inputs
$('.physical-stock').each(function() {
if ($(this).val() === '' || $(this).val() === null || $(this).val() === undefined) {
$(this).val('0.00');
}
});
} else if (activeTab === 'mutasi') {
// Reset button states for mutasi form
$("#btn-save-mutasi").attr("disabled", false);

View File

@@ -327,7 +327,7 @@
<!-- Header -->
<div class="header">
<div class="company-info">
<div class="company-name">PT. CINTA KASIH BERSAMA</div>
<div class="company-name">PT. CIPTA KREASI BARU</div>
<div class="company-tagline">Warehouse Management System</div>
</div>
<div class="document-title">Dokumen Mutasi Stock</div>
@@ -528,7 +528,7 @@
<div class="footer">
<div class="print-info">
Dicetak pada: {{ now()->format('d F Y H:i:s') }} |
Sistem Manajemen Gudang PT. Cinta Kasih Bersama
Sistem Manajemen Gudang PT. Cipta Kreasi Baru
</div>
</div>
</div>

View File

@@ -69,6 +69,7 @@
<th>Dealer</th>
<th>Pengguna</th>
<th>Status</th>
<th>Informasi Stock</th>
<th>Aksi</th>
</tr>
</thead>
@@ -114,6 +115,44 @@
letter-spacing: normal;
display: block;
}
/* Stock info column styling */
.stock-info-cell {
min-width: 120px;
max-width: 150px;
}
.stock-info-cell .text-success {
color: #28a745 !important;
font-weight: 600;
}
.stock-info-cell .text-danger {
color: #dc3545 !important;
font-weight: 600;
}
.stock-info-cell .text-muted {
color: #6c757d !important;
font-size: 11px;
}
.stock-info-cell i {
margin-right: 4px;
}
/* Responsive adjustments for stock info column */
@media (max-width: 768px) {
.stock-info-cell {
min-width: 100px;
max-width: 120px;
font-size: 12px;
}
.stock-info-cell .text-muted {
font-size: 10px;
}
}
</style>
@endsection

View File

@@ -287,7 +287,7 @@
<!-- Header -->
<div class="header">
<div class="company-info">
<div class="company-name">PT. CINTA KASIH BERSAMA</div>
<div class="company-name">PT. CIPTA KREASI BARU</div>
<div class="company-tagline">Warehouse Management System</div>
</div>
<div class="document-title">Laporan Stock Opname</div>
@@ -420,7 +420,7 @@
<div class="footer">
<div class="print-info">
Dicetak pada: {{ now()->format('d F Y H:i:s') }} |
Sistem Manajemen Gudang PT. Cinta Kasih Bersama
Sistem Manajemen Gudang PT. Cipta Kreasi Baru
</div>
</div>
</div>