Files
wms-app/app/ics/manage_stock_out.php
T

465 lines
16 KiB
PHP

<?php
session_start();
require '../config.php';
require '../include_header.php';
?>
<body>
<?php require '../include_topbar.php';?>
<?php require '../include_sidebar.php';?>
<!-- MAIN CONTENT -->
<main id="content" class="content py-15">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="mb-6">
<h1 class="fs-3 mb-0">Stock Out</h1>
</div>
</div>
</div>
<div class="row g">
<div class="col-lg-8 col-12">
<div class="card">
<div class="card-body p-5">
<h2 class="fs-5 mb-4">Remove Stock</h2>
<form class="row gx-5">
<!-- Step 1: Product -->
<div class="mb-3 col-lg-3">
<label for="product_sku" class="form-label">SKU</label>
<input type="text" id="product_sku" class="form-control product_search"
placeholder="Type product sku..." autocomplete="off" required>
</div>
<div class="mb-3 col-lg-3">
<label for="product_name" class="form-label">Name</label>
<input type="text" id="product_name" class="form-control" autocomplete="off" disabled>
</div>
<!-- Step 2: Lot Number (active lots for selected SKU) -->
<div class="mb-3 col-lg-3">
<label for="lot_number" class="form-label">Lot Number <span class="text-muted fw-normal">(optional)</span></label>
<select id="lot_number" class="form-select">
<option value="">Select lot...</option>
</select>
</div>
<!-- Step 3: Serial Number (active serials for selected SKU + lot) -->
<div class="mb-3 col-lg-3">
<label for="serial_number" class="form-label">Serial Number <span class="text-muted fw-normal">(optional)</span></label>
<select id="serial_number" class="form-select">
<option value="">Select serial...</option>
</select>
</div>
<!-- Step 4: Warehouse -->
<div class="mb-3 col-lg-6">
<label for="warehouse" class="form-label">Warehouse</label>
<select name="warehouse" id="warehouse" class="form-select" required disabled>
<option value="">Select warehouse...</option>
</select>
</div>
<!-- Step 5: Zone -->
<div class="mb-3 col-lg-6" id="group_zone">
<label for="zone" class="form-label" id="label_zone">Zone</label>
<select name="zone" id="zone" class="form-select" disabled>
<option value="">Please select zone</option>
</select>
</div>
<!-- Step 6: Aisle -->
<div class="mb-3 col-lg-6" id="group_aisle">
<label for="aisle" class="form-label" id="label_aisle">Aisle</label>
<select name="aisle" id="aisle" class="form-select" disabled>
<option value="">Please select aisle</option>
</select>
</div>
<!-- Step 7: Rack -->
<div class="mb-3 col-lg-6" id="group_rack">
<label for="rack" class="form-label" id="label_rack">Rack</label>
<select name="rack" id="rack" class="form-select" required disabled>
<option value="">Please select rack</option>
</select>
</div>
<!-- Contact -->
<div class="mb-3 col-lg-6">
<label for="contact" class="form-label">Contact</label>
<input type="text" class="form-control contact_search" id="contact" placeholder="Enter contact name">
</div>
<!-- Notes / Description -->
<div class="mb-3 col-lg-12">
<label for="description" class="form-label">Notes / Description</label>
<textarea class="form-control" id="description" rows="3" placeholder="Enter any notes"></textarea>
</div>
<!-- Submit Button -->
<div class="mb-3 col-lg-12">
<button type="submit" class="btn btn-primary" onclick="manage_stock_out();">Remove Stock</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</main>
<?php require "../include_ending.php";?>
<script>
var advanced = false;
var label_rack = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
function load_location_config(callback) {
return ajax_request({
url: server_url + 'setting/api/engine/company_setting.php',
autoPrepare: true,
checkRequired: 0,
action: 'read',
onSuccess: function(res) {
var s = res.output;
advanced = s.advanced_location == 1;
label_rack = s.location_label_rack || (advanced ? 'Rack' : 'Location');
label_zone = s.location_label_zone || 'Zone';
label_aisle = s.location_label_aisle || 'Aisle';
if (callback) callback();
}
});
}
function apply_location_labels() {
if (advanced) {
$('#group_zone').show();
$('#group_aisle').show();
$('#label_zone').text(label_zone);
$('#label_aisle').text(label_aisle);
$('#label_rack').text(label_rack);
} else {
$('#group_zone').hide();
$('#group_aisle').hide();
$('#label_rack').text(label_rack);
}
}
function manage_stock_out() {
if (!advanced) {
var rack_val = $('#rack').val();
$('#zone').val(rack_val);
$('#aisle').val(rack_val);
}
return ajax_request({
url: '<?php echo $server_url?>ics/api/engine/manage_stock_out.php',
autoPrepare: true,
checkRequired: 1,
debugMode: 0,
data: {
'contact_id': $('#contact').attr('data-id'),
'zone': $('#zone').val(),
'aisle': $('#aisle').val(),
},
action: 'manage',
onSuccess: function() {
window.location.href = '<?php echo $server_url?>ics/stock_out.php';
}
});
}
// ── Step 1: Product selected → load active lots ───────────────────────
function retrieve_active_lot() {
var sku = $('#product_sku').attr('secondary') || $('#product_sku').val();
if (!sku) return;
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_active_lot.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
action: 'read',
data: { "product_sku": sku },
onSuccess: function(res) {
var option = '<option value="">Select lot... (optional)</option>';
$.each(res.output, function(i, item) {
var label = item.lot_number;
if (item.expiry_date) label += ' — exp: ' + item.expiry_date;
option += `<option value="${item.lot_number}">${label}</option>`;
});
$('#lot_number').html(option).prop('disabled', false);
$('#serial_number').html('<option value="">Select serial... (optional)</option>').prop('disabled', false);
// Reset downstream
reset_location();
}
});
}
// ── Step 2: Lot selected → load active serials ────────────────────────
function retrieve_active_serial() {
var sku = $('#product_sku').attr('secondary') || $('#product_sku').val();
if (!sku) return;
var lot = $('#lot_number').val();
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_active_serial.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
action: 'read',
data: { "product_sku": sku, "lot_number": lot },
onSuccess: function(res) {
var option = '<option value="">Select serial... (optional)</option>';
$.each(res.output, function(i, serial) {
option += `<option value="${serial}">${serial}</option>`;
});
$('#serial_number').html(option).prop('disabled', false);
// Reset downstream
reset_location();
}
});
}
// ── Step 4: Load warehouse filtered by SKU ────────────────────────────
function retrieve_warehouse() {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_warehouse.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
data: { "type": 'from', "lot_number": $('#lot_number').val() },
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Select warehouse...</option>';
$.each(res.output, function(key, item) {
option += `<option value='${item.id}'>${item.warehouse_name}</option>`;
});
$('#warehouse').html(option).prop('disabled', false);
}
});
}
// ── Steps 5-7: Zone → Aisle → Rack ───────────────────────────────────
function retrieve_zone(callback) {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_zone.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
data: {
"type": 'from',
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
"lot_number": $('#lot_number').val(),
"serial_number": $('#serial_number').val()
},
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_zone.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += `<option value='${item.zone}'>${item.zone}</option>`;
});
$('#zone').html(option).prop('disabled', false);
if (callback) callback();
}
});
}
function retrieve_aisle(callback) {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_aisle.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
data: {
"type": 'from',
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
"lot_number": $('#lot_number').val(),
"serial_number": $('#serial_number').val()
},
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_aisle.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += `<option value='${item}'>${item}</option>`;
});
$('#aisle').html(option).prop('disabled', false);
if (callback) callback();
}
});
}
function retrieve_rack(callback) {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_rack.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
data: {
"type": 'from',
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
"lot_number": $('#lot_number').val(),
"serial_number": $('#serial_number').val()
},
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_rack.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += `<option value='${item}'>${item}</option>`;
});
$('#rack').html(option).prop('disabled', false);
if (callback) callback();
}
});
}
// ── Reset location dropdowns ──────────────────────────────────────────
function reset_location() {
$('#warehouse').html('<option value="">Select warehouse...</option>').prop('disabled', true);
$('#zone').html('<option value="">Please select ' + label_zone.toLowerCase() + '</option>').prop('disabled', true);
$('#aisle').html('<option value="">Please select ' + label_aisle.toLowerCase() + '</option>').prop('disabled', true);
$('#rack').html('<option value="">Please select ' + label_rack.toLowerCase() + '</option>').prop('disabled', true);
}
// ── Edit mode ─────────────────────────────────────────────────────────
function retrieve_for_edit() {
<?php if(empty($_GET["id"])){ ?>
return false;
<?php } ?>
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_stock_out.php",
autoPrepare: true,
checkRequired: 0,
debugMode: 0,
action: 'read',
onSuccess: function(res) {
var data = res.output;
// Lock lot/serial — not editable in edit mode
$('#lot_number').html(`<option value="${data.lot_number || ''}">${data.lot_number || '—'}</option>`)
.val(data.lot_number || '').prop('disabled', true);
$('#serial_number').html(`<option value="${data.serial_number || ''}">${data.serial_number || '—'}</option>`)
.val(data.serial_number || '').prop('disabled', true);
$('#warehouse').val('<?php echo $_GET["wh"];?>').prop('disabled', true);
function populate_fields() {
$.each(data, function(key, item) {
if (!['warehouse', 'zone', 'aisle', 'rack', 'lot_number', 'serial_number'].includes(key)) {
$('#' + key).val(item);
}
});
$('#contact').val(data.contact_name)
.attr('secondary', data.contact_name)
.attr('data-id', data.contact_id);
$('#product_name').val(data.product_name);
$('#product_sku').attr('secondary', data.product_sku).prop('disabled', true);
$('button[type=submit]').text('Update');
$('button[type=reset]').hide();
}
if (advanced) {
retrieve_zone(function() {
$('#zone').val(data.zone).prop('disabled', true);
retrieve_aisle(function() {
$('#aisle').val(data.aisle).prop('disabled', true);
retrieve_rack(function() {
$('#rack').val(data.rack).prop('disabled', true);
populate_fields();
});
});
});
} else {
// Simple mode — skip zone/aisle cascade
retrieve_rack(function() {
$('#rack').val(data.rack).prop('disabled', true);
populate_fields();
});
}
}
});
}
// ── Boot ─────────────────────────────────────────────────────────────
$(async function() {
try {
await load_location_config(apply_location_labels);
await retrieve_warehouse();
await retrieve_for_edit();
} catch(e) {
console.log(e);
}
});
// ── Change handlers (create mode only) ───────────────────────────────
<?php if(empty($_GET["id"])){ ?>
// SKU selected → load lots
$('input#product_sku').on('blur', function() {
var sku = $(this).attr('secondary');
if (!sku) return;
retrieve_active_lot();
retrieve_warehouse();
});
// Lot selected → reload serials + location
$('#lot_number').on('change', function() {
retrieve_active_serial();
retrieve_warehouse();
});
// Serial selected → reload location
$('#serial_number').on('change', function() {
retrieve_warehouse();
});
// Warehouse selected → load zone (advanced) or rack directly (simple)
$('#warehouse').on('change', function() {
if (advanced) {
retrieve_zone();
} else {
retrieve_rack();
}
});
// Zone selected → load aisle (advanced only)
$('#zone').on('change', function() {
if (advanced) retrieve_aisle();
});
// Aisle selected → load rack (advanced only)
$('#aisle').on('change', function() {
if (advanced) retrieve_rack();
});
<?php } ?>
</script>
</body>
</html>