Fix QA review findings: server-side validation, notes encoding, dashboard totals

Validate document lines on the server and recompute their totals, store notes with quotes/markup/emoji (utf8mb4, idempotent escaping, decode in form fields), exclude transfers from company-wide stock in/out, count revenue from confirmed orders only, one low-stock rule everywhere, list unapproved lots, natural bin sort, stable order/PO sort, status tiles that add up.
This commit is contained in:
Thanakorn
2026-09-19 10:58:42 +07:00
parent de760d02da
commit c89b28da4c
32 changed files with 924 additions and 483 deletions
+12 -1
View File
@@ -50,6 +50,13 @@
placeholder="DD/MM/YYYY" autocomplete="off">
</div>
<div class="mb-3 col-lg-6">
<label class="form-label">Department</label>
<select id="department_id" class="form-select">
<option value="0">— No Department —</option>
</select>
</div>
<div class="mb-3 col-lg-12">
<label class="form-label">Notes</label>
<textarea id="notes" class="form-control" rows="2"
@@ -293,7 +300,7 @@
has_active_invoice = has_active_invoice || false;
active_invoice_id = parseInt(active_invoice_id) || 0;
var editable = status === -2;
$('#contact, #order_date, #notes, #discount, #tax_adjustment, #shipping_fee, #btn_add_item')
$('#contact, #order_date, #department_id, #notes, #discount, #tax_adjustment, #shipping_fee, #btn_add_item')
.prop('disabled', !editable);
$('.item_sku, .item_desc, .item_qty, .item_price, .item_tax_rate').prop('disabled', !editable);
$('.remove_item_btn').toggleClass('d-none', !editable);
@@ -357,6 +364,7 @@
$('#contact').val(o.contact_name || '');
$('#contact_id').val(o.contact_id || 0);
$('#order_date').val(o.order_date ? format_date_input(o.order_date) : '');
$('#department_id').val(o.department_id || 0);
$('#notes').val(o.notes || '');
$('#discount').val(o.discount || 0);
$('#tax_adjustment').val(o.tax_adjustment || 0);
@@ -388,6 +396,7 @@
id: order_id,
contact_id: $('#contact_id').val() || 0,
order_date: to_iso_date($('#order_date').val()),
department_id: $('#department_id').val() || 0,
items: JSON.stringify(items),
discount: $('#discount').val() || 0,
tax_adjustment: $('#tax_adjustment').val() || 0,
@@ -490,6 +499,8 @@
$(async function() {
try {
// Options must exist before retrieve_order() selects the saved department
await Promise.resolve(load_departments('department_id')).catch(function() {});
if (order_id) {
await retrieve_order();
} else {