Circolino SPAP · v1.0.41← Indietro
# Circolino SPAP Prenotazioni v1.0.41 Applicazione web mobile-first per la gestione interna delle prenotazioni tavoli e degli ordini da asporto del Circolino SPAP. ## Installazione nuova 1. Crea un database MySQL vuoto. 2. Scompatta il contenuto dello ZIP direttamente nella document root del sito. 3. Rendi scrivibili dal web server le directory `config/`, `uploads/` e `storage/`. 4. Apri il dominio nel browser e completa l'installer. ## Aggiornamento Puoi sovrascrivere direttamente i file della versione precedente. La directory `config/` dello ZIP non contiene `config.php`, quindi le credenziali MySQL restano intatte. Le migrazioni database necessarie vengono eseguite automaticamente al primo accesso. Dalla v1.0.26 le migrazioni sono versionate e vengono eseguite una sola volta; le normali richieste non effettuano più controlli DDL ripetitivi. In caso di problemi di aggiornamento consultare `storage/runtime-schema.log`. ## Regola di versionamento del progetto - Il file `VERSION` contiene la versione corrente dell'applicazione. - Il footer mostra sempre la versione, un collegamento a **README / Novità** (viewer UTF-8 di `README.md`) e quindi la dicitura `powered by IT Easy Informatica`. - A ogni nuova release questo `README.md` deve essere aggiornato mantenendo lo storico delle versioni precedenti. # Changelog ## v1.0.41 - Aggiunto alle prenotazioni il dato **Prenotazione presa da**, così Staff e Admin possono vedere subito chi ha registrato originariamente la prenotazione senza consultare il Log attività. - Il nominativo dell’operatore viene salvato come dato storico direttamente nella prenotazione, quindi resta disponibile anche se in futuro l’account Staff viene cancellato. - Il dato viene mostrato nella **Dashboard**, nell’**Agenda prenotazioni** e nella schermata **Modifica prenotazione**. - Per le prenotazioni già esistenti l’aggiornamento prova a ricostruire automaticamente il nominativo dall’utente creatore e, quando necessario, dal Log attività disponibile. - Aggiornati `VERSION`, footer e changelog. ## v1.0.40 - Il menu principale evidenzia ora con un colore dedicato la sezione attualmente aperta, sia su smartphone sia su desktop, rendendo immediatamente riconoscibile la posizione nell'app. - L'evidenziazione segue anche le pagine collegate: modifica prenotazione resta sotto **Agenda**, nuovo/modifica asporto sotto **Asporti**, modifica contatto sotto **Rubrica** e tutte le pagine amministrative sotto **Admin**. - Nei calendari di **Nuova prenotazione** e **Nuovo asporto** le date già trascorse non sono più cliccabili e vengono indicate come `Passato`. - Aggiunto un controllo lato server che impedisce di salvare prenotazioni tavolo o asporti con data antecedente a quella corrente, anche in caso di URL o richiesta modificata manualmente. - Anche l'API di verifica disponibilità rifiuta le date già trascorse. - Aggiornati `VERSION`, footer e changelog. ## v1.0.39 - Il campo **Bambini** nelle nuove prenotazioni non viene più precompilato con `0`; se lasciato vuoto viene interpretato come zero. Anche in modifica, un valore zero viene mostrato vuoto. - Aggiunta in **Amministrazione → Impostazioni → Regole prenotazioni** la voce **Cancella automaticamente prenotazioni, asporti e log più vecchi di (giorni)**. - Impostando `0` la cancellazione automatica resta disattivata; impostando ad esempio `7`, vengono eliminate le prenotazioni tavolo, gli asporti e le voci del Log attività più vecchie di 7 giorni. - La pulizia automatica viene eseguita al massimo una volta al giorno ed è protetta da lock MySQL per evitare esecuzioni concorrenti. - Quando il numero di giorni viene modificato, la nuova regola viene applicata dalla richiesta successiva senza attendere il giorno seguente. - La cancellazione riguarda lo storico operativo di prenotazioni, asporti e Log attività; la **Rubrica resta sempre invariata**. - Al termine della pulizia viene inserita nel Log attività una nuova voce di manutenzione con il numero di prenotazioni, asporti e log eliminati. ## v1.0.38 - Il campo **Seggioloni** non viene più precompilato con `0`: resta vuoto nelle nuove prenotazioni e, se lasciato vuoto, viene interpretato come `0`. - Anche in modifica prenotazione un valore pari a zero viene mostrato come campo vuoto, mantenendo comunque il calcolo corretto dei coperti. - Rinominata la voce **Dolce** in **Dolce loro cura**, per indicare chiaramente che il dolce viene portato dal cliente. - Aggiornata la stessa dicitura anche nella Dashboard e nei PDF dello staff. - Aggiornati `VERSION`, footer e changelog. ## v1.0.37 - Aggiunta una **barra Salva sempre raggiungibile** durante la compilazione dei principali moduli, pensata soprattutto per l’utilizzo da smartphone. - Il comando di salvataggio resta visibile sopra la barra di navigazione inferiore mentre il relativo form è a schermo, evitando di dover scorrere fino in fondo alla pagina. - La barra scompare automaticamente quando si esce dal form, per esempio entrando nella sezione separata di cancellazione, così da non creare ambiguità tra `Salva` e azioni distruttive. - Applicato il comportamento a prenotazioni tavoli, asporti, preparazione tavoli, impostazioni amministrative, servizi/eccezioni, struttura/inventario tavoli e modifica Rubrica. - Aggiunto spazio di sicurezza in fondo ai form per impedire che la barra fissa copra gli ultimi campi; supportati tema chiaro/scuro e safe-area degli smartphone. - Aggiornati `VERSION`, footer e changelog. ## v1.0.36 - Il limite coperti non è più unico per l’intera giornata: ogni **fascia di apertura / servizio** possiede ora il proprio massimo coperti. - In **Amministrazione → Impostazioni → Giorni e orari** ogni fascia dispone del nuovo campo `Max coperti`, così pranzo e cena possono avere capacità differenti anche nello stesso giorno. - Esempio: domenica `12:00–14:30` con massimo 100 coperti e `19:00–00:00` con massimo 180 coperti. - Durante una prenotazione l’app individua automaticamente il servizio in base all’orario di arrivo e conteggia i coperti esclusivamente nel relativo massimale; la durata continua invece a essere usata per la disponibilità fisica dei tavoli. - L’Admin mantiene la possibilità di **forzare i limiti**: la forzatura agisce ora sul limite del singolo servizio interessato. - La Dashboard mostra una card distinta per ciascun servizio con `coperti utilizzati / massimo`, numero di prenotazioni e, separatamente, il totale informativo della giornata. - La pagina amministrativa `Serate` è stata rinominata **Servizi** e permette di creare, per una singola data, una o più fasce straordinarie con massimale coperti dedicato. Se non vengono inserite fasce straordinarie, vengono ereditati orari e limiti settimanali. - Aggiunta la tabella `service_override_periods` per le eccezioni multi-servizio e la colonna `max_covers` a `opening_periods`; la migrazione automatica assegna alle fasce esistenti il precedente limite predefinito, senza perdere configurazioni. - I PDF tavoli riportano ora nell’intestazione i limiti dei singoli servizi anziché un unico “limite serata”. - Aggiornati `VERSION`, footer, schema runtime e changelog. ## v1.0.35 - Aggiunta la gestione di **più fasce orarie nello stesso giorno della settimana** dalle impostazioni amministrative. - Ogni giornata può ora avere un numero libero di fasce, ad esempio la domenica `12:00–14:30` e `19:00–00:00`, mantenendo non prenotabile l'intervallo pomeridiano tra i due servizi. - Nel pannello **Amministrazione → Impostazioni → Giorni e orari** ogni giorno dispone dei comandi `Aggiungi fascia` e `Rimuovi fascia`; impostando il giorno su `Chiuso` non viene accettata alcuna prenotazione. - Aggiunta la nuova tabella MySQL `opening_periods`; la migrazione automatica importa senza perdita le vecchie fasce singole presenti in `opening_hours`. La tabella storica viene mantenuta e sincronizzata per compatibilità. - Aggiornati i calendari di prenotazioni tavoli e asporti: i giorni con più servizi mostrano gli orari di inizio delle varie fasce e rimangono cliccabili come normali giorni di apertura. - Aggiornata la validazione lato server: una prenotazione o un asporto è accettato solo se l'orario rientra in **una delle fasce attive**; gli orari nel vuoto tra pranzo e cena vengono rifiutati. - Aggiornati i selettori Ora/Minuti mobile-first per lavorare con più fasce nello stesso giorno e mantenere gli intervalli da 15 minuti. - Le eccezioni della singola data continuano a funzionare: lasciando vuoti gli orari ereditano tutte le fasce settimanali; compilando gli orari sostituiscono le fasce di quel giorno con una singola fascia straordinaria. - Aggiornati i PDF tavoli e asporti: vengono create fasce da 15 minuti **solo nei periodi realmente aperti**, evitando righe inutili durante le ore di chiusura tra pranzo e cena. - Aggiornati `VERSION`, footer e changelog. ## v1.0.34 - Aggiunta nella **Rubrica interna** la voce **Cancella** accanto a `Modifica`, disponibile sia agli utenti Staff sia agli Amministratori. - La cancellazione richiede una conferma esplicita per evitare eliminazioni accidentali. - La cancellazione rimuove esclusivamente il contatto dalla Rubrica interna: **prenotazioni tavoli e ordini da asporto storici restano invariati**. - La cancellazione del contatto viene registrata nel **Log attività** con nome, numero di cellulare, utente e data/ora dell'operazione. - Se in futuro lo stesso nominativo/numero viene nuovamente utilizzato in una prenotazione o in un asporto, il normale salvataggio automatico della Rubrica potrà ricreare il contatto. - Nessuna modifica allo schema database. - Aggiornati `VERSION`, footer e changelog. ## v1.0.33 - Aggiunta una **Rubrica interna condivisa** disponibile sia agli utenti Staff sia agli Amministratori tramite la nuova voce `Rubrica` nella navigazione principale. - I clienti vengono salvati automaticamente nella rubrica quando una prenotazione tavolo o un ordine da asporto contiene sia **nome** sia **numero di cellulare**. Le prenotazioni senza telefono restano valide e non generano contatti vuoti. - La rubrica usa il numero di cellulare normalizzato come identificativo per evitare duplicati dello stesso numero e conserva la data dell'ultimo utilizzo. - Al primo aggiornamento alla v1.0.33 vengono importati in modo conservativo nella rubrica anche i clienti già presenti nelle prenotazioni tavoli e negli asporti recenti. - Aggiunta la pagina **Rubrica** con ricerca per nome o cellulare, elenco mobile-first, collegamento telefonico rapido e possibilità per Staff/Admin di creare e modificare nome, cellulare e note del contatto. - Il vecchio pulsante `Rubrica` nei form è stato rinominato **Importa da Rubrica Telefono**, chiarendo che usa la rubrica nativa dello smartphone tramite Contact Picker API quando supportata dal browser. - Aggiunto il nuovo pulsante **Importa da Prenotazioni Recenti** nelle schermate di creazione e modifica di prenotazioni tavoli e asporti. Apre un selettore mobile con ricerca e richiama in un tocco nome e cellulare dei clienti usati più di recente. - La modifica manuale di un contatto nella Rubrica interna non viene sovrascritta automaticamente da prenotazioni successive con lo stesso numero: l'app aggiorna soltanto l'ultimo utilizzo, preservando le correzioni fatte dallo staff. - Le creazioni automatiche e le modifiche manuali dei contatti vengono registrate nel **Log attività**. - Aggiunta la tabella MySQL `contacts` con migrazione automatica protetta dal sistema di schema versionato introdotto nella v1.0.26. - Aggiornati `VERSION`, footer e changelog. ## v1.0.32 - Fix completo della codifica caratteri **UTF-8** per nomi, prenotazioni, note, asporti e interfaccia. - Le risposte HTML dell’app inviano ora esplicitamente l’header HTTP `Content-Type: text/html; charset=UTF-8`, evitando che configurazioni Apache/Plesk legacy interpretino il contenuto come ISO-8859-1. - Tutti i form dichiarano esplicitamente `accept-charset="UTF-8"`, così anche l’invio di caratteri accentati (`à è é ì ò ù`) resta coerente. - La connessione MySQL/MariaDB forza esplicitamente `SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci`; al primo accesso vengono convertite a `utf8mb4` soltanto eventuali tabelle applicative ancora su charset legacy. - Aggiunta una correzione conservativa in visualizzazione per il mojibake più comune (es. `Novità` → `Novità`) senza alterare automaticamente i dati originali nel database. - Corretto il motore PDF: i font Helvetica/Helvetica Bold dichiarano ora `/WinAnsiEncoding`, coerente con la conversione Windows-1252 usata dal generatore PDF, così i caratteri accentati italiani vengono stampati correttamente. - Reso il wrapping/troncamento del PDF **UTF-8 safe anche senza estensione PHP mbstring**: le stringhe non vengono più tagliate a metà di un carattere multibyte, causa concreta di accenti corrotti nelle note più lunghe. - Aggiunto `readme.php`, viewer UTF-8 del file `README.md`; il footer e l’installer puntano ora a questo viewer per evitare problemi di charset del server sui file `.md` statici. - `README.md` viene salvato con firma UTF-8 BOM per migliorare anche la visualizzazione diretta del file su server/browser che non dichiarano correttamente il charset dei Markdown. - Aggiornati `VERSION`, footer e changelog. ## v1.0.31 - Aggiunto nel footer un collegamento sempre visibile a **README / Novità**, disponibile per tutti gli utenti dell’applicazione. - Il collegamento apre `README.md` in una nuova scheda, così staff e amministratori possono consultare rapidamente lo storico delle modifiche e le funzionalità introdotte nelle varie versioni. - Aggiornato anche il footer dell’installer iniziale con lo stesso collegamento. - Aggiunto uno stile dedicato al link del footer per mantenerlo leggibile sia nel tema diurno sia in quello notturno. - Nessuna modifica allo schema database. - Aggiornati `VERSION`, footer e changelog. ## v1.0.30 - Corretto il vincolo introdotto nella v1.0.29: **Bambini** e **Seggioloni** sono ora nuovamente conteggi indipendenti. - Rimosso il controllo `Seggioloni ≤ Bambini` sia dall’interfaccia sia dal backend. - Rimosso il limite dinamico del campo Seggioloni basato sul numero di bambini. - Rimane invariato il controllo obbligatorio di **almeno 1 adulto** per ogni prenotazione. - Il totale coperti continua a essere calcolato come `Adulti + Bambini + Seggioloni`. - Nessuna modifica allo schema database. - Aggiornati `VERSION`, footer e changelog. ## v1.0.29 - Velocizzato l'inserimento di una nuova prenotazione: il campo **Adulti** non è più precompilato con `2` e parte vuoto. - Aggiunto il vincolo obbligatorio di **almeno 1 adulto** per ogni prenotazione, verificato sia nell'interfaccia sia lato server. - Aggiunto il vincolo **Seggioloni ≤ Bambini**: il numero di seggioloni non può superare il numero di bambini indicati nella prenotazione. - Il limite massimo del campo Seggioloni viene aggiornato dinamicamente in base al numero di bambini e il browser segnala immediatamente eventuali valori non validi. - Gli stessi controlli vengono applicati anche durante la modifica di una prenotazione esistente. - Nessuna modifica allo schema database. - Aggiornati `VERSION`, footer e changelog. ## v1.0.28 - Aggiunta nella pagina **Agenda prenotazioni** una ricerca testuale rapida, ottimizzata per smartphone. - La ricerca filtra istantaneamente le prenotazioni del periodo visualizzato per **nome cliente** oppure **numero di cellulare**, senza ricaricare la pagina. - La ricerca del telefono ignora la formattazione: è possibile digitare anche solo una parte delle cifre del numero. - I giorni che non contengono risultati vengono nascosti automaticamente durante la ricerca e ricompaiono appena il filtro viene cancellato. - Aggiunto un contatore dinamico delle prenotazioni trovate e un pulsante rapido per azzerare la ricerca. - Il cellulare, quando presente, viene mostrato anche nella scheda Agenda per identificare più velocemente prenotazioni con nomi simili. - Nessuna modifica allo schema database. - Aggiornati `VERSION`, footer e changelog. ## v1.0.27 - Secondo intervento prestazionale dopo il persistere di timeout Apache/PHP-FPM `AH01075` anche con le migrazioni runtime rese leggere nella v1.0.26. - Ottimizzato il motore di **disponibilità tavoli**, che nelle serate affollate poteva esplorare un numero molto elevato di combinazioni e assegnazioni tra prenotazioni sovrapposte. - Le combinazioni di tavoli vengono ora memorizzate per richiesta, deduplicate e ridotte eliminando le soluzioni dominate che consumano più risorse senza offrire vantaggi. - Il backtracking che assegna virtualmente i tavoli usa ora memoizzazione degli stati già falliti e sceglie prima le prenotazioni con meno alternative disponibili, riducendo drasticamente i rami esplorati. - Aggiunto un **limite di sicurezza temporale** al calcolo disponibilità: invece di lasciare un worker PHP-FPM occupato fino al timeout Apache, l'app interrompe il solver e restituisce un messaggio gestibile invitando a selezionare una zona specifica o, per gli admin, usare la forzatura. - Aggiunti piccoli cache per-request per servizio effettivo, stagione/zone attive e inventario tavoli, riducendo query duplicate durante la stessa pagina. - Impostati, quando supportati dal motore DB, timeout server-side anche sulle query (`max_statement_time` MariaDB / `MAX_EXECUTION_TIME` MySQL), oltre ai timeout di connessione e lock già presenti. - Aggiunto il log diagnostico `storage/performance.log`: vengono registrate automaticamente solo richieste lente (>= 2 secondi), errori HTTP 5xx e fatal error, con URI, durata, IP e memoria di picco. - Nessuna modifica allo schema database: la versione runtime dello schema resta `1.0.26`, quindi l'aggiornamento alla v1.0.27 non forza una nuova migrazione DDL. - Aggiornati `VERSION`, footer e changelog. ## v1.0.26 - Corretto il meccanismo di migrazione runtime che nelle versioni precedenti eseguiva controlli `SHOW COLUMNS`, `CREATE TABLE IF NOT EXISTS` e verifiche su `information_schema` ad ogni singola richiesta HTTP. - Introdotta la chiave database `runtime_schema_version`: dopo il primo aggiornamento, le richieste normali eseguono soltanto una lettura leggera della versione schema e non rilanciano più DDL o controlli strutturali. - Le migrazioni vengono eseguite **una sola volta** quando necessario e sono protette da un advisory lock MySQL (`GET_LOCK`) per impedire migrazioni concorrenti da più worker PHP-FPM. - Ridotte le interrogazioni di migrazione a poche query aggregate su `information_schema`; `ALTER TABLE` e `CREATE TABLE` vengono eseguiti solo quando una struttura risulta realmente mancante. - Impostati timeout DB prudenti (`PDO` connection timeout e lock wait MySQL) per evitare che un worker PHP-FPM rimanga occupato per minuti in presenza di lock. - In caso di migrazione temporaneamente bloccata l'app risponde rapidamente con **HTTP 503 + Retry-After**, invece di restare appesa fino al timeout Apache `AH01075`. - Aggiunto il log diagnostico `storage/runtime-schema.log`, utile per verificare l'esecuzione o eventuali errori delle migrazioni. - Le nuove installazioni vengono marcate direttamente con schema `1.0.26`, quindi non eseguono migrazioni ridondanti al primo accesso. - Nessuna modifica funzionale a prenotazioni, asporti, PDF o WhatsApp rispetto alla v1.0.25. - Aggiornati `VERSION`, footer e changelog. ## v1.0.25 - Rinominato il pulsante principale `+ ASPORTI` in **`+ Asporti`** nella Dashboard e nell’Agenda asporti. - Ridisegnato il **PDF Asporti**: ogni ordine occupa ora **una sola riga tabellare**, anche quando contiene più piatti. - I piatti dello stesso ordine vengono accorpati nella cella **Piatto** con quantità e descrizione su più righe interne alla stessa cella. - La colonna **QTÀ** mostra la quantità complessiva dei pezzi/piatti dell’ordine. - Le note specifiche dei singoli piatti, le note generali dell’ordine e l’eventuale cellulare vengono accorpati nella cella **Note** della stessa riga. - L’altezza della riga dell’ordine cresce automaticamente in base al numero di piatti/note, evitando che uno stesso ordine possa essere interpretato come più ordini distinti. - Restano invariate le fasce da 15 minuti, le righe vuote del planner e la regola che impedisce di spezzare una fascia tra due pagine. - Aggiornati `VERSION`, footer e changelog. ## v1.0.24 - Aggiunto il numero di cellulare nella colonna **Note** di tutti i PDF quando il telefono è presente. - Nel PDF prenotazioni tavoli ogni prenotazione mostra `Cell: numero` insieme alle altre note operative. - Nel PDF asporti il cellulare viene riportato nelle note della prima riga dell'ordine, oltre alla colonna Telefono già esistente, evitando ripetizioni su ogni piatto dello stesso ordine. - Le prenotazioni e gli asporti senza numero di telefono non mostrano alcuna dicitura aggiuntiva. - Aggiornati `VERSION`, footer e changelog. ## v1.0.23 - Aggiunto il nuovo modulo **Asporti**, separato dalle prenotazioni tavoli e senza occupazione di tavoli o zone. - Aggiunto il pulsante **+ ASPORTI** nella Dashboard e una voce dedicata nella navigazione mobile. - Aggiunta una **Agenda asporti** con filtro per intervallo di date, orario di ritiro, cliente, stato e riepilogo dei piatti ordinati. - La creazione di un asporto usa lo stesso calendario del locale: giorni di chiusura e ferie sono rossi/non selezionabili e gli orari di ritiro seguono la fascia di servizio configurata, compresi i servizi oltre mezzanotte. - Ogni asporto contiene nome cliente, telefono facoltativo, data/ora di ritiro, note generali e una lista dinamica di piatti. - Ogni riga piatto dispone di **quantità, nome/tipologia del piatto e note specifiche**, con pulsanti per aggiungere o rimuovere righe direttamente da smartphone. - Aggiunti gli stati asporto: **Prenotato, Confermato, In preparazione, Pronto, Ritirato, Annullato dal cliente**. - Aggiunta la cancellazione per errore di immissione, separata dall'annullamento del cliente e tracciata nel **Log attività**. - Il Log attività registra creazione, modifica, annullamento e cancellazione degli asporti con utente, data/ora e descrizione. - La Dashboard mostra ora il numero di ordini da asporto e il totale dei piatti della serata, oltre a una lista rapida degli ordini. - Aggiunto un **PDF Asporti** separato dal PDF tavoli. - Il PDF asporti usa lo stesso planner staff: A4 verticale, fasce da 15 minuti, almeno 5 righe per fascia, crescita automatica se i piatti sono più numerosi e nessuna fascia viene spezzata tra due pagine. - Nel PDF asporti ogni piatto occupa una riga con colonne **Orario, Cliente, Telefono, Qtà, Piatto, Note**; le righe residue restano vuote per aggiunte a penna. - Il parametro **Righe minime per fascia** nelle impostazioni PDF viene applicato sia al planner tavoli sia al planner asporti. - Aggiunte le tabelle MySQL `takeaway_orders` e `takeaway_items`, create automaticamente al primo accesso in fase di aggiornamento. - Aggiornati `VERSION`, footer e changelog. ## v1.0.22 - Il planner PDF non è più limitato a 2 pagine: genera automaticamente tutti i fogli A4 verticali necessari. - Ogni fascia di 15 minuti contiene sempre **almeno 5 righe complessive**, comprese le prenotazioni già registrate. - Se una fascia contiene più di 5 prenotazioni, cresce automaticamente per stamparle tutte senza perdere dati. - Mantenuta l’altezza delle righe della v1.0.21 per preservare la leggibilità del planner. - Le fasce orarie sono **indivisibili**: se una fascia non entra nello spazio residuo del foglio, viene spostata interamente alla pagina successiva. - Il numero totale di pagine viene calcolato automaticamente e riportato nell’intestazione (`Pagina X / Y`). - In **Amministrazione → Impostazioni → PDF / Planner serata** la preferenza diventa **Righe minime per fascia di 15 minuti**, con minimo 5 e valore predefinito 5. - Aggiornati `VERSION` e changelog. ## v1.0.21 - Aggiunta nuovamente la colonna **Orario** nelle righe del PDF, mantenendo anche l'intestazione orizzontale `FASCIA ORARIA HH:MM`. - Ridotte drasticamente le righe vuote: ogni fascia di 15 minuti usa normalmente una sola riga libera oltre alle prenotazioni già presenti, fino a un massimo configurabile di **5 righe complessive per fascia**. - Se una fascia contiene già 5 prenotazioni non vengono aggiunte righe vuote; se eccezionalmente contiene più di 5 prenotazioni, vengono comunque stampate tutte senza perdere dati. - Le fasce più affollate usano **carattere più grande e righe più alte**, invece di rimpicciolire progressivamente il testo. - La divisione tra le 2 pagine viene ora calcolata in base all'altezza reale delle fasce per distribuire meglio lo spazio disponibile. - Il PDF resta composto da **esattamente 2 fogli A4 verticali**. - In **Amministrazione → Impostazioni → PDF / Planner serata** è disponibile la nuova preferenza **Righe massime per fascia di 15 minuti**, predefinita a 5. - Aggiornati `VERSION` e changelog. ## v1.0.20 - Ridisegnato il planner PDF per migliorare la leggibilità mantenendo sempre **2 pagine A4 verticali**. - Le fasce orarie restano ogni **15 minuti**, ma l'orario non è più una cella verticale stretta: ogni fascia viene ora mostrata come una **riga orizzontale a tutta larghezza**, come nel planner precedente. - Rimossa la colonna `Ora` dalle righe operative: lo spazio recuperato viene distribuito a Nome tavolo, Zona, Note e Numero tavolo. - Ogni fascia riceve lo stesso numero di righe operative; valore predefinito **2 righe per fascia**, molto più alte e leggibili rispetto alla v1.0.19. - Se una fascia contiene più prenotazioni del minimo configurato, tutte le fasce vengono ampliate automaticamente allo stesso numero di righe, preservando la proporzione tra gli orari. - In **Amministrazione → Impostazioni → PDF / Planner serata** la precedente densità 40–60 è stata sostituita dalla preferenza **Righe minime per fascia di 15 minuti** (1–4, predefinito 2). - Il secondo foglio resta sempre disponibile anche per servizi molto brevi. - Nessuna modifica distruttiva al database; la nuova preferenza viene aggiunta automaticamente alla tabella impostazioni. ## v1.0.19 - Ripristinata nel PDF staff la suddivisione del planner in **fasce orarie ogni 15 minuti**. - Le fasce vengono generate automaticamente dal primo all'ultimo orario prenotabile configurato per la serata, comprese le fasce che attraversano la mezzanotte (es. 19:00–00:00). - Tutte le fasce ricevono **esattamente lo stesso numero di righe**, così lo spazio disponibile è distribuito in maniera proporzionale e uniforme tra tutti gli orari. - Le prenotazioni vengono inserite nella propria fascia di 15 minuti e le righe residue restano vuote per la compilazione a penna dello staff. - La colonna **Ora** è visualizzata come una cella unica verticale per tutta la fascia, rendendo immediata la lettura del planner. - Il PDF resta composto **sempre e soltanto da 2 pagine A4 verticali**. - La preferenza in **Amministrazione → Impostazioni → PDF / Planner serata** viene ora interpretata come densità indicativa di righe per foglio (40–60): l'app calcola automaticamente le righe per fascia mantenendole uguali per ogni orario. - Se una singola fascia contiene più prenotazioni delle righe previste, il sistema aumenta automaticamente il numero di righe di **tutte** le fasce, preservando la proporzione e mantenendo sempre 2 pagine. - Le prenotazioni restano ordinate per orario e la zona continua a essere mostrata nell'apposita colonna, senza raggruppamenti per zona. - Nessuna modifica allo schema MySQL. ## v1.0.18 - Reso il **numero di telefono facoltativo** nella creazione e modifica delle prenotazioni. - Una prenotazione senza telefono resta pienamente valida e partecipa normalmente a disponibilità tavoli, coperti, preparazione serata e PDF. - Se il telefono è vuoto, il **Reminder WhatsApp** viene automaticamente disabilitato e non viene salvato come attivo. - Il cron dei reminder ignora esplicitamente le prenotazioni senza numero di telefono, evitando tentativi di invio inutili. - In caso di **Annullata dal cliente**, se la prenotazione non ha un numero di telefono l'app non tenta l'invio WhatsApp di annullamento e registra nel Log attività che il messaggio non era previsto. - Aggiunta nell'interfaccia una nota chiara accanto al telefono e al reminder per indicare che il numero è opzionale. - Nessuna modifica allo schema MySQL. ## v1.0.17 - Aumentato il planner PDF da almeno **20 a 40 righe per foglio**. - Il PDF resta composto da **esattamente 2 pagine A4 verticali**, quindi mette a disposizione almeno **80 righe complessive**, comprese le prenotazioni già registrate. - Le righe non occupate restano vuote e compilabili a penna dallo staff. - Se le prenotazioni superano le 80 complessive, il sistema aumenta automaticamente e in modo uniforme le righe per pagina mantenendo comunque soltanto 2 fogli. - In **Amministrazione → Impostazioni → PDF / Planner serata** il valore è ora configurabile da **40 a 60 righe per foglio**, con valore predefinito 40. - Le installazioni aggiornate da versioni precedenti con un valore inferiore a 40 vengono portate automaticamente a 40 al primo accesso. ## v1.0.16 - Semplificato il PDF staff in un **planner completamente libero**, senza suddivisione per zone e senza blocchi/fasce orarie. - Le prenotazioni presenti vengono stampate semplicemente in **ordine cronologico**; la zona resta disponibile nell'apposita colonna. - Il planner viene generato **sempre e soltanto su 2 pagine A4 verticali**. - Ogni foglio contiene almeno **20 righe totali**, comprese le prenotazioni già registrate; le righe non occupate restano completamente vuote e compilabili a penna. - Se le prenotazioni superano le 40 complessive, il sistema aumenta automaticamente e in modo uniforme il numero di righe per pagina per mantenere tutte le prenotazioni nei 2 fogli. - In **Amministrazione → Impostazioni → PDF / Planner serata** il numero minimo di righe per foglio è configurabile da 20 a 30, con valore predefinito 20. - Rimosso dal planner il precedente concetto di “righe libere per fascia di 30 minuti”. - Ridimensionate colonne e caratteri per il nuovo orientamento verticale mantenendo: Ora, Nome tavolo, Zona, Adulti, Bambini, Seggioloni, Note e Numero tavolo. - Nessuna modifica allo schema MySQL: la nuova preferenza utilizza la tabella impostazioni esistente. ## v1.0.15 - Rifatto il PDF staff in modalità **planner cronologico**: le prenotazioni non sono più separate per zona e vengono ordinate esclusivamente per orario. - Aggiunta la colonna **Zona** direttamente nella tabella del PDF. - Il planner è suddiviso in **fasce di 30 minuti** dalla prima all’ultima ora prenotabile della serata, comprese le fasce che attraversano la mezzanotte. - In ogni fascia vengono stampate le prenotazioni già presenti con il loro orario esatto e vengono aggiunte righe vuote compilabili a penna dallo staff. - Il numero di righe libere per ogni fascia di 30 minuti è configurabile da **Amministrazione → Impostazioni → PDF / Planner serata**; valore predefinito: **6**. - Le righe libere mantengono tutte le colonne operative: Ora, Nome tavolo, Zona, Adulti, Bambini, Seggioloni, Note e Numero tavolo. - Migliorata la gestione multipagina del PDF: intestazione tabella e fascia oraria vengono ripetute quando il planner prosegue nella pagina successiva. - La stampa A4 orizzontale viene generata su **almeno 2 fogli**; se il planner dovesse occupare una sola pagina, il secondo foglio viene predisposto con una griglia vuota per prenotazioni aggiuntive scritte a mano. - Nessuna modifica allo schema MySQL: la nuova preferenza viene salvata nella tabella impostazioni esistente. ## v1.0.14 - Aggiunta in **Amministrazione → Utenti** la possibilità per gli amministratori di **cancellare definitivamente gli utenti Staff**. - Il pulsante **Cancella utente** è disponibile esclusivamente sugli account con ruolo `staff`; gli account amministratore non possono essere eliminati da questa funzione. - Aggiunta protezione contro la cancellazione/disattivazione del proprio account. - Le prenotazioni create da uno Staff eliminato vengono conservate nello storico: il riferimento `created_by` viene reso nullable con vincolo `ON DELETE SET NULL` tramite migrazione automatica. - I precedenti eventi del **Log attività** restano consultabili anche dopo la cancellazione dell'utente, perché nome, username e ruolo sono memorizzati nello storico. - Il filtro utenti del Log include ora anche gli utenti eliminati, evidenziati con la dicitura **(eliminato)**. - La cancellazione di uno Staff viene registrata nel Log attività con descrizione e numero di prenotazioni storiche preservate. ## v1.0.13 - Aggiunta in **Amministrazione → Impostazioni → Test invio WhatsApp** una funzione di verifica manuale della WhatsApp Cloud API. - Aggiunto il campo **Numero WhatsApp destinatario** con normalizzazione automatica dei numeri italiani (`333...`, `+39...`, `0039...`). - Il pulsante **Invia messaggio di test** utilizza il template Meta standard `hello_world` con lingua `en_US`, ideale per verificare il numero di prova fornito da Meta. - Il test usa Graph API version, Phone number ID e Access token già salvati nelle impostazioni e può essere eseguito anche con l'automazione WhatsApp dell'app disabilitata. - In caso di successo viene mostrato anche l'ID messaggio restituito da Meta; in caso di errore viene mostrata la descrizione restituita dalla Cloud API quando disponibile. - Il destinatario usato per l'ultimo test resta precompilato per agevolare prove successive. - I tentativi di test, riusciti o falliti, vengono registrati nel **Log attività** con utente, destinatario ed esito. - Migliorata la gestione interna delle risposte della WhatsApp Cloud API e degli errori cURL senza esporre l'Access token. - `server-check.php` verifica ora anche la disponibilità dell'estensione PHP **cURL**, necessaria per l'invio WhatsApp. ## v1.0.12 - Le prenotazioni distinguono ora i coperti in **Adulti**, **Bambini** e **Seggioloni**. - Il totale della prenotazione viene calcolato automaticamente come somma delle tre categorie e continua a essere usato per disponibilità tavoli e limite coperti della serata. - Aggiunto il totale coperti aggiornato in tempo reale durante inserimento e modifica della prenotazione. - Dashboard, Agenda e Preparazione tavoli mostrano anche la composizione della prenotazione. - Il PDF staff è stato ridisegnato in **A4 orizzontale** con griglia tabellare ispirata al foglio operativo fornito: - Ora; - Nome tavolo; - Numero persone suddiviso in Adulti / Bambini / Seggioloni; - Note; - Numero tavolo. - Le prenotazioni nel PDF sono delimitate da celle e linee ben visibili; le zone sono separate da intestazioni dedicate. - Il PDF riporta in testata anche i totali della serata per categoria. - Aggiunta migrazione automatica delle installazioni precedenti: il totale storico viene preservato attribuendo inizialmente a `Adulti` i coperti non associati ai seggioloni e lasciando `Bambini` a 0 fino a eventuale modifica manuale. - Aggiornati log attività e descrizioni operative con il dettaglio Adulti / Bambini / Seggioloni. ## v1.0.11 - Distinta definitivamente la semantica tra **Annullata dal cliente** e **Cancella prenotazione**. - Lo stato `cancelled` viene ora mostrato come **Annullata dal cliente** e rappresenta una disdetta ricevuta dal cliente. - Aggiunto nella modifica prenotazione il pulsante **Cancella prenotazione**, destinato esclusivamente agli errori di inserimento di staff/admin. - La cancellazione è **logica**: la prenotazione non compare più in agenda operativa, disponibilità tavoli, preparazione serata, conteggi o PDF, ma resta nel database per garantire la tracciabilità. - La cancellazione per errore richiede un motivo e **non invia mai WhatsApp**. - Aggiunta la possibilità, configurabile in **Amministrazione → Impostazioni → WhatsApp**, di inviare un template WhatsApp quando una prenotazione passa allo stato **Annullata dal cliente**. - Aggiunto template separato configurabile per l’annullamento (`reservation_cancelled` come default), con le stesse quattro variabili del reminder: cliente, data, ora, persone. - Migliorata la normalizzazione dei numeri italiani per WhatsApp. - Introdotto **Log attività** visibile esclusivamente agli amministratori. - Il log registra data/ora, utente, ruolo, azione, descrizione, oggetto interessato e indirizzo IP. - Tracciate le principali azioni: accessi/uscite, creazione/modifica/annullamento/cancellazione prenotazioni, preparazione tavoli, impostazioni, ferie, utenti, serate, assetti, zone, tipi tavolo e inventario. - Aggiunti filtri del log per periodo, utente e ricerca testuale. - Aggiunte migrazioni automatiche per cancellazione logica e tabella `audit_logs`. ## v1.0.10 - Migliorata la leggibilità del PDF: ogni prenotazione è separata dalla successiva tramite una linea orizzontale. - Aggiunto in **Preparazione tavoli** il campo **Numero tavolo** per ogni prenotazione. - Il numero tavolo viene salvato nell’allestimento e riportato anche nel PDF della serata. - Il campo numero tavolo accetta anche valori composti, ad esempio `12-13`, utili quando più tavoli vengono accorpati. - Rinominata in tutta l’interfaccia la voce **Dolce portato da fuori / Dolce esterno** in **Dolce**. - Aggiunta migrazione automatica del database per il nuovo campo `table_number` nella tabella `setups`. ## v1.0.9 - Completato il `README.md` con lo storico delle modifiche dalla v1.0.0 in avanti. - Versione dell'applicazione mostrata sempre nel footer nel formato `vX.Y.Z · powered by IT Easy Informatica`. - Versione mostrata anche nel footer dell'installer iniziale. - Il CSS dell'installer utilizza ora anch'esso il numero versione per evitare cache obsolete. ## v1.0.8 - Pulsante **Rubrica** in nuova/modifica prenotazione. - Quando il browser supporta la Contact Picker API, vengono richiesti insieme **nome del contatto e numeri di telefono**. - Il nome viene compilato automaticamente nel campo cliente. - I numeri duplicati dello stesso contatto vengono accorpati anche quando sono salvati con formati diversi (`+39...`, `0039...`, numero nazionale). - Se dopo la deduplicazione rimane un solo numero, viene compilato automaticamente. - Se il contatto ha più numeri realmente diversi, l'app mostra un selettore mobile e permette di scegliere **un solo numero**. - Se il browser non supporta l'accesso diretto alla rubrica, resta disponibile l'inserimento manuale/autocomplete standard. - Nessuna modifica allo schema MySQL rispetto alla v1.0.7. ## v1.0.7 - Nella schermata **Nuova prenotazione** il campo data è stato sostituito da un calendario mobile-first. - I giorni in cui il locale è chiuso sono mostrati in **rosso e non sono cliccabili**. - Il calendario considera: - giorni settimanali di chiusura; - eccezioni della singola serata; - periodi di ferie / chiusure programmate. - I periodi di ferie sono gestibili da **Amministrazione → Impostazioni → Chiusure per ferie**. - Ogni periodo ha data iniziale, data finale e descrizione, ad esempio `Ferie estive`. - Le chiusure possono essere attivate/disattivate oppure eliminate definitivamente. - Impedita la creazione accidentale di periodi di chiusura attivi sovrapposti. - Una eccezione della singola serata impostata esplicitamente su **Aperto** può riaprire una data compresa in un periodo di ferie. - Versionamento automatico di CSS/JS per ridurre i problemi di cache sugli smartphone dopo gli aggiornamenti. ## v1.0.6 - Eliminata la perdita posti globale fissa per le unioni. - Aggiunta per ogni tipologia di tavolo la configurazione: - **posti persi alla prima unione**; - **posti persi alla seconda/unione aggiuntiva**. - L'algoritmo calcola la capienza delle combinazioni usando le perdite specifiche dei singoli tipi di tavolo. - Le tipologie esistenti vengono migrate mantenendo il comportamento precedente con valori iniziali compatibili. - Supportati casi in cui un tavolo non perde posti alla prima unione. ## v1.0.5 - Aggiunta la proprietà **Unibile ad altri tavoli** per ogni tipologia. - Un tavolo marcato come non unibile può essere utilizzato solo singolarmente per una prenotazione. - Un tavolo non unibile non può essere combinato né con tavoli dello stesso tipo né con tipologie differenti. - Più tavoli non unibili possono comunque essere utilizzati contemporaneamente per prenotazioni diverse. - La preparazione della serata propone `Singolo` quando la soluzione usa un solo tavolo e disposizioni multiple solo quando necessario. ## v1.0.4 - Aggiunta la cancellazione definitiva di asset amministrativi oltre alla semplice disattivazione. - Eliminazione disponibile per: - assetti/stagioni; - zone; - tipologie di tavolo. - Introdotte protezioni contro la cancellazione di elementi già usati nello storico prenotazioni o ancora collegati ad altri dati. - Conferma obbligatoria prima della cancellazione definitiva. ## v1.0.3 - Corretta la gestione degli orari che attraversano la mezzanotte. - Una fascia `19:00–00:00` viene interpretata come servizio dalle 19:00 fino alla mezzanotte conclusiva della stessa serata. - Supportate anche fasce come `19:00–01:00`. - Corretto il calcolo delle sovrapposizioni dei tavoli quando la prenotazione termina dopo mezzanotte. - Migliorati i messaggi di errore per gli orari fuori fascia mostrando la fascia realmente applicata. - Orari amministrativi impostabili a intervalli di 15 minuti. - Rifatta in chiave mobile la sezione **Inventario tavoli per zona**, eliminando la tabella orizzontale poco leggibile su smartphone. - Migliorata la navigazione delle sezioni amministrative su schermi stretti. ## v1.0.2 - Orario di arrivo della prenotazione separato in selezione **Ora** e **Minuti**. - Ore selezionabili una per una. - Minuti disponibili: `00`, `15`, `30`, `45`. - Rimosso il campo e-mail dalla prenotazione cliente. - Rimossa la voce specifica `Compleanno`; ricorrenze ed esigenze vengono gestite nelle note. - Mantenuta la compatibilità con le colonne tecniche eventualmente già presenti nel database. ## v1.0.1 - Rimossi i file `.htaccess` dalla distribuzione per evitare errori HTTP 500 su hosting/Plesk che non consentono alcune direttive Apache a livello directory. - Aggiunta la pagina `server-check.php` per verificare rapidamente requisiti PHP e permessi. - Mantenuta l'applicazione indipendente da configurazioni `.htaccess` obbligatorie. ## v1.0.0 Prima versione installabile dell'applicazione. Funzioni principali introdotte: - Stack **Apache + PHP + MySQL**. - Installer guidato con: - host, porta, database, utente e password MySQL; - creazione amministratore; - e-mail recupero password; - titolo iniziale applicazione. - Ruoli **Amministratore** e **Staff**. - Interfaccia **mobile-first** pensata principalmente per smartphone. - Logo configurabile. - Titolo applicazione configurabile da pannello admin. - Tema **Diurno / Notturno / Automatico** e cambio tema dall'interfaccia. - Footer `powered by IT Easy Informatica`. - Gestione prenotazioni interne con: - cliente; - telefono; - data e ora; - adulti; - bambini; - seggioloni; - totale coperti calcolato automaticamente; - durata prevista; - zona; - dolce; - note ed esigenze particolari; - stato prenotazione. - Stati prenotazione: prenotata, confermata, arrivata, terminata, annullata, no-show. - Assetti/stagioni del locale, inizialmente **Estivo / Esterno** e **Invernale / Interno**. - Zone iniziali estive: Tendone, Aperto, Altalene, Giochi, Privée, Fresco. - Giorni e orari di apertura configurabili da amministrazione. - Valori iniziali Giovedì–Domenica, fascia serale. - Eccezioni configurabili per singola serata. - Massimo coperti configurabile per ciascuna fascia di servizio (es. pranzo/cena), con possibilità di forzatura amministratore. - Tipologie tavolo iniziali: - Quadrato, 4 posti; - Rettangolare, 6 posti. - Quantità dei tipi di tavolo configurabile per ogni zona. - Calcolo della disponibilità fisica dei tavoli per fascia oraria. - Gestione di più turni nella stessa serata. - Durata standard prenotazione e tempo di riassetto configurabili. - Prenotazione separata dall'allestimento fisico dei tavoli. - Schermata **Preparazione tavoli** con suggerimenti di disposizione. - PDF A4 orizzontale multipagina per lo staff con griglia operativa, orari, nome tavolo, adulti, bambini, seggioloni, note, numero tavolo e separazione per zone. - Predisposizione per reminder tramite **WhatsApp Cloud API** e cron giornaliero. - Recupero password via e-mail. # Regole funzionali attuali ## Prenotazione e allestimento Durante la prenotazione non viene fissata immediatamente la disposizione fisica. L'app verifica che esista una combinazione di tavoli sufficiente nella zona e nella fascia richiesta. La disposizione viene definita successivamente nella schermata di preparazione della serata. ## Tavoli unibili Ogni tipologia può essere marcata come unibile o non unibile. Per i tipi unibili, la perdita di capienza viene calcolata usando i valori specifici della tipologia per prima e seconda unione. ## Limite coperti per servizio Ogni fascia di apertura possiede il proprio massimo coperti (per esempio pranzo e cena con limiti diversi). La prenotazione viene conteggiata nel servizio corrispondente al proprio orario di arrivo; l’amministratore può forzare il relativo limite quando necessario. Il totale giornaliero resta disponibile come dato informativo. ## Chiusure e ferie La disponibilità di una data deriva da giorni settimanali, eccezioni per singola serata e periodi di ferie. Una eccezione esplicita `Aperto` può prevalere su una chiusura per ferie. ## Orari oltre mezzanotte Una fascia `19:00–00:00` indica il servizio dalle 19:00 fino alla mezzanotte conclusiva della stessa serata. Sono supportate anche fasce che terminano dopo mezzanotte, ad esempio `19:00–01:00`. ## Compatibilità database Per compatibilità con installazioni precedenti, alcune colonne tecniche non più usate dall'interfaccia, come `email` e `birthday` nella tabella `bookings`, possono rimanere nel database. ## Asporti Gli ordini da asporto sono separati dalle prenotazioni tavoli: rispettano giorni, ferie e orari del servizio, ma non impegnano zone o tavoli e non concorrono al calcolo della disponibilità fisica della sala. Ogni ordine può contenere più righe piatto, ciascuna con quantità e note specifiche. Il PDF asporti è un planner dedicato alla cucina/staff: ogni ordine occupa una sola riga tabellare e i suoi piatti vengono accorpati nella stessa cella, così un ordine con più pietanze non può essere scambiato per più ordini distinti. Il planner non modifica il PDF delle prenotazioni tavoli.