From c7a69d8379309f6b5dcbf66d2018243d351c6ba0 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Fri, 29 May 2026 06:37:50 +0000 Subject: [PATCH] fix: consumption anomaly ignores sealed packs in other rows getConsumptionPredictions now aggregates total qty across all inventory rows for the same product_id before flagging. If totalQtyAllRows >= expectedQty, the anomaly is suppressed (stock is healthy, just split across opened+sealed rows). Also uses aggregated total as the displayed actual_qty. --- CHANGELOG.md | 6 ++++++ api/index.php | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb9652..8e4458a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Recipe scraps tips** — During cooking steps, detect "waste" generated (peels, cores, bones, eggshells, coffee grounds, citrus zest, etc.) and surface AI-powered tips on how to reuse them (compost, natural cleaner, broth, candied peel, etc.). Could be shown as an optional collapsible hint card below the step that generates the scrap. +## [1.7.30] - 2026-05-29 + +### Fixed +- **False consumption anomaly with multi-row stock** — The anomaly detection banner was evaluating each inventory row in isolation. Products split across multiple rows (e.g. one opened pack with 1 pz + one sealed pack with 6 pz) incorrectly triggered a "consumed faster than expected" warning because only the opened row (1 pz) was compared against the model. The check now aggregates the total quantity across all rows for the same product before deciding to flag an anomaly. If the combined total ≥ expected remaining, the anomaly is suppressed. + + ## [1.7.29] - 2026-05-29 ### Added diff --git a/api/index.php b/api/index.php index 7b4fb77..187d042 100644 --- a/api/index.php +++ b/api/index.php @@ -4155,6 +4155,24 @@ function getConsumptionPredictions(PDO $db): void { $expectedQty = max(0, $baselineQty - ($dailyRate * $daysSinceRestock)); $actualQty = floatval($item['quantity']); + // Aggregate total stock for this product across ALL inventory rows. + // A product may be split into multiple rows (e.g. one opened pack + one + // sealed pack at a different location). The opened row alone may look + // depleted while the total is healthy — do not flag in that case. + $totalQtyStmt = $db->prepare(" + SELECT COALESCE(SUM(quantity), 0) + FROM inventory + WHERE product_id = ? AND quantity > 0 + "); + $totalQtyStmt->execute([$pid]); + $totalQtyAllRows = floatval($totalQtyStmt->fetchColumn() ?: 0); + // If the aggregate total is above the expected remaining, the "depletion" + // is just stock spread across rows — suppress the anomaly. + if ($totalQtyAllRows >= $expectedQty) continue; + // Use the aggregate total as the visible actual qty so the banner shows + // the real combined stock, not just the single opened row. + $actualQty = $totalQtyAllRows; + // Need at least some post-restock usage observations before warning. if ($txSinceRestock < 2) continue;