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:
@@ -13,13 +13,14 @@ $prm = new PurchaseRequestManager($pdo2, $company_id);
|
||||
|
||||
try {
|
||||
if ($action === 'create') {
|
||||
$new_id = $prm->save(array_merge($data, ['id' => 0, 'items' => $items]), $logging);
|
||||
// One transaction: a failure while writing the lines must not leave the header behind.
|
||||
$new_id = dbTransaction($pdo2, fn() => $prm->save(array_merge($data, ['id' => 0, 'items' => $items]), $logging));
|
||||
$answer['success'] = 1;
|
||||
$answer['message'] = 'Purchase request created.';
|
||||
$answer['new_id'] = $new_id;
|
||||
(new UsageGuard($pdo1, $company_id, $packages))->increment();
|
||||
} elseif ($action === 'update') {
|
||||
$prm->save(array_merge($data, ['id' => $id, 'items' => $items]), $logging);
|
||||
dbTransaction($pdo2, fn() => $prm->save(array_merge($data, ['id' => $id, 'items' => $items]), $logging));
|
||||
$answer['success'] = 1;
|
||||
$answer['message'] = 'Purchase request updated.';
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row g-5 mb-5">
|
||||
<div class="col-lg-3 col-sm-6 col-12">
|
||||
<div class="col-lg col-sm-6 col-12">
|
||||
<div class="card p-4">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="icon-shape icon-md bg-primary bg-opacity-10 text-primary rounded-2">
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 col-12">
|
||||
<div class="col-lg col-sm-6 col-12">
|
||||
<div class="card p-4">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="icon-shape icon-md bg-success bg-opacity-10 text-success rounded-2">
|
||||
@@ -52,7 +52,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 col-12">
|
||||
<div class="col-lg col-sm-6 col-12">
|
||||
<div class="card p-4">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="icon-shape icon-md bg-warning bg-opacity-10 text-warning rounded-2">
|
||||
@@ -65,7 +65,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 col-12">
|
||||
<div class="col-lg col-sm-6 col-12">
|
||||
<div class="card p-4">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="icon-shape icon-md bg-secondary bg-opacity-10 text-secondary rounded-2">
|
||||
<i class="ti ti-ban fs-4"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-0 text-muted small">Void</p>
|
||||
<h3 class="fw-bold mb-0" id="stat_void">—</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg col-sm-6 col-12">
|
||||
<div class="card p-4">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="icon-shape icon-md bg-info bg-opacity-10 text-info rounded-2">
|
||||
@@ -255,8 +268,11 @@
|
||||
function update_stats() {
|
||||
var pis = all_invoices.filter(i => i.doc_type === 'purchase_invoice');
|
||||
$('#stat_invoice').text(format_number(pis.length));
|
||||
$('#stat_paid').text(format_number(pis.filter(i => String(i.status) === '2').length));
|
||||
$('#stat_open').text(format_number(pis.filter(i => ['0','1'].includes(String(i.status))).length));
|
||||
// Same test as the row badge, so a tile never disagrees with the list below it
|
||||
var is_paid = i => String(i.status) === '2' || i.payment_state === 'paid';
|
||||
$('#stat_paid').text(format_number(pis.filter(i => String(i.status) !== '4' && is_paid(i)).length));
|
||||
$('#stat_open').text(format_number(pis.filter(i => ['0','1'].includes(String(i.status)) && !is_paid(i)).length));
|
||||
$('#stat_void').text(format_number(pis.filter(i => String(i.status) === '4').length));
|
||||
$('#stat_scn').text(format_number(all_invoices.filter(i => i.doc_type === 'supplier_credit_note').length));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user