Change 'Rack' to 'Bin'

This commit is contained in:
Thanakorn S
2026-05-27 17:14:53 +07:00
parent b8798bc02d
commit 8f57ab5570
41 changed files with 931 additions and 933 deletions
@@ -8,7 +8,7 @@
$warehouse_id = (int)($data['warehouse_id'] ?? 0);
$zone = trim($data['zone'] ?? '');
$aisle = trim($data['aisle'] ?? '');
$rack = trim($data['rack'] ?? '');
$bin = trim($data['bin'] ?? '');
if ($label_action !== 'list') {
require_role($user_role, ['owner', 'admin', 'staff']);
@@ -56,14 +56,14 @@
}
// Default: create
if ($barcode === '' || !$warehouse_id || $rack === '') {
if ($barcode === '' || !$warehouse_id || $bin === '') {
$answer['message'] = 'Location barcode data is incomplete.';
http_response_code(400);
exit(json_encode($answer));
}
try {
$output = $bm->createLocationLabel($barcode, $warehouse_id, $zone, $aisle, $rack);
$output = $bm->createLocationLabel($barcode, $warehouse_id, $zone, $aisle, $bin);
$answer['success'] = 1;
$answer['output'] = $output;
} catch (Exception $e) {
+4 -4
View File
@@ -13,11 +13,11 @@
if (isset($data['warehouse_to']) && $type === 'to') { $warehouse = (int)$data['warehouse_to']; $zone = $data['zone_to'] ?? $zone; $aisle = $data['aisle_to'] ?? $aisle; }
if (!empty($data['id'])) {
$output = $whMgmt->getRacksAll($warehouse, $zone, $aisle);
$output = $whMgmt->getBinsAll($warehouse, $zone, $aisle);
} elseif ($type === 'to') {
$output = $whMgmt->getRacksIn($warehouse, $zone, $aisle);
$output = $whMgmt->getBinsIn($warehouse, $zone, $aisle);
} elseif ($type === 'from') {
$output = $whMgmt->getRacksOut(
$output = $whMgmt->getBinsOut(
$warehouse,
$zone,
$aisle,
@@ -26,7 +26,7 @@
$data['serial_number'] ?? null
);
} else {
$output = $whMgmt->getRacksAll($warehouse, $zone, $aisle);
$output = $whMgmt->getBinsAll($warehouse, $zone, $aisle);
}
$answer['output'] = $output;
+1 -1
View File
@@ -10,7 +10,7 @@
$id = (int)($data['id'] ?? 0);
// When type=from and a lot is selected, filter warehouses to only those
// holding that specific lot in an approved, rack-occupied stock-in row.
// holding that specific lot in an approved, bin-occupied stock-in row.
if ($type === 'from' && $sku && $lot) {
$answer['output'] = $wh->getWarehousesByLot($sku, $lot);
} else {
@@ -11,7 +11,7 @@
$warehouse_id = (int)($data['warehouse_id'] ?? 0);
$zone = trim($data['zone'] ?? '');
$aisle = trim($data['aisle'] ?? '');
$rack = trim($data['rack'] ?? '');
$bin = trim($data['bin'] ?? '');
$product_sku = trim($data['product_sku'] ?? '');
$lot_number = trim($data['lot_number'] ?? '');
$serial = trim($data['serial_number'] ?? '');
@@ -22,7 +22,7 @@
$warehouse_id,
$zone,
$aisle,
$rack,
$bin,
$product_sku,
$lot_number,
$serial
+43 -43
View File
@@ -18,7 +18,7 @@
<div class="col-12 d-flex justify-content-between align-items-center">
<div>
<h1 class="fs-3 mb-1">Location Barcode Labels</h1>
<p class="mb-0 text-muted">Print or reprint labels from the rack master list.</p>
<p class="mb-0 text-muted">Print or reprint labels from the bin master list.</p>
</div>
<div class="d-flex gap-2">
<button id="btn_print" class="btn btn-outline-success" data-min-role="staff" onclick="print_selected_label()" disabled>
@@ -39,7 +39,7 @@
<div class="card"><div class="card-body p-5">
<div class="position-relative mb-4">
<input type="search" id="search_location" class="form-control ps-9"
placeholder="Search warehouse, zone, aisle, rack, or SKU...">
placeholder="Search warehouse, zone, aisle, bin, or SKU...">
<span class="position-absolute top-25 ms-4">
<i class="ti ti-search text-muted"></i>
</span>
@@ -51,13 +51,13 @@
<th>Warehouse</th>
<th class="th-zone">Zone</th>
<th class="th-aisle">Aisle</th>
<th id="th-rack">Rack</th>
<th id="th-bin">Bin</th>
<th>Status</th>
<th>Label Status</th>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody id="rack_tbody">
<tbody id="bin_tbody">
<tr><td colspan="7" class="text-center text-muted py-4">Loading locations...</td></tr>
</tbody>
</table>
@@ -79,13 +79,13 @@
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/dist/JsBarcode.all.min.js"></script>
<script>
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
var racks = [];
var bins = [];
var barcode_status = {};
var selected_payload = '';
var selected_rack_index = -1;
var selected_bin_index = -1;
function escape_html(value) {
return String(value ?? '').replace(/[&<>"']/g, function(char) {
@@ -103,9 +103,9 @@
}
function highlight_selected_row() {
$('#rack_tbody tr').removeClass('table-active');
if (selected_rack_index >= 0) {
$('#rack_tbody tr[data-rack-index="' + selected_rack_index + '"]').addClass('table-active');
$('#bin_tbody tr').removeClass('table-active');
if (selected_bin_index >= 0) {
$('#bin_tbody tr[data-bin-index="' + selected_bin_index + '"]').addClass('table-active');
}
}
@@ -119,26 +119,26 @@
onSuccess: function(res) {
var s = res.output || {};
advanced = s.advanced_location == 1;
label_rack = s.location_label_rack || (advanced ? 'Rack' : 'Location');
label_bin = s.location_label_bin || (advanced ? 'Bin' : 'Location');
label_zone = s.location_label_zone || 'Zone';
label_aisle = s.location_label_aisle || 'Aisle';
$('.th-zone').text(label_zone).toggleClass('d-none', !advanced);
$('.th-aisle').text(label_aisle).toggleClass('d-none', !advanced);
$('#th-rack').text(label_rack);
$('#th-bin').text(label_bin);
}
});
}
function load_racks() {
function load_bins() {
return ajax_request({
url: server_url + 'reports/api/engine_report/rack_occupancy.php',
url: server_url + 'reports/api/engine_report/bin_occupancy.php',
autoPrepare: true,
checkRequired: 0,
action: 'read',
queueLock: false,
onSuccess: function(res) {
racks = res.output || [];
render_racks();
bins = res.output || [];
render_bins();
highlight_selected_row();
}
});
@@ -157,26 +157,26 @@
(res.output || []).forEach(function(item) {
barcode_status[item.barcode] = parseInt(item.status) === 1 ? 'active' : 'disabled';
});
render_racks();
render_bins();
}
});
}
function location_payload(item) {
return advanced
? `LOC|${item.warehouse_id}|${item.zone}|${item.aisle}|${item.rack}`
: `LOC|${item.warehouse_id}|${item.rack}`;
? `LOC|${item.warehouse_id}|${item.zone}|${item.aisle}|${item.bin}`
: `LOC|${item.warehouse_id}|${item.bin}`;
}
function render_racks() {
function render_bins() {
var keyword = $('#search_location').val().toLowerCase();
var rows = racks.filter(function(item) {
var rows = bins.filter(function(item) {
if (!keyword) return true;
return [
item.warehouse_name,
item.zone,
item.aisle,
item.rack,
item.bin,
item.product_sku,
item.product_name,
item.status
@@ -184,13 +184,13 @@
});
if (!rows.length) {
$('#rack_tbody').html('<tr><td colspan="7" class="text-center text-muted py-4">No locations found.</td></tr>');
$('#bin_tbody').html('<tr><td colspan="7" class="text-center text-muted py-4">No locations found.</td></tr>');
return;
}
var body = '';
rows.forEach(function(item) {
var idx = racks.indexOf(item);
var idx = bins.indexOf(item);
var status = item.status === 'occupied'
? '<span class="badge bg-warning text-dark">Occupied</span>'
: '<span class="badge bg-success">Empty</span>';
@@ -202,11 +202,11 @@
if (barcode_status[payload] === 'disabled') {
labelStatus = '<span class="badge bg-danger">Disabled</span>';
}
body += `<tr data-rack-index="${idx}">
body += `<tr data-bin-index="${idx}">
<td>${escape_html(item.warehouse_name)}</td>
<td class="th-zone ${advanced ? '' : 'd-none'}">${escape_html(item.zone)}</td>
<td class="th-aisle ${advanced ? '' : 'd-none'}">${escape_html(item.aisle)}</td>
<td>${escape_html(item.rack)}</td>
<td>${escape_html(item.bin)}</td>
<td>${status}</td>
<td>${labelStatus}</td>
<td class="text-end">
@@ -216,7 +216,7 @@
</td>
</tr>`;
});
$('#rack_tbody').html(body);
$('#bin_tbody').html(body);
}
function render_preview(item, payload) {
@@ -224,8 +224,8 @@
<div class="barcode-label mx-auto">
<div class="fw-bold fs-5">${escape_html(item.warehouse_name)}</div>
<div class="small">${advanced
? `${escape_html(item.zone)} / ${escape_html(item.aisle)} / ${escape_html(item.rack)}`
: escape_html(item.rack)}</div>
? `${escape_html(item.zone)} / ${escape_html(item.aisle)} / ${escape_html(item.bin)}`
: escape_html(item.bin)}</div>
<svg id="barcode_svg"></svg>
<div class="small text-muted">${escape_html(payload)}</div>
</div>`);
@@ -233,7 +233,7 @@
}
function preview_label(index) {
var item = racks[index];
var item = bins[index];
if (!item) return;
var payload = location_payload(item);
@@ -249,13 +249,13 @@
warehouse_id: item.warehouse_id,
zone: item.zone || '',
aisle: item.aisle || '',
rack: item.rack
bin: item.bin
},
onSuccess: function() {
selected_payload = payload;
selected_rack_index = index;
selected_bin_index = index;
if (!barcode_status[payload]) barcode_status[payload] = 'active';
render_racks();
render_bins();
refresh_header_buttons();
highlight_selected_row();
render_preview(item, payload);
@@ -303,9 +303,9 @@
onSuccess: function() {
barcode_status[selected_payload] = 'disabled';
selected_payload = '';
selected_rack_index = -1;
selected_bin_index = -1;
$('#label_preview').html('Select a location to preview its label.');
render_racks();
render_bins();
refresh_header_buttons();
highlight_selected_row();
}
@@ -316,8 +316,8 @@
function reenable_selected_label() {
if (!selected_payload) return;
var index = selected_rack_index;
var item = racks[index];
var index = selected_bin_index;
var item = bins[index];
if (!item) return;
ajax_request({
@@ -329,7 +329,7 @@
data: { label_action: 'enable', barcode: selected_payload },
onSuccess: function() {
barcode_status[selected_payload] = 'active';
render_racks();
render_bins();
refresh_header_buttons();
highlight_selected_row();
render_preview(item, selected_payload);
@@ -338,7 +338,7 @@
}
function enable_label_for_row(index) {
var item = racks[index];
var item = bins[index];
if (!item) return;
var payload = location_payload(item);
@@ -352,8 +352,8 @@
onSuccess: function() {
barcode_status[payload] = 'active';
selected_payload = payload;
selected_rack_index = index;
render_racks();
selected_bin_index = index;
render_bins();
refresh_header_buttons();
highlight_selected_row();
render_preview(item, payload);
@@ -361,11 +361,11 @@
});
}
$('#search_location').on('input', render_racks);
$('#search_location').on('input', render_bins);
$(async function() {
await load_config();
await load_racks();
await load_bins();
await load_barcode_statuses();
});
</script>
+33 -33
View File
@@ -97,10 +97,10 @@
</select>
</div>
<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>
<option value="">Please select rack</option>
<div class="mb-3 col-lg-6" id="group_bin">
<label for="bin" class="form-label" id="label_bin">Bin</label>
<select name="bin" id="bin" class="form-select" required>
<option value="">Please select bin</option>
</select>
</div>
@@ -137,7 +137,7 @@
// custom.js globals: set_select_value(), load_location_config(), init_lot_search_inputs()
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
var scan_sku_ready = false;
@@ -150,15 +150,15 @@
$('#group_aisle').show();
$('#label_zone').text(label_zone);
$('#label_aisle').text(label_aisle);
$('#label_rack').text(label_rack);
$('#label_bin').text(label_bin);
$('#zone').attr('placeholder', 'Please select ' + label_zone.toLowerCase());
$('#aisle').attr('placeholder', 'Please select ' + label_aisle.toLowerCase());
$('#rack').attr('placeholder', 'Please select ' + label_rack.toLowerCase());
$('#bin').attr('placeholder', 'Please select ' + label_bin.toLowerCase());
} else {
$('#group_zone').hide();
$('#group_aisle').hide();
$('#label_rack').text(label_rack);
$('#rack').attr('placeholder', 'Please select ' + label_rack.toLowerCase());
$('#label_bin').text(label_bin);
$('#bin').attr('placeholder', 'Please select ' + label_bin.toLowerCase());
}
}
@@ -174,7 +174,7 @@
$('#warehouse').val('');
$('#zone').val('');
$('#aisle').val('');
$('#rack').val('');
$('#bin').val('');
$('#product_sku').trigger('blur');
}
@@ -189,7 +189,7 @@
set_select_value('#zone', data.zone, data.zone);
set_select_value('#aisle', data.aisle, data.aisle);
}
set_select_value('#rack', data.rack, data.rack);
set_select_value('#bin', data.bin, data.bin);
scan_location_ready = true;
});
}
@@ -207,7 +207,7 @@
warehouse_id: data.warehouse_id,
zone: data.zone,
aisle: data.aisle,
rack: data.rack,
bin: data.bin,
product_sku: $('#product_sku').attr('secondary') || $('#product_sku').val(),
lot_number: $('#lot_number').val(),
serial_number: $('#serial_number').val()
@@ -230,7 +230,7 @@
$('#warehouse').val('');
$('#zone').val('');
$('#aisle').val('');
$('#rack').val('');
$('#bin').val('');
scan_sku_ready = false;
scan_location_ready = false;
$('#product_sku').focus();
@@ -241,7 +241,7 @@
bootbox.alert('Scan the SKU label first.');
return;
}
if (!scan_location_ready && !$('#rack').val()) {
if (!scan_location_ready && !$('#bin').val()) {
bootbox.alert('Scan the location label before saving.');
return;
}
@@ -250,17 +250,17 @@
function manage_stock_in() {
var rack_val = $('#rack').val();
var zone_val = advanced ? $('#zone').val() : rack_val;
var aisle_val = advanced ? $('#aisle').val() : rack_val;
var bin_val = $('#bin').val();
var zone_val = advanced ? $('#zone').val() : bin_val;
var aisle_val = advanced ? $('#aisle').val() : bin_val;
var warehouse_val = $('#warehouse').val();
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
var quantity_val = $('#quantity').val();
// Mirror to hidden inputs for autoPrepare consistency (simple mode)
if (!advanced) {
$('#zone').val(rack_val);
$('#aisle').val(rack_val);
$('#zone').val(bin_val);
$('#aisle').val(bin_val);
}
return ajax_request({
@@ -275,7 +275,7 @@
'serial_number': $('#serial_number').val(),
'zone': zone_val,
'aisle': aisle_val,
'rack': rack_val,
'bin': bin_val,
'product_sku': sku_val,
'quantity': quantity_val,
'warehouse': warehouse_val,
@@ -398,10 +398,10 @@
function retrieve_rack(type, callback) {
function retrieve_bin(type, callback) {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_rack.php",
url: "<?php echo $server_url?>ics/api/engine/retrieve_bin.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
@@ -411,11 +411,11 @@
},
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_rack.toLowerCase() + '</option>';
var option = '<option value="">Please select ' + label_bin.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += '<option value="' + item + '">' + item + '</option>';
});
$('select#rack').html(option);
$('select#bin').html(option);
if (callback) callback(); // ← add this
}
@@ -445,7 +445,7 @@
function populate_fields() {
$.each(data, function(key, item) {
if (!['warehouse', 'zone', 'aisle', 'rack'].includes(key)) {
if (!['warehouse', 'zone', 'aisle', 'bin'].includes(key)) {
$('#' + key).val(item);
}
});
@@ -478,16 +478,16 @@
$('select#zone').val(data.zone).attr('disabled', true);
retrieve_aisle('to', function() {
$('#aisle').val(data.aisle).attr('disabled', true);
retrieve_rack('to', function() {
$('#rack').val(data.rack).attr('disabled', true);
retrieve_bin('to', function() {
$('#bin').val(data.bin).attr('disabled', true);
populate_fields();
});
});
});
} else {
// Simple mode — skip zone/aisle cascade
retrieve_rack('to', function() {
$('#rack').val(data.rack).attr('disabled', true);
retrieve_bin('to', function() {
$('#bin').val(data.bin).attr('disabled', true);
populate_fields();
});
}
@@ -536,11 +536,11 @@
if (advanced) {
retrieve_zone('to', function() {
retrieve_aisle('to', function() {
retrieve_rack('to');
retrieve_bin('to');
});
});
} else {
retrieve_rack('to');
retrieve_bin('to');
}
}
@@ -615,7 +615,7 @@
if (advanced) {
retrieve_zone('to');
} else {
retrieve_rack('to');
retrieve_bin('to');
}
});
@@ -624,7 +624,7 @@
});
$("select#aisle").change(function() {
if (advanced) retrieve_rack('to');
if (advanced) retrieve_bin('to');
});
<?php } ?>
+32 -32
View File
@@ -85,11 +85,11 @@
</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>
<!-- Step 7: Bin -->
<div class="mb-3 col-lg-6" id="group_bin">
<label for="bin" class="form-label" id="label_bin">Bin</label>
<select name="bin" id="bin" class="form-select" required disabled>
<option value="">Please select bin</option>
</select>
</div>
@@ -124,7 +124,7 @@
// custom.js globals: set_select_value(), load_location_config()
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
var scan_sku_ready = false;
@@ -157,7 +157,7 @@
set_select_value('#zone', data.zone, data.zone);
set_select_value('#aisle', data.aisle, data.aisle);
}
set_select_value('#rack', data.rack, data.rack);
set_select_value('#bin', data.bin, data.bin);
scan_location_ready = true;
});
}
@@ -175,7 +175,7 @@
warehouse_id: data.warehouse_id,
zone: data.zone,
aisle: data.aisle,
rack: data.rack,
bin: data.bin,
product_sku: $('#product_sku').attr('secondary') || $('#product_sku').val(),
lot_number: $('#lot_number').val(),
serial_number: $('#serial_number').val()
@@ -204,7 +204,7 @@
bootbox.alert('Scan the SKU label first.');
return;
}
if (!scan_location_ready && !$('#rack').val()) {
if (!scan_location_ready && !$('#bin').val()) {
bootbox.alert('Scan the location label before saving.');
return;
}
@@ -218,22 +218,22 @@
$('#group_aisle').show();
$('#label_zone').text(label_zone);
$('#label_aisle').text(label_aisle);
$('#label_rack').text(label_rack);
$('#label_bin').text(label_bin);
} else {
$('#group_zone').hide();
$('#group_aisle').hide();
$('#label_rack').text(label_rack);
$('#label_bin').text(label_bin);
}
}
function manage_stock_out() {
var rack_val = $('#rack').val();
var bin_val = $('#bin').val();
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
var wh_val = $('#warehouse').val();
if (!advanced) {
$('#zone').val(rack_val);
$('#aisle').val(rack_val);
$('#zone').val(bin_val);
$('#aisle').val(bin_val);
}
return ajax_request({
@@ -243,9 +243,9 @@
debugMode: 0,
data: {
'contact_id': $('#contact').attr('data-id'),
'zone': advanced ? $('#zone').val() : rack_val,
'aisle': advanced ? $('#aisle').val() : rack_val,
'rack': rack_val,
'zone': advanced ? $('#zone').val() : bin_val,
'aisle': advanced ? $('#aisle').val() : bin_val,
'bin': bin_val,
'product_sku': sku_val,
'warehouse': wh_val,
'lot_number': $('#lot_number').val(),
@@ -391,7 +391,7 @@
}
// ── Steps 5-7: Zone → Aisle → Rack ───────────────────────────────────
// ── Steps 5-7: Zone → Aisle → Bin ───────────────────────────────────
function retrieve_zone(callback) {
return ajax_request({
@@ -447,10 +447,10 @@
});
}
function retrieve_rack(callback) {
function retrieve_bin(callback) {
return ajax_request({
url: "<?php echo $server_url?>ics/api/engine/retrieve_rack.php",
url: "<?php echo $server_url?>ics/api/engine/retrieve_bin.php",
autoPrepare: true,
checkRequired: 0,
noLoading: true,
@@ -466,11 +466,11 @@
},
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_rack.toLowerCase() + '</option>';
var option = '<option value="">Please select ' + label_bin.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += `<option value='${item}'>${item}</option>`;
});
$('#rack').html(option).prop('disabled', false);
$('#bin').html(option).prop('disabled', false);
if (callback) callback();
}
});
@@ -482,7 +482,7 @@
$('#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);
$('#bin').html('<option value="">Please select ' + label_bin.toLowerCase() + '</option>').prop('disabled', true);
}
@@ -513,7 +513,7 @@
function populate_fields() {
$.each(data, function(key, item) {
if (!['warehouse', 'zone', 'aisle', 'rack', 'lot_number', 'serial_number'].includes(key)) {
if (!['warehouse', 'zone', 'aisle', 'bin', 'lot_number', 'serial_number'].includes(key)) {
$('#' + key).val(item);
}
});
@@ -534,16 +534,16 @@
$('#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);
retrieve_bin(function() {
$('#bin').val(data.bin).prop('disabled', true);
populate_fields();
});
});
});
} else {
// Simple mode — skip zone/aisle cascade
retrieve_rack(function() {
$('#rack').val(data.rack).prop('disabled', true);
retrieve_bin(function() {
$('#bin').val(data.bin).prop('disabled', true);
populate_fields();
});
}
@@ -600,12 +600,12 @@
retrieve_warehouse();
});
// Warehouse selected → load zone (advanced) or rack directly (simple)
// Warehouse selected → load zone (advanced) or bin directly (simple)
$('#warehouse').on('change', function() {
if (advanced) {
retrieve_zone();
} else {
retrieve_rack();
retrieve_bin();
}
});
@@ -614,9 +614,9 @@
if (advanced) retrieve_aisle();
});
// Aisle selected → load rack (advanced only)
// Aisle selected → load bin (advanced only)
$('#aisle').on('change', function() {
if (advanced) retrieve_rack();
if (advanced) retrieve_bin();
});
<?php } ?>
+56 -56
View File
@@ -87,9 +87,9 @@
</select>
</div>
<div class="mb-3 col-lg-3">
<label class="form-label" id="label_rack_from">From Rack</label>
<select name="rack" id="rack_from" role="from" class="form-select" required disabled>
<option value="">Please select rack</option>
<label class="form-label" id="label_bin_from">From Bin</label>
<select name="bin" id="bin_from" role="from" class="form-select" required disabled>
<option value="">Please select bin</option>
</select>
</div>
@@ -119,9 +119,9 @@
</select>
</div>
<div class="mb-3 col-lg-3">
<label class="form-label" id="label_rack_to">To Rack</label>
<select name="rack" id="rack_to" role="to" class="form-select" required>
<option value="">Please select rack</option>
<label class="form-label" id="label_bin_to">To Bin</label>
<select name="bin" id="bin_to" role="to" class="form-select" required>
<option value="">Please select bin</option>
</select>
</div>
@@ -157,7 +157,7 @@
// ── Location config ───────────────────────────────────────────────────────
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
var scan_sku_ready = false;
@@ -200,7 +200,7 @@
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);
set_select_value('#bin_' + role, data.bin, data.bin);
if (role === 'from') {
scan_from_ready = true;
@@ -214,7 +214,7 @@
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);
&& String($('#bin_from').val()) === String(data.bin);
}
function validate_scanned_location(role, data, onSuccess) {
@@ -230,7 +230,7 @@
warehouse_id: data.warehouse_id,
zone: data.zone,
aisle: data.aisle,
rack: data.rack,
bin: data.bin,
product_sku: $('#product_sku').attr('secondary') || $('#product_sku').val(),
lot_number: $('#lot_number').val(),
serial_number: $('#serial_number').val()
@@ -243,7 +243,7 @@
$('#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('');
$('#bin_to').html('<option value="">Please select ' + label_bin.toLowerCase() + '</option>').val('');
}
function reset_stock_transfer_inputs() {
@@ -269,11 +269,11 @@
bootbox.alert('Scan the SKU label first.');
return;
}
if (!scan_from_ready && !$('#rack_from').val()) {
if (!scan_from_ready && !$('#bin_from').val()) {
bootbox.alert('Scan the from-location label before saving.');
return;
}
if (!scan_to_ready && !$('#rack_to').val()) {
if (!scan_to_ready && !$('#bin_to').val()) {
bootbox.alert('Scan the to-location label before saving.');
return;
}
@@ -290,19 +290,19 @@
$('#label_zone_to').text('To ' + label_zone);
$('#label_aisle_from').text('From ' + label_aisle);
$('#label_aisle_to').text('To ' + label_aisle);
$('#label_rack_from').text('From ' + label_rack);
$('#label_rack_to').text('To ' + label_rack);
$('#label_bin_from').text('From ' + label_bin);
$('#label_bin_to').text('To ' + label_bin);
// Update select placeholders
$('#zone_from, #zone_to').find('option:first').text('Please select ' + label_zone.toLowerCase());
$('#aisle_from, #aisle_to').find('option:first').text('Please select ' + label_aisle.toLowerCase());
$('#rack_from, #rack_to').find('option:first').text('Please select ' + label_rack.toLowerCase());
$('#bin_from, #bin_to').find('option:first').text('Please select ' + label_bin.toLowerCase());
} else {
$('#group_zone_from, #group_zone_to').hide();
$('#group_aisle_from, #group_aisle_to').hide();
$('#zone_from, #zone_to, #aisle_from, #aisle_to').prop('required', false).removeClass('is-invalid is-valid');
$('#label_rack_from').text('From ' + label_rack);
$('#label_rack_to').text('To ' + label_rack);
$('#rack_from, #rack_to').find('option:first').text('Please select ' + label_rack.toLowerCase());
$('#label_bin_from').text('From ' + label_bin);
$('#label_bin_to').text('To ' + label_bin);
$('#bin_from, #bin_to').find('option:first').text('Please select ' + label_bin.toLowerCase());
}
}
@@ -310,16 +310,16 @@
// ── Submit ────────────────────────────────────────────────────────────────
function manage_stock_transfer() {
var rack_from_val = $('#rack_from').val();
var rack_to_val = $('#rack_to').val();
var bin_from_val = $('#bin_from').val();
var bin_to_val = $('#bin_to').val();
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
// Simple mode — mirror rack value to zone and aisle before submit
// Simple mode — mirror bin value to zone and aisle before submit
if (!advanced) {
$('#zone_from').val(rack_from_val);
$('#aisle_from').val(rack_from_val);
$('#zone_to').val(rack_to_val);
$('#aisle_to').val(rack_to_val);
$('#zone_from').val(bin_from_val);
$('#aisle_from').val(bin_from_val);
$('#zone_to').val(bin_to_val);
$('#aisle_to').val(bin_to_val);
}
return ajax_request({
@@ -330,12 +330,12 @@
'contact_id': $('#contact').attr('data-id'),
'warehouse_from': $('#warehouse_from').val(),
'warehouse_to': $('#warehouse_to').val(),
'zone_from': advanced ? $('#zone_from').val() : rack_from_val,
'aisle_from': advanced ? $('#aisle_from').val() : rack_from_val,
'rack_from': rack_from_val,
'zone_to': advanced ? $('#zone_to').val() : rack_to_val,
'aisle_to': advanced ? $('#aisle_to').val() : rack_to_val,
'rack_to': rack_to_val,
'zone_from': advanced ? $('#zone_from').val() : bin_from_val,
'aisle_from': advanced ? $('#aisle_from').val() : bin_from_val,
'bin_from': bin_from_val,
'zone_to': advanced ? $('#zone_to').val() : bin_to_val,
'aisle_to': advanced ? $('#aisle_to').val() : bin_to_val,
'bin_to': bin_to_val,
'product_sku': sku_val,
'lot_number': $('#lot_number').val(),
'serial_number': $('#serial_number').val(),
@@ -467,7 +467,7 @@
}
// ── Zone / Aisle / Rack loaders ───────────────────────────────────────────
// ── Zone / Aisle / Bin loaders ───────────────────────────────────────────
function retrieve_zone(type, callback) {
var extra = {
'warehouse_from': $('#warehouse_from').val(),
@@ -532,7 +532,7 @@
});
}
function retrieve_rack(type, callback) {
function retrieve_bin(type, callback) {
var extra = {
'warehouse_from': $('#warehouse_from').val(),
'warehouse_to': $('#warehouse_to').val(),
@@ -549,7 +549,7 @@
});
}
return ajax_request({
url: '<?php echo $server_url?>ics/api/engine/retrieve_rack.php',
url: '<?php echo $server_url?>ics/api/engine/retrieve_bin.php',
autoPrepare: true,
checkRequired: 0,
noLoading: true,
@@ -557,11 +557,11 @@
data: Object.assign({ 'type': type }, extra),
action: 'read',
onSuccess: function(res) {
var option = '<option value="">Please select ' + label_rack.toLowerCase() + '</option>';
var option = '<option value="">Please select ' + label_bin.toLowerCase() + '</option>';
$.each(res.output, function(key, item) {
option += '<option value="' + item + '">' + item + '</option>';
});
$('select[name="rack"][role="' + type + '"]').html(option).prop('disabled', false);
$('select[name="bin"][role="' + type + '"]').html(option).prop('disabled', false);
if (callback) callback();
}
});
@@ -573,7 +573,7 @@
$('#warehouse_from').html('<option value="">Select warehouse...</option>').prop('disabled', true);
$('#zone_from').html('<option value="">Please select ' + label_zone.toLowerCase() + '</option>').prop('disabled', true);
$('#aisle_from').html('<option value="">Please select ' + label_aisle.toLowerCase() + '</option>').prop('disabled', true);
$('#rack_from').html('<option value="">Please select ' + label_rack.toLowerCase() + '</option>').prop('disabled', true);
$('#bin_from').html('<option value="">Please select ' + label_bin.toLowerCase() + '</option>').prop('disabled', true);
}
@@ -616,23 +616,23 @@
$('select[name="zone"][role="from"]').val(data.zone).prop('disabled', true);
retrieve_aisle('from', function() {
$('select[name="aisle"][role="from"]').val(data.aisle).prop('disabled', true);
retrieve_rack('from', function() {
$('select[name="rack"][role="from"]').val(data.rack).prop('disabled', true);
retrieve_bin('from', function() {
$('select[name="bin"][role="from"]').val(data.bin).prop('disabled', true);
populate_to_side(data, to_wh);
});
});
});
} else {
// Simple mode — skip zone/aisle cascade, load rack directly
retrieve_rack('from', function() {
$('select[name="rack"][role="from"]').val(data.rack).prop('disabled', true);
// Simple mode — skip zone/aisle cascade, load bin directly
retrieve_bin('from', function() {
$('select[name="bin"][role="from"]').val(data.bin).prop('disabled', true);
populate_to_side_simple(data, to_wh);
});
}
// Common fields
$.each(data, function(key, item) {
if (!['warehouse', 'zone', 'aisle', 'rack', 'lot_number', 'serial_number', 'ref'].includes(key)) {
if (!['warehouse', 'zone', 'aisle', 'bin', 'lot_number', 'serial_number', 'ref'].includes(key)) {
$('#' + key).val(item);
}
});
@@ -655,16 +655,16 @@
$('select[name="zone"][role="to"]').val(data.ref.zone).prop('disabled', true);
retrieve_aisle('to', function() {
$('select[name="aisle"][role="to"]').val(data.ref.aisle).prop('disabled', true);
retrieve_rack('to', function() {
$('select[name="rack"][role="to"]').val(data.ref.rack).prop('disabled', true);
retrieve_bin('to', function() {
$('select[name="bin"][role="to"]').val(data.ref.bin).prop('disabled', true);
});
});
});
}
function populate_to_side_simple(data, to_wh) {
retrieve_rack('to', function() {
$('select[name="rack"][role="to"]').val(data.ref.rack).prop('disabled', true);
retrieve_bin('to', function() {
$('select[name="bin"][role="to"]').val(data.ref.bin).prop('disabled', true);
});
}
@@ -717,9 +717,9 @@
retrieve_warehouse('from');
});
// From warehouse → zone (advanced) or rack directly (simple)
// From warehouse → zone (advanced) or bin directly (simple)
$('select[name="warehouse"][role="from"]').on('change', function() {
if (advanced) { retrieve_zone('from'); } else { retrieve_rack('from'); }
if (advanced) { retrieve_zone('from'); } else { retrieve_bin('from'); }
});
// From zone → aisle (advanced only)
@@ -727,14 +727,14 @@
if (advanced) retrieve_aisle('from');
});
// From aisle → rack (advanced only)
// From aisle → bin (advanced only)
$('select[name="aisle"][role="from"]').on('change', function() {
if (advanced) retrieve_rack('from');
if (advanced) retrieve_bin('from');
});
// To warehouse → zone (advanced) or rack directly (simple)
// To warehouse → zone (advanced) or bin directly (simple)
$('select[name="warehouse"][role="to"]').on('change', function() {
if (advanced) { retrieve_zone('to'); } else { retrieve_rack('to'); }
if (advanced) { retrieve_zone('to'); } else { retrieve_bin('to'); }
});
// To zone → aisle (advanced only)
@@ -742,9 +742,9 @@
if (advanced) retrieve_aisle('to');
});
// To aisle → rack (advanced only)
// To aisle → bin (advanced only)
$('select[name="aisle"][role="to"]').on('change', function() {
if (advanced) retrieve_rack('to');
if (advanced) retrieve_bin('to');
});
<?php } ?>
+7 -7
View File
@@ -64,7 +64,7 @@
<th>Source</th>
<th class="th_loc_zone">Zone</th>
<th class="th_loc_aisle">Aisle</th>
<th class="th_loc_rack">Rack</th>
<th class="th_loc_bin">Bin</th>
<th>Status</th>
<th>Action</th>
</tr>
@@ -90,7 +90,7 @@
<script>
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
@@ -98,10 +98,10 @@
if (advanced) {
$('.th_loc_zone').text(label_zone).show();
$('.th_loc_aisle').text(label_aisle).show();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
} else {
$('.th_loc_zone, .th_loc_aisle').hide();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
}
}
@@ -109,9 +109,9 @@
if (advanced) {
return `<td class="py-3">${item['zone'] || ''}</td>
<td class="py-3">${item['aisle'] || ''}</td>
<td class="py-3">${item['rack'] || ''}</td>`;
<td class="py-3">${item['bin'] || ''}</td>`;
}
return `<td class="py-3">${item['rack'] || ''}</td>`;
return `<td class="py-3">${item['bin'] || ''}</td>`;
}
function escape_html(value) {
@@ -309,7 +309,7 @@
var s = res.output || {};
auto_approve = s.default_stock_status == 1;
advanced = s.advanced_location == 1;
label_rack = s.location_label_rack || (advanced ? 'Rack' : 'Location');
label_bin = s.location_label_bin || (advanced ? 'Bin' : 'Location');
label_zone = s.location_label_zone || 'Zone';
label_aisle = s.location_label_aisle || 'Aisle';
apply_location_labels();
+7 -7
View File
@@ -63,7 +63,7 @@
<th>Source</th>
<th class="th_loc_zone">Zone</th>
<th class="th_loc_aisle">Aisle</th>
<th class="th_loc_rack">Rack</th>
<th class="th_loc_bin">Bin</th>
<th>Status</th>
<th>Action</th>
</tr>
@@ -89,7 +89,7 @@
<script>
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
@@ -97,10 +97,10 @@
if (advanced) {
$('.th_loc_zone').text(label_zone).show();
$('.th_loc_aisle').text(label_aisle).show();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
} else {
$('.th_loc_zone, .th_loc_aisle').hide();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
}
}
@@ -108,9 +108,9 @@
if (advanced) {
return `<td class="py-3">${item['zone'] || ''}</td>
<td class="py-3">${item['aisle'] || ''}</td>
<td class="py-3">${item['rack'] || ''}</td>`;
<td class="py-3">${item['bin'] || ''}</td>`;
}
return `<td class="py-3">${item['rack'] || ''}</td>`;
return `<td class="py-3">${item['bin'] || ''}</td>`;
}
function escape_html(value) {
@@ -329,7 +329,7 @@
var s = res.output || {};
auto_approve = s.default_stock_status == 1;
advanced = s.advanced_location == 1;
label_rack = s.location_label_rack || (advanced ? 'Rack' : 'Location');
label_bin = s.location_label_bin || (advanced ? 'Bin' : 'Location');
label_zone = s.location_label_zone || 'Zone';
label_aisle = s.location_label_aisle || 'Aisle';
apply_location_labels();
+1 -1
View File
@@ -42,7 +42,7 @@
<div>
<span class="mb-4 d-block">Total Capacity</span>
<h3 class="fw-bold mb-0 text-info" id="stat_capacity">—</h3>
<p class="mb-0 small text-secondary" id="stat_capacity_sub">Racks in warehouse</p>
<p class="mb-0 small text-secondary" id="stat_capacity_sub">Bins in warehouse</p>
</div>
<i class="ti ti-box-seam fs-3 text-muted"></i>
</div>
+7 -7
View File
@@ -52,7 +52,7 @@
<th style="text-align: right;">Quantity</th>
<th class="th_loc_zone">Zone</th>
<th class="th_loc_aisle">Aisle</th>
<th class="th_loc_rack">Rack</th>
<th class="th_loc_bin">Bin</th>
<th>Status</th>
<th>Action</th>
</tr>
@@ -78,7 +78,7 @@
<script>
var advanced = false;
var label_rack = 'Location';
var label_bin = 'Location';
var label_zone = 'Zone';
var label_aisle = 'Aisle';
@@ -86,10 +86,10 @@
if (advanced) {
$('.th_loc_zone').text(label_zone).show();
$('.th_loc_aisle').text(label_aisle).show();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
} else {
$('.th_loc_zone, .th_loc_aisle').hide();
$('.th_loc_rack').text(label_rack);
$('.th_loc_bin').text(label_bin);
}
}
@@ -97,9 +97,9 @@
if (advanced) {
return `<td class="py-3">${item['zone'] || ''}</td>
<td class="py-3">${item['aisle'] || ''}</td>
<td class="py-3">${item['rack'] || ''}</td>`;
<td class="py-3">${item['bin'] || ''}</td>`;
}
return `<td class="py-3">${item['rack'] || ''}</td>`;
return `<td class="py-3">${item['bin'] || ''}</td>`;
}
function retrieve_stock_transfer() {
@@ -240,7 +240,7 @@
var s = res.output || {};
auto_approve = s.default_stock_status == 1;
advanced = s.advanced_location == 1;
label_rack = s.location_label_rack || (advanced ? 'Rack' : 'Location');
label_bin = s.location_label_bin || (advanced ? 'Bin' : 'Location');
label_zone = s.location_label_zone || 'Zone';
label_aisle = s.location_label_aisle || 'Aisle';
apply_location_labels();