📦 Gestione Ordini di Acquisto

Gestione completa ordini di acquisto: creazione, monitoraggio, righe dettaglio e statistiche. Sistema CRUD con paginazione e filtri avanzati.

📦 TOTALE
0
ordini
🚚 IN ARRIVO
0
ordini
✅ ARRIVATI
0
ordini
💰 TOTALE
0 €
valore ordini
📦 TOTALE
0
pallet

🔍 Filtri & Ricerca

🔄 Sync automatica: 5:00
📌 Filtri attivi:
// ==================== CONFERMA SLOT SELEZIONATO ==================== function confermaSlotSelezionato() { console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log('✅ CONFERMA SLOT PREMUTO!'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); try { // ✅ Recupera slot temporaneo if (!window.slotCalendar || !window.slotCalendar.tempSlot) { alert('⚠️ Nessuno slot selezionato! Clicca prima su uno slot nel calendario.'); console.error('❌ tempSlot non trovato!'); return; } const tempSlot = window.slotCalendar.tempSlot; const slotDateTimeValue = tempSlot.date + 'T' + tempSlot.time; console.log('📦 Slot temporaneo:', tempSlot); console.log('🎯 Valore finale:', slotDateTimeValue); // ✅ SCRIVE nel campo inputSlotTime (ORA SÌ!) const inputSlot = document.getElementById('inputSlotTime'); const confirmBtn = document.getElementById('confirmSlotBtn'); const previewBox = document.getElementById('slotPreviewBox'); const slotAvailability = document.getElementById('slotAvailability'); const infoEl = document.getElementById('slotSelectedInfo'); if (inputSlot) { inputSlot.value = slotDateTimeValue; inputSlot.setAttribute('readonly', true); inputSlot.style.background = '#d1fae5'; // Verde confermato inputSlot.style.borderColor = '#10b981'; inputSlot.placeholder = '✅ Slot confermato!'; console.log('✅ Campo inputSlotTime compilato:', inputSlot.value); } // ✅ Compila anche inputDataArrivo const dataArrivoInput = document.getElementById('inputDataArrivo'); if (dataArrivoInput) { dataArrivoInput.value = slotDateTimeValue; console.log('✅ Campo inputDataArrivo compilato:', dataArrivoInput.value); } // ✅ Nasconde box anteprima GIALLO e mostra VERDE if (previewBox) { previewBox.style.background = '#d1fae5'; // Verde confermato previewBox.style.borderColor = '#10b981'; console.log('✅ Box anteprima cambiato in VERDE'); } // ✅ Nasconde pulsante conferma if (confirmBtn) { confirmBtn.style.display = 'none'; confirmBtn.style.animation = 'none'; console.log('✅ Pulsante "Conferma Slot" nascosto'); } // ✅ Aggiorna messaggio if (slotAvailability) { const slotDate = new Date(slotDateTimeValue); slotAvailability.innerHTML = `✅ Slot confermato e prenotato!
${slotDate.toLocaleString('it-IT')}`; slotAvailability.style.color = '#10b981'; } // ✅ Aggiorna info nel box if (infoEl) { infoEl.style.color = '#10b981'; infoEl.style.fontWeight = '700'; } // ✅ Aggiorna metadata confermati (per timeline) const selectFornitore = document.getElementById('inputFornitoreId'); const docNumeroFornitore = document.getElementById('inputDocNumero1'); const savedMeta = window.confirmedSlotMeta || {}; if (selectFornitore && selectFornitore.selectedOptions.length > 0) { const text = selectFornitore.selectedOptions[0].textContent.trim(); const label = text.includes(' - ') ? text.split(' - ').slice(1).join(' - ').trim() : text; savedMeta.fornitore = label || savedMeta.fornitore || window.caricoFornitoreLabel; window.caricoFornitoreLabel = savedMeta.fornitore; } if (docNumeroFornitore && docNumeroFornitore.value) { savedMeta.numeroDoc = docNumeroFornitore.value; window.caricoDocNumber = docNumeroFornitore.value; } savedMeta.date = tempSlot.date; savedMeta.time = tempSlot.time; window.confirmedSlotMeta = savedMeta; // ✅ SALTA alla settimana dello slot confermato + RI-RENDERIZZA if (window.slotCalendar) { console.log('🚀 SALTO alla settimana dello slot confermato:', tempSlot.date); if (window.slotCalendar.goToDate) { window.slotCalendar.goToDate(tempSlot.date + 'T12:00:00'); } else { window.slotCalendar.render(); } console.log('✅ Calendario aggiornato con slot prenotato'); } // ✅ NON usa più overlay (rimosso), lo slot è già visualizzato nel calendario // const meta = window.confirmedSlotMeta || {}; // renderConfirmedSlotOverlay(meta.date || tempSlot.date, tempSlot.time, meta.fornitore || window.caricoFornitoreLabel, meta.numeroDoc || window.caricoDocNumber); // ✅ TOAST SUCCESS if (window.QMS && window.QMS.toast) { window.QMS.toast.success('✅ Slot confermato e prenotato!'); } else { alert('✅ Slot confermato e prenotato!'); } // ✅ Pulisce slot temporaneo window.slotCalendar.tempSlot = null; console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.log('✅✅✅ SLOT CONFERMATO E SALVATO NEL FORM!'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); } catch (error) { console.error('❌❌❌ ERRORE in confermaSlotSelezionato:', error); alert('⚠️ Errore nella conferma dello slot. Controlla la console (F12).'); } } // Mostra pulsante "Conferma Slot" quando uno slot viene selezionato/suggerito document.addEventListener('DOMContentLoaded', () => { const inputSlot = document.getElementById('inputSlotTime'); const btnConferma = document.getElementById('btnConfermaSlot'); if (inputSlot) { // Observer per cambiamenti al campo slot const observer = new MutationObserver(() => { if (inputSlot.value && btnConferma) { btnConferma.style.display = 'block'; console.log('🔘 Pulsante "Conferma Slot" mostrato'); } }); observer.observe(inputSlot, { attributes: true, attributeFilter: ['value'] }); // Anche su change manuale inputSlot.addEventListener('change', () => { if (inputSlot.value && btnConferma) { btnConferma.style.display = 'block'; console.log('🔘 Pulsante "Conferma Slot" mostrato (change event)'); } }); } }); // ==================== CALCOLO REAL-TIME DURATA SLOT ==================== document.addEventListener('DOMContentLoaded', () => { const inputNumeroPallet = document.getElementById('inputNumeroPallet'); const inputTipoProdotto = document.getElementById('inputTipoProdotto'); if (inputNumeroPallet) { // Listener su cambio numero pallet inputNumeroPallet.addEventListener('input', async (e) => { const numPallet = parseInt(e.target.value); const tipoProdotto = inputTipoProdotto?.value || 'SURGELATO'; // 🤖 CALENDARIO INTELLIGENTE: Mostra/Nascondi calendario slot automaticamente const calendarioSection = document.getElementById('calendarioSlotSection'); const palletCapacityInfo = document.getElementById('palletCapacityInfo'); if (numPallet > 0 && !isNaN(numPallet)) { // Mostra calendario automaticamente if (calendarioSection) { calendarioSection.style.display = 'block'; console.log('📅 Calendario slot VISIBILE automaticamente'); } // Aggiorna info capacità if (palletCapacityInfo) { palletCapacityInfo.textContent = ` Cercando slot per ${numPallet} pallet...`; palletCapacityInfo.style.color = '#2196F3'; } // Aggiorna calendario con nuova capacità richiesta if (window.slotCalendar) { window.slotCalendar.requiredPallet = numPallet; window.slotCalendar.render(); console.log('🔄 Calendario aggiornato con capacità:', numPallet, 'pallet'); } } else { // ✅ FIX: Calendario SEMPRE VISIBILE (non nascondere mai) // Il calendario è utile anche senza pallet per vedere disponibilità if (calendarioSection) { // calendarioSection.style.display = 'none'; ← RIMOSSO! console.log('📅 Calendario slot SEMPRE VISIBILE (anche senza pallet)'); } } if (numPallet > 0 && !isNaN(numPallet)) { try { // ✅ FIX #3: Formula calcolo durata - Documentazione corretta // Il backend calcola: (num_pallet × 2 min/pallet) + 10 min buffer // Esempi: 5 pallet = 20 min | 10 pallet = 30 min | 15 pallet = 40 min // La formula viene restituita dinamicamente dall'API e mostrata all'utente const response = await fetch('https://quality.mercurysurgelati.org/api/slots/calculate-duration', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ num_pallet: numPallet, tipo_prodotto: tipoProdotto }) }); if (!response.ok) throw new Error('API error'); const data = await response.json(); if (data.success) { // Crea o aggiorna preview durata let previewEl = document.getElementById('slot_duration_preview'); if (!previewEl) { previewEl = document.createElement('div'); previewEl.id = 'slot_duration_preview'; previewEl.style.cssText = 'margin-top: 12px; padding: 12px 16px; background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); border-left: 4px solid #3b82f6; border-radius: 8px; animation: slideDown 0.3s ease-out;'; e.target.closest('.form-group').appendChild(previewEl); } previewEl.innerHTML = `
⏱️ Durata Prevista Scarico: ${data.duration_minutes} minuti
${data.formula}
`; console.log(`✅ Durata calcolata: ${data.duration_minutes} min`); } } catch (error) { console.error('⚠️ Errore calcolo durata:', error); // Silently fail - non bloccare l'utente } } else { // Rimuovi preview se campo vuoto const previewEl = document.getElementById('slot_duration_preview'); if (previewEl) previewEl.remove(); } }); // Listener anche su cambio tipo prodotto if (inputTipoProdotto) { inputTipoProdotto.addEventListener('change', () => { // Trigger calcolo se c'è già un valore if (inputNumeroPallet.value) { inputNumeroPallet.dispatchEvent(new Event('input')); } }); } console.log('✅ Calcolo real-time durata slot attivato'); } }); // ==================== SISTEMA DOCUMENTI INTELLIGENTE - MAIN ==================== // 🤖 Drag & Drop PRIMA del numero documento (nella sezione principale) // 🔥 FUNZIONE GLOBALE per inizializzare automatismi (chiamata dopo apertura modale) // 🔄 Inizializza automatismi al caricamento SE il modale è già presente document.addEventListener('DOMContentLoaded', () => { // Controlla se il modale esiste già e inizializza if (document.getElementById('modalCarico')) { console.log('🔄 Modale già presente, inizializzo automatismi'); window.initModalAutomatismi(); } else { // Aspetta che il modale venga aggiunto al DOM const observer = new MutationObserver((mutations) => { if (document.getElementById('modalCarico')) { console.log('✅ Modale rilevato, inizializzo automatismi'); window.initModalAutomatismi(); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); } });