Fix 3 bugs: banana use blocked, cleanup never ran, stale Bring items

1. Use form pz step bug (banana non scalabile):
   - min=0.25 + step=0.5 → solo 0.75, 1.25, 1.75... validi per browser
   - 1 intero (default) era INVALIDO → form bloccato silenziosamente
   - Fix: step='any', min=0.01 (il passo logico resta in adjustUseQty)

2. cleanupObsoleteBringItems mai eseguita:
   - Usava products_list che non ha campo quantity → (qty||0)<=0 sempre vero → skip sempre
   - Fix: usa inventory_list che ha le qty reali per location

3. cleanupObsoleteBringItems troppo rara:
   - sessionStorage → una sola volta per sessione
   - Fix: localStorage con TTL 30 minuti
   - Ora rimuove da Bring qualsiasi item che ha scorte in inventario
     e NON è flaggato come critical/high dalla spesa intelligente
This commit is contained in:
dadaloop82
2026-04-07 15:08:03 +00:00
parent 9b51bb606d
commit 0bca79b8a2
+47 -24
View File
@@ -3972,8 +3972,8 @@ async function loadUseInventoryInfo() {
const qtyInput = document.getElementById('use-quantity');
qtyInput.value = 1;
qtyInput.step = unit === 'pz' ? '0.5' : 'any';
qtyInput.min = (unit === 'g' || unit === 'ml') ? '1' : '0.25';
qtyInput.step = 'any';
qtyInput.min = '0.01';
document.getElementById('use-partial-hint').textContent = 'Oppure specifica la quantità usata:';
// Fraction buttons for pz unit
@@ -5067,40 +5067,63 @@ async function autoAddCriticalItems() {
* Items not matching any DB product are left untouched (likely manually added by user).
*/
async function cleanupObsoleteBringItems() {
if (sessionStorage.getItem('_bringCleanupDone')) return;
sessionStorage.setItem('_bringCleanupDone', '1');
if (!shoppingItems.length || !smartShoppingItems.length) return;
// Run at most once every 30 minutes (not once per session — user may restock mid-session)
const lastCleanup = parseInt(localStorage.getItem('_bringCleanupTs') || '0');
if (Date.now() - lastCleanup < 30 * 60 * 1000) return;
localStorage.setItem('_bringCleanupTs', String(Date.now()));
if (!shoppingItems.length) return;
// Build set of smart-flagged names (these should stay)
const smartNames = new Set(smartShoppingItems.map(i => i.name.toLowerCase()));
// Build set of smart-flagged names (these should stay if still urgently needed)
const smartUrgent = new Set(
smartShoppingItems
.filter(i => i.urgency === 'critical' || i.urgency === 'high')
.map(i => i.name.toLowerCase())
);
// Load all products from our DB to cross-reference
let allProducts = [];
// Load live inventory (has actual quantities unlike products_list)
let invItems = [];
try {
const res = await api('products_list');
allProducts = res.products || res.data || [];
const res = await api('inventory_list');
invItems = res.inventory || [];
} catch (e) { return; }
if (!allProducts.length) return;
// Index our products by lowercase name
const dbByName = {};
for (const p of allProducts) {
dbByName[p.name.toLowerCase()] = p;
// Build map: lowercase product name → total inventory qty
const invQtyByName = {};
const invQtyById = {};
for (const inv of invItems) {
const key = (inv.name || '').toLowerCase();
invQtyByName[key] = (invQtyByName[key] || 0) + parseFloat(inv.quantity || 0);
invQtyById[inv.product_id] = (invQtyById[inv.product_id] || 0) + parseFloat(inv.quantity || 0);
}
const toRemove = [];
for (const item of shoppingItems) {
const nameLower = item.name.toLowerCase();
// If smart shopping still flags it, keep it
if (smartNames.has(nameLower)) continue;
if (_findSimilarItem(item.name, smartShoppingItems)) continue;
// Must match a known DB product — otherwise it's likely a manual addition
const dbProduct = dbByName[nameLower] || _findSimilarItem(item.name, allProducts);
if (!dbProduct) continue;
// Keep if still urgent according to smart shopping
if (smartUrgent.has(nameLower)) continue;
const urgentMatch = smartShoppingItems.find(si =>
(si.urgency === 'critical' || si.urgency === 'high') &&
_nameTokens(si.name)[0] === _nameTokens(item.name)[0]
);
if (urgentMatch) continue;
// Only remove if we have stock (qty > 0) — if qty == 0 user may still need it
if ((dbProduct.quantity || 0) <= 0) continue;
// Check if we have stock in inventory (exact name match or first-token match)
let hasStock = false;
const exactQty = invQtyByName[nameLower] || 0;
if (exactQty > 0) {
hasStock = true;
} else {
// Fuzzy: find inventory item with matching first token
const itemFirst = _nameTokens(item.name)[0];
if (itemFirst) {
const match = invItems.find(inv => _nameTokens(inv.name || '')[0] === itemFirst);
if (match && invQtyById[match.product_id] > 0) hasStock = true;
}
}
// Only remove Bring items for products we actually track (have inventory entry)
if (!hasStock) continue;
toRemove.push(item);
}