From d1139a7e4bd737433b0c089c7e8f80f71d52708d Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Sun, 10 May 2026 15:34:29 +0000 Subject: [PATCH] fix: falso alert burro; JSON traduzioni corrotte; allineamento inventario MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Smart shopping: aggiungi family-coverage check per prodotti 'quasi finiti'. Se il shopping_name family ha scorte da altri prodotti (es. Burro conf) con unità diff (g/ml vs conf), l'alert 'sta finendo' viene soppresso. - Corretto bug traduzioni: sezione 'action' duplicata in de/en/it.json causava JSONDecodeError in CI/CD (line 944 column 2). - DB: allineamento inventario burro — rimossi 30g residui (usati), pulito opened_at da pacco nuovo Burro conf (comprato 2026-05-08). --- CHANGELOG.md | 7 +++++++ api/index.php | 16 +++++++++++++--- data/opened_shelf_cache.json | 14 ++++++++++++++ translations/de.json | 1 - translations/en.json | 1 - translations/it.json | 1 - 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d87b684..5e86a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - **Trasferisci a Ricette dalla chat** — Quando la chat con Gemini Chef genera una ricetta, compare il bottone "📥 Trasferisci a Ricette". Premendolo, Gemini converte il testo in JSON strutturato completo (titolo, pasti, ingredienti, passi), il backend arricchisce ogni ingrediente con product_id e location via fuzzy-match (identico a generateRecipe), la ricetta viene salvata in archivio e si apre direttamente nella sezione Ricette con tutti i pulsanti "Usa" e la modalità cottura completa. +- **Bottone "Apri la ricetta"** — Dopo un trasferimento riuscito, il bottone "📥 Trasferisci a Ricette" si trasforma direttamente in "📖 Apri la ricetta" (stesso elemento DOM), evitando problemi di sovrapposizione. +- **Crea una ricetta per ingrediente** — Nel pannello azione di ogni alimento in inventario compare il bottone "👨‍🍳 Crea una ricetta con questo" (teal, larghezza piena). Premendolo, Gemini genera una ricetta italiana usando quell'alimento come protagonista (stesso pipeline di chatToRecipe: arricchimento fuzzy-match inventario, meal=null, 8192 token max). +- **meal non auto-categorizzato** — Le ricette generate da chat o da ingrediente non vengono più auto-categorizzate (meal rimane null); il tag pasto nell'UI viene mostrato solo se valorizzato. + +### Fixed +- **Smart shopping: falso positivo "quasi finito"** — Se un prodotto in grammi/ml era quasi esaurito (es. Burro 30g = 12%) ma lo stesso prodotto era disponibile anche come confezione (Burro 1 conf = 99%), il sistema segnalava ugualmente "sta finendo". Ora verifica se la famiglia `shopping_name` ha scorte da altri prodotti: se sì, l'alert viene soppresso. (Esempio: 30g di Burro + 1 conf di Burro → nessun alert.) +- **Traduzioni JSON corrotte** — La sezione `action` era duplicata nei file `de.json`, `en.json` e `it.json`, causando errori di parsing che bloccavano la CI/CD. Rimossa la sezione spuria. ## [1.7.7] - 2026-05-10 diff --git a/api/index.php b/api/index.php index 1294128..e7b7551 100644 --- a/api/index.php +++ b/api/index.php @@ -6075,12 +6075,22 @@ function smartShopping(PDO $db): void { } } - // Almost finished — only flag if usage frequency justifies it - if ($qty > 0 && $pctLeft <= 15 && $isRegular) { + // Almost finished — only flag if usage frequency justifies it. + // Suppress if the same shopping_name family has adequate stock from OTHER products + // (e.g. "Burro g" at 12% but "Burro conf" at 99% → no need to flag). + $sNameLow = strtolower(trim($p['shopping_name'] ?? '')); + $familyOtherStock = ($sNameLow !== '') ? max(0, ($stockByShoppingName[$sNameLow] ?? 0) - $qty) : 0; + // For g/ml/kg/l: any conf/pz family stock ≥ 0.5 means a package is available. + // For conf/pz: needs at least 1 full unit from other family products. + $familyCovered = $sNameLow !== '' && $qty > 0 && ( + (!in_array($unit, ['conf', 'pz']) && $familyOtherStock >= 0.5) || + (in_array($unit, ['conf', 'pz']) && $familyOtherStock >= 1.0) + ); + if (!$familyCovered && $qty > 0 && $pctLeft <= 15 && $isRegular) { $urgency = $isFrequent ? 'high' : 'medium'; $reasons[] = 'Quasi finito (' . round($pctLeft) . '%)'; $score += 80; - } elseif ($qty > 0 && $pctLeft <= 30 && $isRegular) { + } elseif (!$familyCovered && $qty > 0 && $pctLeft <= 30 && $isRegular) { if ($dailyRate > 0 && $daysLeft <= 5 && $isFrequent) { $urgency = 'high'; $reasons[] = 'Finisce tra ~' . round($daysLeft) . 'gg'; diff --git a/data/opened_shelf_cache.json b/data/opened_shelf_cache.json index a22338d..1d6666f 100644 --- a/data/opened_shelf_cache.json +++ b/data/opened_shelf_cache.json @@ -152,5 +152,19 @@ "name": "Pancetta Dolce", "location": "frigo", "ts": 1778419507 + }, + "9e4189bd3f8cb1121e7389967dd4f74c": { + "days": 180, + "source": "rule", + "name": "Farina di grano tenero tipo rossa", + "location": "dispensa", + "ts": 1778427005 + }, + "e3472dd051ed13ae18fc96bbebedc1ba": { + "days": 60, + "source": "rule", + "name": "Lievito di birra", + "location": "dispensa", + "ts": 1778427005 } } \ No newline at end of file diff --git a/translations/de.json b/translations/de.json index 3674f0b..deb885a 100644 --- a/translations/de.json +++ b/translations/de.json @@ -478,7 +478,6 @@ "transferred": "Zu Rezepten hinzugefügt!", "open_recipe": "Rezept öffnen" }, - "action": { "cooking": { "close": "Schließen", "tts_btn": "Vorlesen", diff --git a/translations/en.json b/translations/en.json index 6fdef2c..62d4d7d 100644 --- a/translations/en.json +++ b/translations/en.json @@ -478,7 +478,6 @@ "transferred": "Added to Recipes!", "open_recipe": "Open recipe" }, - "action": { "cooking": { "close": "Close", "tts_btn": "Read aloud", diff --git a/translations/it.json b/translations/it.json index 157840b..0d6a827 100644 --- a/translations/it.json +++ b/translations/it.json @@ -478,7 +478,6 @@ "transferred": "Aggiunta alle Ricette!", "open_recipe": "Apri la ricetta" }, - "action": { "cooking": { "close": "Chiudi", "tts_btn": "Leggi ad alta voce",