[test] contact to setting modules

This commit is contained in:
Thanakorn S
2026-05-06 08:58:09 +07:00
parent 414f1cd81d
commit 6501d326ca
43 changed files with 4295 additions and 581 deletions
+96 -28
View File
@@ -31,10 +31,18 @@
<div class="mb-3 col-lg-2">
<input class="form-control" value='Warehouse' disabled>
</div>
<div class="mb-3 col-lg-4">
<div class="mb-3 col-lg-2">
<select name="warehouse" id="warehouse" class="form-select" required></select>
</div>
<div class="mb-3 col-lg-6">
<div class="mb-3 col-lg-2">
<input class="form-control" value='Source' disabled>
</div>
<div class="mb-3 col-lg-2">
<select name="source" id="source" class="form-select">
<option value="">All Sources</option>
</select>
</div>
<div class="mb-3 col-lg-2">
<button class='btn btn-secondary' onclick='retrieve_stock_out()'>Search</button>
</div>
@@ -50,7 +58,8 @@
<th>Product</th>
<th>Lot Number</th>
<th>Serial Number</th>
<th>Quantity</th>
<th style="text-align: right;">Quantity</th>
<th>Source</th>
<th class="th_loc_zone">Zone</th>
<th class="th_loc_aisle">Aisle</th>
<th class="th_loc_rack">Rack</th>
@@ -103,6 +112,70 @@
return `<td class="py-3">${item['rack'] || ''}</td>`;
}
function escape_html(value) {
return String(value ?? '').replace(/[&<>"']/g, function(char) {
return {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
}[char];
});
}
function source_label(source) {
source = source || '';
if (!source) return 'Manual';
return source.charAt(0).toUpperCase() + source.slice(1).replace(/_/g, ' ');
}
function source_cell(source) {
var label = escape_html(source_label(source));
return source
? `<span class="badge bg-info-subtle text-info">${label}</span>`
: `<span class="badge bg-secondary-subtle text-secondary">${label}</span>`;
}
function populate_source_filter(rows) {
var current = $('#source').val() || '';
var sources = {};
$.each(rows, function(_, item) {
sources[item.source || '__manual__'] = item.source || '';
});
var option = `<option value="">All Sources</option>`;
$.each(Object.keys(sources).sort(), function(_, key) {
var value = sources[key];
var option_value = value || '__manual__';
option += `<option value="${escape_html(option_value)}">${escape_html(source_label(value))}</option>`;
});
$('#source').html(option).val(current);
if ($('#source').val() !== current) $('#source').val('');
}
function apply_source_filter() {
var selected = $('#source').val() || '';
var rows = alasql.tables.stock_out_all ? alasql.tables.stock_out_all.data : [];
if (!selected) {
alasql.tables.stock_out.data = rows;
} else {
alasql.tables.stock_out.data = rows.filter(function(item) {
var source = item.source || '';
return selected === '__manual__' ? !source : source === selected;
});
}
var table_id = 'stock_out';
var total_records = alasql.tables.stock_out.data.length;
var page = generate_pagination(table_id, total_records);
$(`table#${table_id} tfoot`).html(page);
change_page_stock_out(1);
}
function retrieve_stock_out() {
return ajax_request({
@@ -114,22 +187,12 @@
onSuccess: function(res) {
// Register the array as a table name
alasql('CREATE TABLE IF NOT EXISTS stock_out_all');
alasql('CREATE TABLE IF NOT EXISTS stock_out');
alasql.tables.stock_out.data = res.output || [];
alasql.tables.stock_out_all.data = res.output || [];
var total_records = alasql.tables.stock_out.data.length;
var table_id = 'stock_out';
var page = generate_pagination(table_id, total_records);
$(`table#${table_id} tfoot`).html(page);
// dynamic function name
if (typeof window[`change_page_${table_id}`] === "function") {
window[`change_page_${table_id}`](1);
} else {
console.error(`Function change_page_${table_id} does not exist.`);
}
populate_source_filter(alasql.tables.stock_out_all.data);
apply_source_filter();
}
});
@@ -153,19 +216,19 @@
<td class="py-3">${item["product_sku"]}: ${item['product_name']}</td>
<td class="py-3">${item['lot_number'] || '<span class="text-muted">—</span>'}</td>
<td class="py-3">${item['serial_number'] || '<span class="text-muted">—</span>'}</td>
<td class="py-3">${item['quantity']}</td>
<td class="py-3">
<div class="d-flex justify-content-end align-items-baseline gap-1">
<span>${format_number(item['quantity'], 2)}</span>
<span class="text-muted small" style="min-width:28px;">${item['uom'] || ''}</span>
</div>
</td>
<td class="py-3">${source_cell(item['source'])}</td>
${location_cells(item)}
<td class="py-3">
${item['status'] == 1 ? '<span class="badge bg-success">Approved</span>' : '<span class="badge bg-warning text-dark">Draft</span>'}
</td>
<td class="py-3">
<a href="<?php echo $server_url?>ics/manage_stock_out.php?id=${item['id']}&wh=${warehouse}" class=""><i class="ti ti-eye fs-5"></i></a>
${item['status'] == 0
? (auto_approve
? '<button class="btn btn-sm btn-outline-secondary ms-2" disabled title="Auto-approved on save — no manual approval needed"><i class=\"ti ti-check\"></i></button>'
: '<button class="btn btn-sm btn-outline-success ms-2" onclick=\"approve_stock('+item['id']+', '+item['warehouse_id']+', \'out\')\" title="Approve"><i class=\"ti ti-check\"></i></button>'
)
: ''}
<a href="javascript:void(0);" class="link-danger"
onclick="delete_stock_out($(this),${item['id']})">
<i class="ti ti-trash ms-2 fs-5"></i>
@@ -225,6 +288,9 @@
console.log(e);
}
});
$(document).on('change', '#source', apply_source_filter);
$(document).on('change', '#warehouse', retrieve_stock_out);
// ── Stock approval ────────────────────────────────────────────────────────
var auto_approve = false; // set from company_setting on load
@@ -258,11 +324,13 @@
autoPrepare: true,
checkRequired: 0,
action: 'update',
id: id,
warehouse: warehouse_id,
type: type,
data: {
id: id,
warehouse: warehouse_id,
type: type
},
onSuccess: function(res) {
retrieve_stock_list();
retrieve_stock_out();
}
});
}