fix: falso alert burro; JSON traduzioni corrotte; allineamento inventario
- 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).
This commit is contained in:
@@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### 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.
|
- **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
|
## [1.7.7] - 2026-05-10
|
||||||
|
|
||||||
|
|||||||
+13
-3
@@ -6075,12 +6075,22 @@ function smartShopping(PDO $db): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Almost finished — only flag if usage frequency justifies it
|
// Almost finished — only flag if usage frequency justifies it.
|
||||||
if ($qty > 0 && $pctLeft <= 15 && $isRegular) {
|
// 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';
|
$urgency = $isFrequent ? 'high' : 'medium';
|
||||||
$reasons[] = 'Quasi finito (' . round($pctLeft) . '%)';
|
$reasons[] = 'Quasi finito (' . round($pctLeft) . '%)';
|
||||||
$score += 80;
|
$score += 80;
|
||||||
} elseif ($qty > 0 && $pctLeft <= 30 && $isRegular) {
|
} elseif (!$familyCovered && $qty > 0 && $pctLeft <= 30 && $isRegular) {
|
||||||
if ($dailyRate > 0 && $daysLeft <= 5 && $isFrequent) {
|
if ($dailyRate > 0 && $daysLeft <= 5 && $isFrequent) {
|
||||||
$urgency = 'high';
|
$urgency = 'high';
|
||||||
$reasons[] = 'Finisce tra ~' . round($daysLeft) . 'gg';
|
$reasons[] = 'Finisce tra ~' . round($daysLeft) . 'gg';
|
||||||
|
|||||||
@@ -152,5 +152,19 @@
|
|||||||
"name": "Pancetta Dolce",
|
"name": "Pancetta Dolce",
|
||||||
"location": "frigo",
|
"location": "frigo",
|
||||||
"ts": 1778419507
|
"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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,6 @@
|
|||||||
"transferred": "Zu Rezepten hinzugefügt!",
|
"transferred": "Zu Rezepten hinzugefügt!",
|
||||||
"open_recipe": "Rezept öffnen"
|
"open_recipe": "Rezept öffnen"
|
||||||
},
|
},
|
||||||
"action": {
|
|
||||||
"cooking": {
|
"cooking": {
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"tts_btn": "Vorlesen",
|
"tts_btn": "Vorlesen",
|
||||||
|
|||||||
@@ -478,7 +478,6 @@
|
|||||||
"transferred": "Added to Recipes!",
|
"transferred": "Added to Recipes!",
|
||||||
"open_recipe": "Open recipe"
|
"open_recipe": "Open recipe"
|
||||||
},
|
},
|
||||||
"action": {
|
|
||||||
"cooking": {
|
"cooking": {
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"tts_btn": "Read aloud",
|
"tts_btn": "Read aloud",
|
||||||
|
|||||||
@@ -478,7 +478,6 @@
|
|||||||
"transferred": "Aggiunta alle Ricette!",
|
"transferred": "Aggiunta alle Ricette!",
|
||||||
"open_recipe": "Apri la ricetta"
|
"open_recipe": "Apri la ricetta"
|
||||||
},
|
},
|
||||||
"action": {
|
|
||||||
"cooking": {
|
"cooking": {
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
"tts_btn": "Leggi ad alta voce",
|
"tts_btn": "Leggi ad alta voce",
|
||||||
|
|||||||
Reference in New Issue
Block a user