Confezioni: permetti uso parziale in sub-unità (ml, g) con switch unità
This commit is contained in:
@@ -826,6 +826,30 @@ body {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.use-unit-switch {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
margin-bottom: 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
border: 2px solid var(--primary);
|
||||
}
|
||||
.use-unit-btn {
|
||||
flex: 1;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.use-unit-btn.active {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.use-all-btn {
|
||||
min-height: 70px;
|
||||
font-size: 1.15rem;
|
||||
|
||||
+116
-8
@@ -2893,8 +2893,10 @@ async function submitAdd(e) {
|
||||
// ===== USE FROM INVENTORY =====
|
||||
function showUseForm() {
|
||||
renderUsePreview();
|
||||
_useConfMode = null; // reset
|
||||
document.getElementById('use-quantity').value = 1;
|
||||
document.getElementById('use-location').value = 'dispensa';
|
||||
document.getElementById('use-unit-switch').style.display = 'none';
|
||||
|
||||
// Reset location buttons
|
||||
document.querySelectorAll('#page-use .loc-btn').forEach(b => b.classList.remove('active'));
|
||||
@@ -2918,17 +2920,22 @@ function renderUsePreview() {
|
||||
`;
|
||||
}
|
||||
|
||||
// Conf-mode tracking for USE form
|
||||
let _useConfMode = null; // null = normal, { packageSize, packageUnit, totalSub, unit } = conf mode active
|
||||
|
||||
async function loadUseInventoryInfo() {
|
||||
try {
|
||||
const data = await api('inventory_list');
|
||||
const items = (data.inventory || []).filter(i => i.product_id == currentProduct.id);
|
||||
const infoEl = document.getElementById('use-inventory-info');
|
||||
const unitSwitch = document.getElementById('use-unit-switch');
|
||||
|
||||
if (items.length > 0) {
|
||||
infoEl.innerHTML = '<strong>📦 Disponibile:</strong> ' + items.map(i => {
|
||||
const loc = LOCATIONS[i.location] || { icon: '📦', label: i.location };
|
||||
return `${loc.icon} ${loc.label}: ${i.quantity} ${i.unit}`;
|
||||
}).join(' · ');
|
||||
if (items.length === 0) {
|
||||
infoEl.innerHTML = '⚠️ Prodotto non presente nell\'inventario.';
|
||||
unitSwitch.style.display = 'none';
|
||||
_useConfMode = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-select the first available location
|
||||
const firstLoc = items[0].location;
|
||||
@@ -2939,14 +2946,103 @@ async function loadUseInventoryInfo() {
|
||||
b.classList.add('active');
|
||||
}
|
||||
});
|
||||
|
||||
const unit = items[0].unit || 'pz';
|
||||
const pkgSize = parseFloat(items[0].default_quantity) || 0;
|
||||
const pkgUnit = items[0].package_unit || '';
|
||||
const isConf = unit === 'conf' && pkgSize > 0 && pkgUnit;
|
||||
|
||||
if (isConf) {
|
||||
// --- CONF MODE: show sub-unit controls ---
|
||||
const totalConf = items.reduce((s, i) => s + parseFloat(i.quantity), 0);
|
||||
const totalSub = totalConf * pkgSize;
|
||||
const unitLabels = { 'ml': 'ml', 'l': 'L', 'g': 'g', 'kg': 'kg', 'pz': 'pz' };
|
||||
const subLabel = unitLabels[pkgUnit] || pkgUnit;
|
||||
|
||||
_useConfMode = { packageSize: pkgSize, packageUnit: pkgUnit, totalSub, totalConf, subLabel };
|
||||
|
||||
// Show inventory info with sub-unit total
|
||||
infoEl.innerHTML = '<strong>📦 Disponibile:</strong> ' + items.map(i => {
|
||||
const loc = LOCATIONS[i.location] || { icon: '📦', label: i.location };
|
||||
const confQty = parseFloat(i.quantity);
|
||||
const subQty = Math.round(confQty * pkgSize);
|
||||
const confDisplay = confQty === Math.floor(confQty) ? Math.floor(confQty) : confQty.toFixed(1);
|
||||
return `${loc.icon} ${loc.label}: ${confDisplay} conf (${subQty}${subLabel})`;
|
||||
}).join(' · ');
|
||||
|
||||
// Show unit switch
|
||||
unitSwitch.style.display = 'flex';
|
||||
document.getElementById('use-unit-sub').textContent = subLabel;
|
||||
|
||||
// Default to sub-unit mode
|
||||
switchUseUnit('sub');
|
||||
} else {
|
||||
infoEl.innerHTML = '⚠️ Prodotto non presente nell\'inventario.';
|
||||
// --- NORMAL MODE ---
|
||||
_useConfMode = null;
|
||||
unitSwitch.style.display = 'none';
|
||||
|
||||
infoEl.innerHTML = '<strong>📦 Disponibile:</strong> ' + items.map(i => {
|
||||
const loc = LOCATIONS[i.location] || { icon: '📦', label: i.location };
|
||||
return `${loc.icon} ${loc.label}: ${i.quantity} ${i.unit}`;
|
||||
}).join(' · ');
|
||||
|
||||
document.getElementById('use-quantity').value = 1;
|
||||
document.getElementById('use-partial-hint').textContent = 'Oppure specifica la quantità usata:';
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
function switchUseUnit(mode) {
|
||||
const subBtn = document.getElementById('use-unit-sub');
|
||||
const confBtn = document.getElementById('use-unit-conf');
|
||||
const qtyInput = document.getElementById('use-quantity');
|
||||
const hint = document.getElementById('use-partial-hint');
|
||||
|
||||
if (mode === 'sub') {
|
||||
subBtn.classList.add('active');
|
||||
confBtn.classList.remove('active');
|
||||
_useConfMode._activeUnit = 'sub';
|
||||
const step = getSubUnitStep(_useConfMode.packageUnit);
|
||||
qtyInput.value = step;
|
||||
qtyInput.step = step;
|
||||
hint.textContent = `Quantità in ${_useConfMode.subLabel} (totale: ${Math.round(_useConfMode.totalSub)}${_useConfMode.subLabel})`;
|
||||
} else {
|
||||
confBtn.classList.add('active');
|
||||
subBtn.classList.remove('active');
|
||||
_useConfMode._activeUnit = 'conf';
|
||||
qtyInput.value = 1;
|
||||
qtyInput.step = 0.5;
|
||||
hint.textContent = `Confezioni da ${_useConfMode.packageSize}${_useConfMode.subLabel} (hai ${_useConfMode.totalConf.toFixed(1)} conf)`;
|
||||
}
|
||||
}
|
||||
|
||||
function getSubUnitStep(pkgUnit) {
|
||||
switch (pkgUnit) {
|
||||
case 'ml': return 100;
|
||||
case 'l': return 0.25;
|
||||
case 'g': return 50;
|
||||
case 'kg': return 0.1;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function adjustUseQty(direction) {
|
||||
const input = document.getElementById('use-quantity');
|
||||
let val = parseFloat(input.value) || 0;
|
||||
let step;
|
||||
if (_useConfMode && _useConfMode._activeUnit === 'sub') {
|
||||
step = getSubUnitStep(_useConfMode.packageUnit);
|
||||
} else if (_useConfMode && _useConfMode._activeUnit === 'conf') {
|
||||
step = 0.5;
|
||||
} else {
|
||||
step = 0.5;
|
||||
}
|
||||
val = Math.max(step, val + direction * step);
|
||||
input.value = Math.round(val * 1000) / 1000;
|
||||
}
|
||||
|
||||
function selectUseLocation(btn, loc) {
|
||||
btn.parentElement.querySelectorAll('.loc-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
@@ -2981,7 +3077,18 @@ async function submitUse(e) {
|
||||
e.preventDefault();
|
||||
showLoading(true);
|
||||
try {
|
||||
const qty = parseFloat(document.getElementById('use-quantity').value) || 1;
|
||||
let qty = parseFloat(document.getElementById('use-quantity').value) || 1;
|
||||
let displayQty = qty;
|
||||
let displayUnit = '';
|
||||
|
||||
// Convert sub-unit to conf if needed
|
||||
if (_useConfMode && _useConfMode._activeUnit === 'sub') {
|
||||
displayUnit = _useConfMode.subLabel;
|
||||
qty = qty / _useConfMode.packageSize; // convert to conf
|
||||
} else if (_useConfMode && _useConfMode._activeUnit === 'conf') {
|
||||
displayUnit = 'conf';
|
||||
}
|
||||
|
||||
const result = await api('inventory_use', {}, 'POST', {
|
||||
product_id: currentProduct.id,
|
||||
quantity: qty,
|
||||
@@ -2989,7 +3096,8 @@ async function submitUse(e) {
|
||||
});
|
||||
showLoading(false);
|
||||
if (result.success) {
|
||||
showToast(`📤 Usato ${qty} di ${currentProduct.name}. Rimasti: ${result.remaining}`, 'success');
|
||||
const usedText = displayUnit ? `${displayQty}${displayUnit}` : displayQty;
|
||||
showToast(`📤 Usato ${usedText} di ${currentProduct.name}`, 'success');
|
||||
if (result.added_to_bring) {
|
||||
setTimeout(() => showToast('🛒 Prodotto finito → aggiunto a Bring!', 'info'), 1500);
|
||||
}
|
||||
|
||||
Binary file not shown.
+9
-5
@@ -9,7 +9,7 @@
|
||||
<title>Dispensa Manager</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260313d">
|
||||
<link rel="stylesheet" href="assets/css/style.css?v=20260313g">
|
||||
<!-- QuaggaJS for barcode scanning -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
|
||||
</head>
|
||||
@@ -240,16 +240,20 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Quanto hai usato?</label>
|
||||
<div class="use-unit-switch" id="use-unit-switch" style="display:none">
|
||||
<button type="button" class="use-unit-btn active" id="use-unit-sub" onclick="switchUseUnit('sub')"></button>
|
||||
<button type="button" class="use-unit-btn" id="use-unit-conf" onclick="switchUseUnit('conf')">Confezioni</button>
|
||||
</div>
|
||||
<div class="use-options">
|
||||
<button type="button" class="btn btn-large btn-danger full-width use-all-btn" onclick="submitUseAll()">
|
||||
🗑️ Usato TUTTO / Finito
|
||||
</button>
|
||||
<div class="use-partial">
|
||||
<p>Oppure specifica la quantità usata:</p>
|
||||
<p id="use-partial-hint">Oppure specifica la quantità usata:</p>
|
||||
<div class="qty-control">
|
||||
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', -0.5)">−</button>
|
||||
<button type="button" class="qty-btn" id="use-qty-minus" onclick="adjustUseQty(-1)">−</button>
|
||||
<input type="number" id="use-quantity" value="1" min="0.1" step="any" class="qty-input">
|
||||
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', 0.5)">+</button>
|
||||
<button type="button" class="qty-btn" id="use-qty-plus" onclick="adjustUseQty(1)">+</button>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-large btn-warning full-width mt-2">📤 Usa questa quantità</button>
|
||||
</div>
|
||||
@@ -874,6 +878,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/js/app.js?v=20260313f"></script>
|
||||
<script src="assets/js/app.js?v=20260313g"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user