Fix anomaly banner when expected_qty is negative (untracked initial stock)
This commit is contained in:
@@ -1584,6 +1584,10 @@ function getInventoryAnomalies(PDO $db): void {
|
|||||||
if (!empty($dismissed[$key])) continue;
|
if (!empty($dismissed[$key])) continue;
|
||||||
|
|
||||||
$direction = $diff > 0 ? 'phantom' : 'missing';
|
$direction = $diff > 0 ? 'phantom' : 'missing';
|
||||||
|
// Special case: expected is negative — more consumption recorded than entries.
|
||||||
|
// The real qty vs tx comparison is meaningless; what we actually know is that
|
||||||
|
// "initial stock was never formally registered as an 'in' transaction".
|
||||||
|
if ($expected <= 0) $direction = 'untracked';
|
||||||
$anomalies[] = [
|
$anomalies[] = [
|
||||||
'inventory_id' => (int)$r['inventory_id'],
|
'inventory_id' => (int)$r['inventory_id'],
|
||||||
'product_id' => (int)$r['product_id'],
|
'product_id' => (int)$r['product_id'],
|
||||||
|
|||||||
+6
-1
@@ -2962,9 +2962,14 @@ function renderBannerItem() {
|
|||||||
} else if (entry.type === 'anomaly') {
|
} else if (entry.type === 'anomaly') {
|
||||||
const an = entry.data;
|
const an = entry.data;
|
||||||
const isPhantom = an.direction === 'phantom';
|
const isPhantom = an.direction === 'phantom';
|
||||||
|
const isUntracked = an.direction === 'untracked';
|
||||||
banner.className = 'alert-banner banner-anomaly';
|
banner.className = 'alert-banner banner-anomaly';
|
||||||
iconEl.textContent = '🔍';
|
iconEl.textContent = '🔍';
|
||||||
if (isPhantom) {
|
if (isUntracked) {
|
||||||
|
// More consumption recorded than entries — initial stock was never registered
|
||||||
|
titleEl.textContent = `${an.name} — ${t('dashboard.banner_anomaly_untracked_title')}`;
|
||||||
|
detailEl.innerHTML = t('dashboard.banner_anomaly_untracked_detail', { inv_qty: an.inv_qty, unit: an.unit });
|
||||||
|
} else if (isPhantom) {
|
||||||
titleEl.textContent = `${an.name} — ${t('dashboard.banner_anomaly_phantom_title')}`;
|
titleEl.textContent = `${an.name} — ${t('dashboard.banner_anomaly_phantom_title')}`;
|
||||||
detailEl.innerHTML = t('dashboard.banner_anomaly_phantom_detail', { inv_qty: an.inv_qty, unit: an.unit, expected_qty: an.expected_qty });
|
detailEl.innerHTML = t('dashboard.banner_anomaly_phantom_detail', { inv_qty: an.inv_qty, unit: an.unit, expected_qty: an.expected_qty });
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -128,6 +128,9 @@
|
|||||||
"banner_finished_check": "Kannst du nachschauen?",
|
"banner_finished_check": "Kannst du nachschauen?",
|
||||||
"banner_anomaly_phantom_title": "mehr Bestand als erwartet",
|
"banner_anomaly_phantom_title": "mehr Bestand als erwartet",
|
||||||
"banner_anomaly_phantom_detail": "Bestand zeigt {inv_qty} {unit}, aber laut Buchungen solltest du nur {expected_qty} {unit} haben. Hast du Bestand ohne Buchung hinzugefügt?",
|
"banner_anomaly_phantom_detail": "Bestand zeigt {inv_qty} {unit}, aber laut Buchungen solltest du nur {expected_qty} {unit} haben. Hast du Bestand ohne Buchung hinzugefügt?",
|
||||||
|
"banner_anomaly_untracked_title": "Anfangsbestand nicht als Eingang gebucht",
|
||||||
|
"banner_anomaly_untracked_detail": "Du hast <strong>{inv_qty} {unit}</strong> im Bestand, aber die gebuchten Abgänge übersteigen die Eingänge — der Anfangsbestand wurde wahrscheinlich nie als \"Eingang\" erfasst. Bitte korrigiere die Menge oder trage die fehlenden Eingänge nach."
|
||||||
|
,
|
||||||
"banner_anomaly_ghost_title": "weniger Bestand als erwartet",
|
"banner_anomaly_ghost_title": "weniger Bestand als erwartet",
|
||||||
"banner_anomaly_ghost_detail": "Laut Buchungen solltest du {expected_qty} {unit} von {name} haben, aber der Bestand zeigt nur {inv_qty} {unit}. Hast du etwas ohne Buchung entnommen?",
|
"banner_anomaly_ghost_detail": "Laut Buchungen solltest du {expected_qty} {unit} von {name} haben, aber der Bestand zeigt nur {inv_qty} {unit}. Hast du etwas ohne Buchung entnommen?",
|
||||||
"consumed": "Verbraucht: {n} ({pct}%)",
|
"consumed": "Verbraucht: {n} ({pct}%)",
|
||||||
|
|||||||
@@ -128,6 +128,8 @@
|
|||||||
"banner_finished_check": "Can you check?",
|
"banner_finished_check": "Can you check?",
|
||||||
"banner_anomaly_phantom_title": "you have more stock than expected",
|
"banner_anomaly_phantom_title": "you have more stock than expected",
|
||||||
"banner_anomaly_phantom_detail": "Inventory shows {inv_qty} {unit}, but based on records you should only have {expected_qty} {unit}. Did you add stock without recording it?",
|
"banner_anomaly_phantom_detail": "Inventory shows {inv_qty} {unit}, but based on records you should only have {expected_qty} {unit}. Did you add stock without recording it?",
|
||||||
|
"banner_anomaly_untracked_title": "stock not recorded as an entry",
|
||||||
|
"banner_anomaly_untracked_detail": "You have <strong>{inv_qty} {unit}</strong> in inventory, but recorded outflows exceed inflows — the initial stock was likely never added as an \"in\" transaction. You can correct the quantity or log the missing entries.",
|
||||||
"banner_anomaly_ghost_title": "you have less stock than expected",
|
"banner_anomaly_ghost_title": "you have less stock than expected",
|
||||||
"banner_anomaly_ghost_detail": "Based on recorded operations you should have {expected_qty} {unit} of {name}, but inventory shows only {inv_qty} {unit}. Did you take stock without recording it?",
|
"banner_anomaly_ghost_detail": "Based on recorded operations you should have {expected_qty} {unit} of {name}, but inventory shows only {inv_qty} {unit}. Did you take stock without recording it?",
|
||||||
"consumed": "Consumed: {n} ({pct}%)",
|
"consumed": "Consumed: {n} ({pct}%)",
|
||||||
|
|||||||
@@ -128,6 +128,8 @@
|
|||||||
"banner_finished_check": "Puoi controllare?",
|
"banner_finished_check": "Puoi controllare?",
|
||||||
"banner_anomaly_phantom_title": "hai più scorte del previsto",
|
"banner_anomaly_phantom_title": "hai più scorte del previsto",
|
||||||
"banner_anomaly_phantom_detail": "L'inventario segna {inv_qty} {unit}, ma in base alle registrazioni ne dovresti avere solo {expected_qty} {unit}. Hai aggiunto scorte senza registrarle?",
|
"banner_anomaly_phantom_detail": "L'inventario segna {inv_qty} {unit}, ma in base alle registrazioni ne dovresti avere solo {expected_qty} {unit}. Hai aggiunto scorte senza registrarle?",
|
||||||
|
"banner_anomaly_untracked_title": "scorte non registrate come entrata",
|
||||||
|
"banner_anomaly_untracked_detail": "Hai <strong>{inv_qty} {unit}</strong> in inventario, ma le uscite registrate superano le entrate — le scorte iniziali probabilmente non sono mai state aggiunte come entrata. Puoi correggere la quantità o registrare le entrate mancanti.",
|
||||||
"banner_anomaly_ghost_title": "hai meno scorte del previsto",
|
"banner_anomaly_ghost_title": "hai meno scorte del previsto",
|
||||||
"banner_anomaly_ghost_detail": "In base alle operazioni registrate dovresti avere {expected_qty} {unit} di {name}, ma l'inventario mostra solo {inv_qty} {unit}. Hai prelevato senza registrarlo?",
|
"banner_anomaly_ghost_detail": "In base alle operazioni registrate dovresti avere {expected_qty} {unit} di {name}, ma l'inventario mostra solo {inv_qty} {unit}. Hai prelevato senza registrarlo?",
|
||||||
"consumed": "Consumati: {n} ({pct}%)",
|
"consumed": "Consumati: {n} ({pct}%)",
|
||||||
|
|||||||
Reference in New Issue
Block a user