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:
+47
-24
@@ -3972,8 +3972,8 @@ async function loadUseInventoryInfo() {
|
|||||||
|
|
||||||
const qtyInput = document.getElementById('use-quantity');
|
const qtyInput = document.getElementById('use-quantity');
|
||||||
qtyInput.value = 1;
|
qtyInput.value = 1;
|
||||||
qtyInput.step = unit === 'pz' ? '0.5' : 'any';
|
qtyInput.step = 'any';
|
||||||
qtyInput.min = (unit === 'g' || unit === 'ml') ? '1' : '0.25';
|
qtyInput.min = '0.01';
|
||||||
document.getElementById('use-partial-hint').textContent = 'Oppure specifica la quantità usata:';
|
document.getElementById('use-partial-hint').textContent = 'Oppure specifica la quantità usata:';
|
||||||
|
|
||||||
// Fraction buttons for pz unit
|
// 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).
|
* Items not matching any DB product are left untouched (likely manually added by user).
|
||||||
*/
|
*/
|
||||||
async function cleanupObsoleteBringItems() {
|
async function cleanupObsoleteBringItems() {
|
||||||
if (sessionStorage.getItem('_bringCleanupDone')) return;
|
// Run at most once every 30 minutes (not once per session — user may restock mid-session)
|
||||||
sessionStorage.setItem('_bringCleanupDone', '1');
|
const lastCleanup = parseInt(localStorage.getItem('_bringCleanupTs') || '0');
|
||||||
if (!shoppingItems.length || !smartShoppingItems.length) return;
|
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)
|
// Build set of smart-flagged names (these should stay if still urgently needed)
|
||||||
const smartNames = new Set(smartShoppingItems.map(i => i.name.toLowerCase()));
|
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
|
// Load live inventory (has actual quantities unlike products_list)
|
||||||
let allProducts = [];
|
let invItems = [];
|
||||||
try {
|
try {
|
||||||
const res = await api('products_list');
|
const res = await api('inventory_list');
|
||||||
allProducts = res.products || res.data || [];
|
invItems = res.inventory || [];
|
||||||
} catch (e) { return; }
|
} catch (e) { return; }
|
||||||
if (!allProducts.length) return;
|
|
||||||
|
|
||||||
// Index our products by lowercase name
|
// Build map: lowercase product name → total inventory qty
|
||||||
const dbByName = {};
|
const invQtyByName = {};
|
||||||
for (const p of allProducts) {
|
const invQtyById = {};
|
||||||
dbByName[p.name.toLowerCase()] = p;
|
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 = [];
|
const toRemove = [];
|
||||||
for (const item of shoppingItems) {
|
for (const item of shoppingItems) {
|
||||||
const nameLower = item.name.toLowerCase();
|
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
|
// Keep if still urgent according to smart shopping
|
||||||
const dbProduct = dbByName[nameLower] || _findSimilarItem(item.name, allProducts);
|
if (smartUrgent.has(nameLower)) continue;
|
||||||
if (!dbProduct) 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
|
// Check if we have stock in inventory (exact name match or first-token match)
|
||||||
if ((dbProduct.quantity || 0) <= 0) continue;
|
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);
|
toRemove.push(item);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user