Come evitare le doppie prenotazioni in un coworking

Una doppia prenotazione è raramente un problema di calendario. Quasi sempre è un problema di definizione: due persone non erano d'accordo su cosa significhi "occupato". Ecco come definirlo in modo abbastanza preciso da poterlo far rispettare al software.

Aggiornato

Il problema non è il calendario

Quasi tutti i coworking scoprono le doppie prenotazioni allo stesso modo: due persone si presentano alle 10:00 per la stessa sala riunioni, entrambe con una conferma in mano. L'istinto è dare la colpa alla vista calendario. Ma il calendario è solo un disegno dei dati: se nel database esistono due prenotazioni sovrapposte, il calendario le disegnerà fedelmente entrambe.

Evitare le doppie prenotazioni significa rifiutare la seconda nel momento in cui viene creata. E questo richiede di rispondere a una domanda a cui molti gestionali rispondono in modo vago: che cosa conta esattamente come conflitto?

Due prenotazioni consecutive non sono un conflitto

L'errore più diffuso nei sistemi costruiti in casa è trattare 10:00–11:00 e 11:00–12:00 come sovrapposte. Non lo sono. Se il sistema le rifiuta, hai appena reso invendibili le tue sale per metà giornata.

La soluzione è trattare ogni prenotazione come un intervallo semiaperto: include l'istante di inizio ed esclude quello di fine. Due intervalli si sovrappongono solo quando ciascuno inizia prima che l'altro finisca:

start_datetime < :fine_richiesta
AND end_datetime > :inizio_richiesto

Verifichiamolo sul caso scomodo. Per 10:00–11:00 contro una richiesta 11:00–12:00: 10:00 < 12:00 è vero, ma 11:00 > 11:00 è falso. Nessuna sovrapposizione, prenotazione accettata. Per una richiesta 10:30–11:30 il secondo test diventa 11:00 > 10:30, che è vero, e la prenotazione viene rifiutata. La regola è tutta qui, e applicarla correttamente elimina un'intera categoria di lamentele in entrambe le direzioni.

"Occupato" significa due cose diverse

Una sala riunioni e una postazione flessibile falliscono in modi diversi, e un sistema che ne modella solo uno sbaglierà l'altro.

  • Prenotazione dell'intera risorsa. Qualcuno prende la sala riunioni. La capienza è irrilevante: una sola prenotazione rende la risorsa indisponibile a tutti gli altri, per quanto poche persone si presentino.
  • Prenotazione a posto. Qualcuno prende tre scrivanie in uno spazio aperto da dodici. La risorsa resta disponibile finché la somma dei posti già prenotati in quella finestra non raggiunge la capienza.

Il secondo caso non è affatto un test di sovrapposizione: è una somma. Non stai chiedendo "esiste un'altra prenotazione?" ma "quante persone sono già prenotate in questa finestra, e c'è spazio per un'altra?" In Boris è una SUM(people_count) sulle prenotazioni sovrapposte, sottratta alla capienza della risorsa.

I quattro modi in cui una prenotazione viene rifiutata

Una volta che entrambi i modelli esistono, una richiesta deve superare quattro controlli distinti. Vale la pena nominarli uno per uno, perché "la sala non è disponibile" è un messaggio inutile da dare a un membro: ognuno di questi ha un rimedio diverso.

  1. La risorsa è bloccata. Manutenzione, pulizie, un evento privato. Non è una prenotazione, quindi non comparirà mai in un test di sovrapposizione fra prenotazioni e va controllata separatamente.
  2. Una prenotazione dell'intera risorsa copre già la finestra. Qualcuno ha la sala. Non entra nient'altro, di nessuna dimensione.
  3. I posti sono già venduti. Qualcuno vuole tutta la sala, ma singole scrivanie al suo interno sono già prenotate. La sala non è libera anche se non esiste nessuna prenotazione dell'intera risorsa.
  4. La capienza è esaurita. Restano posti, ma meno di quelli richiesti. Qui il messaggio utile include quanti ne restano, così il membro può prenotare quel che c'è invece di tirare a indovinare.

Boris restituisce questi esiti come casi distinti invece che come un unico errore generico: è ciò che permette all'interfaccia di dire "restano solo 2 posti in questa fascia" invece di "non disponibile".

L'elenco delle prenotazioni in Boris, con spazio, modalità di prenotazione, numero di persone e stato del pagamento
Ogni prenotazione porta con sé la modalità e il numero di persone: sono esattamente i dati che legge il controllo di disponibilità.

Le prenotazioni annullate devono liberare lo slot

Un modo semplice per reintrodurre il problema appena risolto: dimenticare di filtrare per stato. Una prenotazione annullata resta in tabella, continua a sovrapporsi e continuerà a bloccare una risorsa che in realtà è libera. Ogni query di disponibilità deve limitarsi agli stati che occupano davvero la risorsa: in Boris, pending e confirmed.

Il ragionamento vale anche al contrario. Se pending non occupa la risorsa, due persone possono completare il checkout contemporaneamente per lo stesso slot. Una prenotazione in attesa dovrebbe riservare la risorsa e scadere a tempo, invece di essere ignorata finché non arriva il pagamento.

Registra il rifiuto, non solo la prenotazione

Le prenotazioni accettate sono visibili per definizione. Quelle rifiutate no, e sono il dato più interessante: una sala che rifiuta venti prenotazioni a settimana ti sta dicendo di comprare un'altra sala, o di accorciare la durata massima prenotabile.

Boris registra ogni conflitto bloccato sulla risorsa e genera una notifica, deduplicata per risorsa e finestra temporale, così dieci rifiuti sullo stesso slot non diventano dieci avvisi. Nell'arco di un mese quel registro è il segnale di domanda più onesto che uno spazio possieda: misura ciò che le persone volevano e non hanno potuto avere, cosa che nessun report di occupazione ti mostrerà mai.

Una breve checklist

  • Usa intervalli semiaperti, così le prenotazioni consecutive sono ammesse.
  • Modella separatamente la prenotazione dell'intera risorsa e quella a posto.
  • Controlla i blocchi della risorsa come caso a sé, non come prenotazioni.
  • Filtra la disponibilità per stato, e lascia che pending occupi lo slot con una scadenza.
  • Restituisci la capienza residua nell'errore, non solo un rifiuto.
  • Conserva i rifiuti: sono i tuoi dati di domanda.