Barcode Operations
This commit is contained in:
@@ -28,8 +28,13 @@
|
||||
<!-- 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 class="input-group">
|
||||
<input type="text" id="product_sku" class="form-control product_search"
|
||||
placeholder="Type product sku..." autocomplete="off" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="scanner.open_camera()" title="Scan barcode label">
|
||||
<i class="ti ti-scan"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-3">
|
||||
<label for="product_name" class="form-label">Name</label>
|
||||
@@ -150,6 +155,133 @@
|
||||
var label_rack = 'Location';
|
||||
var label_zone = 'Zone';
|
||||
var label_aisle = 'Aisle';
|
||||
var scan_sku_ready = false;
|
||||
var scan_from_ready = false;
|
||||
var scan_to_ready = false;
|
||||
var pending_scan_lot = '';
|
||||
var pending_scan_serial = '';
|
||||
|
||||
function set_select_value(selector, value, label) {
|
||||
if (!value) return;
|
||||
var $select = $(selector);
|
||||
if (!$select.find(`option[value="${value}"]`).length) {
|
||||
$select.append(`<option value="${value}">${label || value}</option>`);
|
||||
}
|
||||
$select.val(value).prop('disabled', false);
|
||||
}
|
||||
|
||||
function apply_sku_label_scan(data) {
|
||||
$('#product_sku').val(data.sku).attr('secondary', data.sku);
|
||||
$('#product_name').val(data.product_name || '').attr('secondary', data.product_name || '');
|
||||
pending_scan_lot = data.lot_number || '';
|
||||
pending_scan_serial = data.serial_number || '';
|
||||
set_select_value('#lot_number', data.lot_number, data.lot_number);
|
||||
set_select_value('#serial_number', data.serial_number, data.serial_number);
|
||||
scan_sku_ready = true;
|
||||
scan_from_ready = false;
|
||||
scan_to_ready = false;
|
||||
reset_from_location();
|
||||
reset_to_location();
|
||||
retrieve_active_lot();
|
||||
}
|
||||
|
||||
function apply_location_label_scan(data) {
|
||||
if (!scan_sku_ready && !($('#product_sku').attr('secondary') || $('#product_sku').val())) {
|
||||
bootbox.alert('Scan the SKU label first, then scan the from-location label.');
|
||||
return;
|
||||
}
|
||||
|
||||
var role = scan_from_ready ? 'to' : 'from';
|
||||
if (role === 'to' && same_location_as_from(data)) {
|
||||
bootbox.alert('To-location must be different from from-location.');
|
||||
return;
|
||||
}
|
||||
|
||||
validate_scanned_location(role, data, function() {
|
||||
set_select_value('#warehouse_' + role, data.warehouse_id, data.warehouse_id);
|
||||
if (advanced) {
|
||||
set_select_value('#zone_' + role, data.zone, data.zone);
|
||||
set_select_value('#aisle_' + role, data.aisle, data.aisle);
|
||||
}
|
||||
set_select_value('#rack_' + role, data.rack, data.rack);
|
||||
|
||||
if (role === 'from') {
|
||||
scan_from_ready = true;
|
||||
} else {
|
||||
scan_to_ready = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function same_location_as_from(data) {
|
||||
return String($('#warehouse_from').val()) === String(data.warehouse_id)
|
||||
&& String($('#zone_from').val()) === String(data.zone)
|
||||
&& String($('#aisle_from').val()) === String(data.aisle)
|
||||
&& String($('#rack_from').val()) === String(data.rack);
|
||||
}
|
||||
|
||||
function validate_scanned_location(role, data, onSuccess) {
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/validate_scan_location.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'read',
|
||||
queueLock: false,
|
||||
noLoading: true,
|
||||
data: {
|
||||
mode: role,
|
||||
warehouse_id: data.warehouse_id,
|
||||
zone: data.zone,
|
||||
aisle: data.aisle,
|
||||
rack: data.rack,
|
||||
product_sku: $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
lot_number: $('#lot_number').val(),
|
||||
serial_number: $('#serial_number').val()
|
||||
},
|
||||
onSuccess: onSuccess
|
||||
});
|
||||
}
|
||||
|
||||
function reset_to_location() {
|
||||
$('#warehouse_to').val('');
|
||||
$('#zone_to').html('<option value="">Please select ' + label_zone.toLowerCase() + '</option>').val('');
|
||||
$('#aisle_to').html('<option value="">Please select ' + label_aisle.toLowerCase() + '</option>').val('');
|
||||
$('#rack_to').html('<option value="">Please select ' + label_rack.toLowerCase() + '</option>').val('');
|
||||
}
|
||||
|
||||
function reset_stock_transfer_inputs() {
|
||||
$('form')[0].reset();
|
||||
$('#product_sku').removeAttr('secondary').prop('disabled', false);
|
||||
$('#product_name').removeAttr('secondary').val('');
|
||||
$('#lot_number').html('<option value="">Select lot...</option>').prop('disabled', false);
|
||||
$('#serial_number').html('<option value="">Select serial...</option>').prop('disabled', false);
|
||||
$('#contact').removeAttr('secondary data-id');
|
||||
reset_from_location();
|
||||
reset_to_location();
|
||||
retrieve_warehouse('to');
|
||||
scan_sku_ready = false;
|
||||
scan_from_ready = false;
|
||||
scan_to_ready = false;
|
||||
pending_scan_lot = '';
|
||||
pending_scan_serial = '';
|
||||
$('#product_sku').focus();
|
||||
}
|
||||
|
||||
function save_scanned_stock_transfer() {
|
||||
if (!scan_sku_ready && !($('#product_sku').attr('secondary') || $('#product_sku').val())) {
|
||||
bootbox.alert('Scan the SKU label first.');
|
||||
return;
|
||||
}
|
||||
if (!scan_from_ready && !$('#rack_from').val()) {
|
||||
bootbox.alert('Scan the from-location label before saving.');
|
||||
return;
|
||||
}
|
||||
if (!scan_to_ready && !$('#rack_to').val()) {
|
||||
bootbox.alert('Scan the to-location label before saving.');
|
||||
return;
|
||||
}
|
||||
manage_stock_transfer();
|
||||
}
|
||||
|
||||
function load_location_config(callback) {
|
||||
return ajax_request({
|
||||
@@ -224,10 +356,16 @@
|
||||
'aisle_to': advanced ? $('#aisle_to').val() : rack_to_val,
|
||||
'rack_to': rack_to_val,
|
||||
'product_sku': sku_val,
|
||||
'lot_number': $('#lot_number').val(),
|
||||
'serial_number': $('#serial_number').val(),
|
||||
},
|
||||
action: 'manage',
|
||||
onSuccess: function() {
|
||||
<?php if(empty($_GET['id'])){ ?>
|
||||
reset_stock_transfer_inputs();
|
||||
<?php } else { ?>
|
||||
window.location.href = '<?php echo $server_url?>ics/stock_transfer.php';
|
||||
<?php } ?>
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -266,6 +404,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
action: 'read',
|
||||
data: { 'product_sku': sku },
|
||||
onSuccess: function(res) {
|
||||
@@ -276,8 +415,16 @@
|
||||
option += '<option value="' + item.lot_number + '">' + label + '</option>';
|
||||
});
|
||||
$('#lot_number').html(option).prop('disabled', false);
|
||||
if (pending_scan_lot) {
|
||||
set_select_value('#lot_number', pending_scan_lot, pending_scan_lot);
|
||||
}
|
||||
$('#serial_number').html('<option value="">Select serial... (optional)</option>').prop('disabled', false);
|
||||
reset_from_location();
|
||||
if (!scan_from_ready) reset_from_location();
|
||||
if (pending_scan_lot) {
|
||||
retrieve_active_serial();
|
||||
} else {
|
||||
retrieve_warehouse('from');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -292,6 +439,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
action: 'read',
|
||||
data: { 'product_sku': sku, 'lot_number': $('#lot_number').val() },
|
||||
onSuccess: function(res) {
|
||||
@@ -300,7 +448,12 @@
|
||||
option += '<option value="' + serial + '">' + serial + '</option>';
|
||||
});
|
||||
$('#serial_number').html(option).prop('disabled', false);
|
||||
reset_from_location();
|
||||
if (pending_scan_serial) {
|
||||
set_select_value('#serial_number', pending_scan_serial, pending_scan_serial);
|
||||
pending_scan_serial = '';
|
||||
}
|
||||
if (!scan_from_ready) reset_from_location();
|
||||
retrieve_warehouse('from');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -313,6 +466,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
data: {
|
||||
'type': type,
|
||||
'product_sku': type === 'from' ? ($('#product_sku').attr('secondary') || $('#product_sku').val()) : '',
|
||||
@@ -320,11 +474,13 @@
|
||||
},
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
var current = $('#warehouse_' + type).val();
|
||||
var option = '<option value="">Select warehouse...</option>';
|
||||
$.each(res.output, function(key, item) {
|
||||
option += '<option value="' + item.id + '">' + item.warehouse_name + '</option>';
|
||||
});
|
||||
$('select[name="warehouse"][role="' + type + '"]').html(option).prop('disabled', false);
|
||||
if (current) set_select_value('#warehouse_' + type, current, current);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -348,6 +504,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
data: Object.assign({ 'type': type }, extra),
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
@@ -380,6 +537,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
data: Object.assign({ 'type': type }, extra),
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
@@ -414,6 +572,7 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
queueLock: false,
|
||||
data: Object.assign({ 'type': type }, extra),
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
@@ -535,6 +694,14 @@
|
||||
await retrieve_warehouse('to');
|
||||
<?php } ?>
|
||||
await retrieve_for_edit();
|
||||
scanner.init({
|
||||
allowRaw: false,
|
||||
allowedTypes: ['sku', 'loc'],
|
||||
onScan: function(sku, product_name, uom, data) {
|
||||
if (data.type === 'sku') apply_sku_label_scan(data);
|
||||
if (data.type === 'loc') apply_location_label_scan(data);
|
||||
}
|
||||
});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
@@ -544,6 +711,13 @@
|
||||
// ── Change handlers (create mode only) ───────────────────────────────────
|
||||
<?php if(empty($_GET['id'])){ ?>
|
||||
|
||||
$(document).on('keydown', function(e) {
|
||||
if (e.key === 'F2') {
|
||||
e.preventDefault();
|
||||
save_scanned_stock_transfer();
|
||||
}
|
||||
});
|
||||
|
||||
$('input#product_sku').on('blur', function() {
|
||||
var sku = $(this).attr('secondary');
|
||||
if (!sku) return;
|
||||
|
||||
Reference in New Issue
Block a user