Sposta prodotto dopo l'uso + fix prodotti aperti

- Dopo aver usato un prodotto, se rimane quantità mostra modal con opzione
  di spostarlo in un'altra posizione (es. dispensa→frigo dopo apertura)
- La scadenza viene ricalcolata per la nuova posizione
- Fix marmellata: default_quantity era 0 → non appariva tra prodotti aperti
- Auto-set default_quantity al primo add per prodotti g/ml/kg/l senza pkg size
- Versione: 20260316b
This commit is contained in:
dadaloop82
2026-03-16 06:48:48 +00:00
parent 458206b39f
commit eb5ee60dd7
4 changed files with 62 additions and 2 deletions
+9
View File
@@ -501,6 +501,15 @@ function addToInventory(PDO $db): void {
if ($unit) {
$stmt = $db->prepare("UPDATE products SET unit = ?, default_quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?");
$stmt->execute([$unit, $quantity, $productId]);
} else {
// Auto-set default_quantity if product has none (first add sets package size)
$stmt = $db->prepare("SELECT default_quantity, unit FROM products WHERE id = ?");
$stmt->execute([$productId]);
$prod = $stmt->fetch();
if ($prod && (float)($prod['default_quantity'] ?? 0) == 0 && !in_array($prod['unit'], ['pz', 'conf'])) {
$stmt = $db->prepare("UPDATE products SET default_quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?");
$stmt->execute([$quantity, $productId]);
}
}
// Update package info if conf
+52 -1
View File
@@ -3410,6 +3410,51 @@ function selectUseLocation(btn, loc) {
document.getElementById('use-location').value = loc;
}
function showMoveAfterUseModal(product, fromLoc, remaining) {
const otherLocs = Object.entries(LOCATIONS).filter(([k]) => k !== fromLoc);
const locButtons = otherLocs.map(([k, v]) =>
`<button type="button" class="loc-btn" onclick="confirmMoveAfterUse(${product.id}, '${fromLoc}', '${k}')">${v.icon} ${v.label}</button>`
).join('');
document.getElementById('modal-content').innerHTML = `
<div class="modal-header">
<h3>📦 Spostare il resto?</h3>
<button class="modal-close" onclick="closeModal();showPage('dashboard')">✕</button>
</div>
<div style="padding:0 16px 16px">
<p style="margin-bottom:12px">Vuoi spostare il resto di <strong>${escapeHtml(product.name)}</strong> in un'altra posizione?</p>
<div class="location-selector">${locButtons}</div>
<button type="button" class="btn btn-secondary full-width" style="margin-top:12px" onclick="closeModal();showPage('dashboard')">No, resta in ${LOCATIONS[fromLoc]?.label || fromLoc}</button>
</div>
`;
document.getElementById('modal-overlay').style.display = 'flex';
}
async function confirmMoveAfterUse(productId, fromLoc, toLoc) {
closeModal();
showLoading(true);
try {
const data = await api('inventory_list');
const item = (data.inventory || []).find(i => i.product_id == productId && i.location === fromLoc && parseFloat(i.quantity) > 0);
if (item) {
const product = { name: item.name || '', category: item.category || '' };
let days = estimateExpiryDays(product, toLoc);
if (item.vacuum_sealed) days = getVacuumExpiryDays(days);
await api('inventory_update', {}, 'POST', {
id: item.id,
location: toLoc,
expiry_date: addDays(days),
product_id: productId,
});
showToast(`📦 Spostato in ${LOCATIONS[toLoc]?.label || toLoc}`, 'success');
}
} catch (e) {
console.error('Move error:', e);
}
showLoading(false);
showPage('dashboard');
}
async function submitUseAll() {
showLoading(true);
try {
@@ -3462,7 +3507,13 @@ async function submitUse(e) {
if (result.added_to_bring) {
setTimeout(() => showToast('🛒 Prodotto finito → aggiunto a Bring!', 'info'), 1500);
}
showPage('dashboard');
// If there's remaining quantity, offer to move to another location
const usedFrom = document.getElementById('use-location').value;
if (result.remaining > 0) {
showMoveAfterUseModal(currentProduct, usedFrom, result.remaining);
} else {
showPage('dashboard');
}
} else {
showToast(result.error || 'Errore', 'error');
}
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -895,6 +895,6 @@
</div>
</div>
<script src="assets/js/app.js?v=20260316a"></script>
<script src="assets/js/app.js?v=20260316b"></script>
</body>
</html>