From 0de9a6205844f64bec727cbd8154f1667e8c6f16 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Thu, 7 May 2026 17:38:05 +0000 Subject: [PATCH] fix: price estimate for all items, including manually-added ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AI prompt: always return a best-guess price (never null/price_not_found) for unrecognised items returns generic package estimate with '~' prefix - Cache key bumped to v3 to invalidate old null-returning cache entries - JS: manually-added items (no smart match, no spec) default to qty=1/conf instead of qty=1/pz so _calcEstimatedTotal treats them as a single pack - Price badge: shows '~€X.XX' prefix when source_note starts with '~' so user knows the price is a rough estimate --- api/index.php | 16 +++++++++------- assets/js/app.js | 13 ++++++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/api/index.php b/api/index.php index cda3fb9..92599c1 100644 --- a/api/index.php +++ b/api/index.php @@ -6488,7 +6488,7 @@ function _savePriceCache(array $data): void { * Bump version suffix when AI prompt format changes to auto-invalidate old entries. */ function _priceKey(string $name, string $country): string { - return md5(mb_strtolower(trim($name)) . '|' . mb_strtolower(trim($country)) . '|v2'); + return md5(mb_strtolower(trim($name)) . '|' . mb_strtolower(trim($country)) . '|v3'); } /** @@ -6505,20 +6505,22 @@ function _fetchPriceFromAI(string $name, string $country, string $currency, stri $prompt = << [['parts' => [['text' => $prompt]]]]]; diff --git a/assets/js/app.js b/assets/js/app.js index 7f600fd..8f4fedc 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -8772,6 +8772,11 @@ function _buildPricePayload() { if (qtyMatch) { quantity = parseFloat(qtyMatch[1].replace(',', '.')); unit = qtyMatch[2].toLowerCase(); + } else { + // Manually-added item with no spec: assume 1 confezione + // (most grocery items are bought as a single pack) + quantity = 1; + unit = 'conf'; } } @@ -8785,9 +8790,11 @@ function _buildPricePayload() { * @param {string} sym — currency symbol like "€" */ function _buildPriceBadgeHTML(entry, sym) { - const mainLabel = entry.estimated_total != null - ? `${sym}${entry.estimated_total.toFixed(2)}` - : `${sym}${entry.price_per_unit.toFixed(2)}`; + const isApprox = (entry.source_note || '').startsWith('~'); + const mainLabel = (isApprox ? '~' : '') + + (entry.estimated_total != null + ? `${sym}${entry.estimated_total.toFixed(2)}` + : `${sym}${entry.price_per_unit.toFixed(2)}`); const unitLabel = entry.unit_label || ''; const unitLine = unitLabel && entry.price_per_unit != null ? `${sym}${entry.price_per_unit.toFixed(2)}/${unitLabel}`