Table of Contents

BR-BOOK — Regole di business del dominio Booking / Prenotazioni

Estrazione delle regole di business del modulo BookCenter (creazione e gestione prenotazioni di entità spaziali), ancorata a docs/07-business-flows/FLOW-BOOK-001.md e alla relativa evidenza. Backend Oracle INFOCAD_TEST38 (procedure top-level BOOK_*, nessun ORM), frontend ASP.NET Web Forms BookCenterWeb (C#), BL/DAL nel servizio Windows BookManager via .NET Remoting; path programmatico equivalente WCF BookingReaderWCF.svc.

Il create-booking runtime passa dal modulo Book* (BookController/BookDAL), non dal modulo omonimo Booking* (amministrazione/config). Le regole sotto coprono: validazioni di inserimento, anti-sovrapposizione, ricorrenza, workflow DEM, permessi, transizioni di stato, vincoli DB, e le varianti customer-specific (soglie comfort/consumi energetici).

Legenda enforcement: UI = solo lato interfaccia (code-behind) · BL = business layer (controller/DAL/helper) · DB = vincolo/PL-SQL sul database · mixed = più punti. Legenda confidence: VERIFIED = letto su codice e/o sorgente DB · SUPPORTED = per analogia documentata · INFERRED = dedotto dalla struttura, non testato a runtime.


Registro regole

ID Regola Tipo Enforcement Conf.
BR-BOOK-001 Entità spaziale obbligatoria per creare la prenotazione validation UI VERIFIED
BR-BOOK-002 Tipo orario obbligatorio per creare la prenotazione validation UI VERIFIED
BR-BOOK-003 Anti-sovrapposizione occorrenze sulla stessa entità (stati Booked/Approved/Confirmed) validation UI ⚠️ VERIFIED
BR-BOOK-004 Data inizio non successiva alla data fine ricorrenza date-logic UI VERIFIED
BR-BOOK-005 La ricorrenza è espansa in N occorrenze, ciascuna con proprio elemento DEM calculation UI/BL VERIFIED
BR-BOOK-006 Ogni occorrenza genera un elemento di workflow DEM di tipo Create state-transition BL SUPPORTED
BR-BOOK-007 Ramo di scrittura Current vs Stored selezionato da BookTable/PTABLE config-flag mixed VERIFIED
BR-BOOK-008 BOOK_DEMAND esige ID_USER e ID_CDP NOT NULL, non popolati nel path interattivo validation DB ⚠️ VERIFIED
BR-BOOK-009 BOOK_SCHEDULE esige START/END_DATETIME NOT NULL + FK verso demand/time-type validation DB VERIFIED
BR-BOOK-010 Nessun vincolo DB anti-doppia-prenotazione (no trigger, no unique su entità+intervallo) validation DB (assenza) ⚠️ VERIFIED
BR-BOOK-011 InsertDemand e InsertScheduleWithElement non sono in una transazione unica → domanda orfana possibile state-transition BL/DB ⚠️ INFERRED
BR-BOOK-012 Creazione consentita solo con CanAll oppure (CanBook e tabella Current) permission UI VERIFIED
BR-BOOK-013 Utente senza CanAll può editare solo appuntamenti in stato Booked permission UI VERIFIED
BR-BOOK-014 Non è modificabile una serie con occorrenze Approved/Confirmed validation UI VERIFIED
BR-BOOK-015 DeleteDemand annulla (Activity.Cancel) solo gli elementi in stato Booked state-transition BL/UI VERIFIED
BR-BOOK-016 Update di serie ricorrente = cancellazione schedule Booked + re-insert occorrenze state-transition UI/BL VERIFIED
BR-BOOK-017 Bottoni di cambio stato visibili solo se attore ∈ CanGroup e stato-successivo valido permission UI VERIFIED
BR-BOOK-018 Notifica mail di approvazione "consumi" agli attori Confirm customer-specific BL VERIFIED
BR-BOOK-019 Alert soglia comfort (ore min/max + percentuali) attivato da IfConfortClassExists() customer-specific BL VERIFIED
BR-BOOK-020 Id di stato/attività e GUID workflow hard-coded (magic numbers) config-flag UI/BL ⚠️ VERIFIED
BR-BOOK-021 Path WCF: idActivity deve essere di tipo Create; salta l'anti-sovrapposizione e forza valori fissi validation BL ⚠️ VERIFIED
BR-BOOK-022 Finestra calendario di default: da SelectedDate-8gg a SelectedDate+38gg date-logic UI VERIFIED

⚠️ = regola a rischio (solo-UI, solo-DB, gap di vincolo, magic number, o bypass).


Dettaglio regole

BR-BOOK-001 — Entità spaziale obbligatoria

Tipo: validation · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Se e.Appointment.Resources.GetResourceByType(GroupEntity) è null l'inserimento viene annullato (e.Cancel = true) con radalert('Scegliere una entità spaziale!'). Nessuna scrittura DB. Evidenza: BookCenterWeb/UserControl/Schedule.ascx.cs:580-590.

BR-BOOK-002 — Tipo orario obbligatorio

Tipo: validation · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Se manca la risorsa GroupTimee.Cancel = true + radalert('Scegliere un tipo di orario!'). Evidenza: Schedule.ascx.cs:591-601.

BR-BOOK-003 — Anti-sovrapposizione occorrenze ⚠️ SOLO-UI

Tipo: validation · Enforcement: UI (rischio) · Conf.: VERIFIED · customer_specific: no Prima dell'insert si legge GetScheduleByEntity(...), si filtra sugli stati Booked (21) / Approved / Confirmed e, per ogni occorrenza, ExistsOccurenceInRangeDates(...) verifica 5 casi di overlap (uguaglianza, sovrapposizione sinistra/destra, contenimento reciproco). In conflitto → e.Cancel = true. Rischio: il controllo è esclusivamente lato UI. Non esiste alcun vincolo/trigger DB (cfr. BR-BOOK-010) né controllo nel path WCF (cfr. BR-BOOK-021): due sessioni concorrenti o l'app mobile possono creare prenotazioni sovrapposte. Inoltre l'enum Status in codice espone solo Booked=21/Canceled=22 (Approved/Confirmed commentati) → gli stati Approved/Confirmed usati nel filtro dipendono da id caricati altrove. Evidenza: Schedule.ascx.cs:602-651,1248-1286; Resources/Workflow.cs:12-23.

BR-BOOK-004 — Coerenza data inizio / fine ricorrenza

Tipo: date-logic · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Con ricorrenza attiva: se e.Appointment.Start > parsedRule.Range.RecursUntilradalert('La data inizio è maggiore della data fine ricorrenza') e e.Cancel = true. Evidenza: Schedule.ascx.cs:607-621.

BR-BOOK-005 — Espansione ricorrenza in N occorrenze

Tipo: calculation / date-logic · Enforcement: UI/BL · Conf.: VERIFIED · customer_specific: no La RecurrenceRule Telerik è espansa lato UI (parsedRule.Occurrences); per ogni occorrenza EndDateTime = occurrence + Duration (giorni/ore/minuti/secondi dell'appuntamento) e viene chiamata InsertScheduleWithElement. Risultato: N righe BOOK_SCHEDULE + N elementi DEM + N righe BOOK_SCHEDULE_WF_INTERFACE, tutte legate all'unica BOOK_DEMAND. Evidenza: Schedule.ascx.cs:677-698.

BR-BOOK-006 — Creazione elemento di workflow DEM (tipo Create)

Tipo: state-transition · Enforcement: BL · Conf.: SUPPORTED · customer_specific: no GetActivityToAddBook seleziona l'attività DEM il cui ActivityType.GUID == DEM.Constants.ActivityTypes.Create; GetElementAddedToBook esegue DEM.WorkflowCreatingActivity.Run(idActor) → crea l'elemento e ne restituisce l'id, assegnato a schedule.IdElement. Lo stato iniziale è governato dal workflow DEM (cross-schema DEM_TEST38, per analogia con FLOW-REQ-001). Evidenza: Schedule.ascx.cs:675,686,695; Resources/Workflow.cs:150-182.

BR-BOOK-007 — Ramo Current vs Stored (PTABLE)

Tipo: config-flag · Enforcement: mixed · Conf.: VERIFIED · customer_specific: no BookTable.Current=1 (dato operativo) / Stored=2 (storico) viaggia come parametro PTABLE. Nel path interattivo è sempre Current=1 (INSERT su BOOK_DEMAND/BOOK_SCHEDULE); con PTABLE=2 (import Excel/archiviazione) le procedure scrivono su BOOK_DEMAND_HISTORY/BOOK_SCHEDULE_HISTORY. Evidenza: Resources/Enumeration.cs:10-14; BookDAL.cs:851,1671; USER_SOURCE BOOK_INSERTDEMAND/BOOK_INSERTSCHEDULEWITHELEMENT (rami IF PTABLE=1/2).

BR-BOOK-008 — ID_USER/ID_CDP NOT NULL non popolati nel path interattivo ⚠️ SOLO-DB + gap dati

Tipo: validation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Vincoli DB confermati: BOOK_DEMAND.ID_USER NOT NULL (SYS_C001715692) e BOOK_DEMAND.ID_CDP NOT NULL (SYS_C001715693). La procedura BOOK_INSERTDEMAND inserisce i valori passati dal DAL (PID_USER, PID_CDP). Rischio: nel path interattivo schedBook_AppointmentInsert il DemandDTO valorizza Username/Subject/Description/Entity/IdEntity/IdTimeType/RecurrenceRule/BookingTable ma non IdUser/IdCdp → il DAL invia il default int = 0. Il vincolo NOT NULL è soddisfatto formalmente (0 ≠ null) ma le domande interattive risultano con ID_USER=0/ID_CDP=0, dato di scarsa qualità/non tracciabile. Nel path WCF entrambi sono valorizzati esplicitamente (GetIdUserByUserId, newBooking.idCdp). Evidenza: USER_CONSTRAINTS BOOK_DEMAND (C: "ID_USER" IS NOT NULL, "ID_CDP" IS NOT NULL); Schedule.ascx.cs:654-666 (assenza set IdUser/IdCdp); BookingReaderWCF.svc.vb:272,274; BookDAL.cs:1678-1679.

BR-BOOK-009 — Vincoli DB su BOOK_SCHEDULE

Tipo: validation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no START_DATETIME NOT NULL (SYS_C001713529), END_DATETIME NOT NULL (SYS_C001713530), PK ID_SCHEDULE, FK FK_BOOK_SCHEDULE_BOOK_DEMAND (verso BOOK_DEMAND), FK FK_BOOK_SCHEDULE_BOOK_TIME_TYP, FK FK_BOOK_SCHEDULE_ID_ASSOCIATION. Un'occorrenza non può quindi esistere senza domanda padre e senza date. Analogamente BOOK_DEMAND ha FK FK_BOOK_DEMAND_BOOK_TIME_TYPEIdTimeType deve esistere in BOOK_TIME_TYPE (nota: il path WCF forza IdTimeType=0, cfr. BR-BOOK-021). Evidenza: USER_CONSTRAINTS BOOK_SCHEDULE / BOOK_DEMAND.

BR-BOOK-010 — Nessun vincolo DB anti-doppia-prenotazione ⚠️ GAP

Tipo: validation · Enforcement: DB (assenza) · Conf.: VERIFIED · customer_specific: no Lookup su USER_TRIGGERS per BOOK_DEMAND/BOOK_SCHEDULE/BOOK_SCHEDULE_WF_INTERFACE/relative history: nessun trigger. USER_CONSTRAINTS: nessun UNIQUE su (entità, intervallo). L'unica difesa contro le sovrapposizioni è la UI (BR-BOOK-003), bypassabile da concorrenza o dal path WCF. Evidenza: USER_TRIGGERS (NONE); USER_CONSTRAINTS BOOK_SCHEDULE (solo PK + FK, nessun UNIQUE temporale).

BR-BOOK-011 — Assenza di transazione applicativa unica ⚠️

Tipo: state-transition · Enforcement: BL/DB · Conf.: INFERRED · customer_specific: no InsertDemand e InsertScheduleWithElement sono chiamate Remoting/procedure autonome distinte. BOOK_INSERTDEMAND non ha protezione transazionale; solo BOOK_INSERTSCHEDULEWITHELEMENT ha SAVEPOINT start_tran + EXCEPTION WHEN OTHERS THEN ROLLBACK TO start_tran; RAISE (rollback della singola occorrenza). Un errore in fase di occorrenza lascia persistita la BOOK_DEMAND già inserita → domanda senza occorrenze. Dedotto dalla struttura, non testato a runtime. Evidenza: Schedule.ascx.cs:666,688,697; USER_SOURCE BOOK_INSERTSCHEDULEWITHELEMENT (SAVEPOINT/ROLLBACK TO start_tran); USER_SOURCE BOOK_INSERTDEMAND (INSERT diretto, no savepoint).

BR-BOOK-012 — Permesso di creazione prenotazione

Tipo: permission · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Il form di inserimento è consentito solo se CanAll || (CanBook && IsCurrentTable); altrimenti schedBook_FormCreating annulla (e.Cancel = true). Le voci di toolbar/menu ("Prenotazione", import Excel, "Amministrazione") seguono la stessa logica (Amministrazione richiede CanAll). IsCurrentTable = tabella Current. Evidenza: Schedule.ascx.cs:388-392,1046-1054; IsCurrentTable def. :58.

BR-BOOK-013 — Edit limitato agli appuntamenti in stato Booked

Tipo: permission · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Se l'utente non ha CanAll, non sta aggiungendo occorrenze, e lo stato dell'appuntamento ≠ Booked (21) → il form è annullato. Evidenza: Schedule.ascx.cs:393-397.

BR-BOOK-014 — Serie con occorrenze approvate/confermate non modificabile

Tipo: validation · Enforcement: UI · Conf.: VERIFIED · customer_specific: no In AdvancedEdit di una serie (IsUpdateSeriesToBooking), se esistono occorrenze in stato Approved/Confirmedradalert('Non è possibile modificare una serie con occorrenze approvate o confermate!') e e.Cancel = true. Evidenza: Schedule.ascx.cs:398-414.

BR-BOOK-015 — Cancellazione domanda: annulla solo elementi Booked

Tipo: state-transition · Enforcement: BL/UI · Conf.: VERIFIED · customer_specific: no DeleteDemand scorre gli elementi della domanda ed esegue ChangeActivityState(..., Activity.Cancel (22)) solo per quelli in stato Booked (21); gli elementi in altri stati non vengono annullati. Evidenza: Schedule.ascx.cs:857-872; Resources/Workflow.cs:103-114 (ChangeActivityState).

BR-BOOK-016 — Update di serie ricorrente = delete + re-insert

Tipo: state-transition · Enforcement: UI/BL · Conf.: VERIFIED · customer_specific: no Nell'update, se non si sta aggiungendo un'occorrenza (!IsAddOccurenceToBooking) e c'è ricorrenza / serie: DeleteScheduleByIdDemand(..., Status.Booked) elimina le occorrenze Booked e poi le occorrenze vengono re-inserite con nuovo elemento DEM. Le occorrenze non-Booked (approvate/confermate) sopravvivono. Evidenza: Schedule.ascx.cs:801-848.

BR-BOOK-017 — Visibilità dei bottoni di cambio stato

Tipo: permission · Enforcement: UI · Conf.: VERIFIED · customer_specific: no In schedBook_AppointmentCreated, i bottoni di transizione sono generati solo se l'utente ha almeno uno tra CanAll/CanConfirm/CanApprove/CanBook (in tabella Current) e, per ciascuna attività, solo se l'attore è presente in CanGroup, lo stato-successivo ≠ "0" e diverso dallo stato corrente. Evidenza: Schedule.ascx.cs:888-917.

BR-BOOK-018 — Notifica mail approvazione "consumi" (customer-specific)

Tipo: customer-specific · Enforcement: BL · Conf.: VERIFIED · customer_specific: All'attività Approve, NotifyApproved invia mail agli indirizzi degli attori Actor.Confirm con corpo "...sono stati approvati i seguenti consumi...". La terminologia ("edificio", "consumi", "ore approvate") indica un adattamento del modulo prenotazioni a un contesto di gestione consumi/energia specifico del cliente, non generico "sala/postazione". Evidenza: Schedule.ascx.cs:212-250 (NotifyApproved, body "consumi").

BR-BOOK-019 — Alert soglia comfort (customer-specific, config-flag)

Tipo: customer-specific / config-flag · Enforcement: BL · Conf.: VERIFIED · customer_specific: NotifyAlert è eseguito solo se IfConfortClassExists() è vero (feature-flag di configurazione). Calcola totHours = TotHoursByEntity(..., Status.Approved) per l'entità, recupera MinHours/MaxHours dalla ConfortClass e le percentuali GetConfortAlert() ([minPerc, maxPerc]); invia alert se totHours >= (maxPerc/100)*maxHours (soglia massima) oppure totHours <= minHours + (minPerc/100)*minHours (soglia minima). Logica di capacità/soglia specifica del dominio comfort/energia. Evidenza: Schedule.ascx.cs:215-216,252-309; BookControllers/BookController.cs:102-104,126-128 (GetConfortAlert, IfConfortClassExists).

BR-BOOK-020 — Id di stato/attività e GUID workflow hard-coded ⚠️ MAGIC NUMBERS

Tipo: config-flag · Enforcement: UI/BL · Conf.: VERIFIED · customer_specific: no Id hard-coded in Resources.Workflow: Status.Booked=21, Canceled=22; Activity.Book=21, Cancel=22, Update=26, View=29, Overwrite=32, Add=35, Delete=38. GUID di fallback del workflow hard-coded e1db8d10-7319-44f2-a994-11f01ee9e2bb usato quando BookWorkFlows.Count != 1. Enum Actor (Book=22221 … Confirm=22223) e i riferimenti Actor.Confirm sono in parte commentati/deprecati (GetActorListByCan/SetPermissionToWorkflow risultano richiamati ma con definizione commentata nel sorgente ispezionato → possibile disallineamento del codice). Questi id devono corrispondere ai record del catalogo DEM/BOOK sul DB: cambiando ambiente/cliente il rischio è di mismatch silenzioso. Evidenza: Resources/Workflow.cs:12-39,51-58,42-48; riferimenti Schedule.ascx.cs:224,671; BookingReaderWCF.svc.vb:248-254 (stesso set di id attività).

BR-BOOK-021 — Path WCF: attività Create obbligatoria, anti-overlap bypassato ⚠️

Tipo: validation / permission · Enforcement: BL · Conf.: VERIFIED · customer_specific: no CreateNewBooking (mobile/integrazione) accetta la creazione solo se activity.ActivityType.GUID == ActivityTypes.Create, altrimenti "IDACTIVITY specificato non corrisponde ad una azione di Creazione". Condivide lo stesso BL (InsertDemand + InsertScheduleWithElement) ma non esegue né la validazione entità/orario né l'anti-sovrapposizione (BR-BOOK-001/002/003) e forza valori fissi: IdTimeType=0, RecurrenceRule="", idServicelist={-1}. Quindi le regole di sovrapposizione e di tipo orario valgono solo per il path UI. Evidenza: BookingReaderWCF.svc.vb:258-313 (guardia Create :266, valori fissi :279-281,290).

BR-BOOK-022 — Finestra calendario di default

Tipo: date-logic · Enforcement: UI · Conf.: VERIFIED · customer_specific: no Il range di caricamento del calendario è impostato a FromDate = SelectedDate.AddDays(-8) e ToDate = SelectedDate.AddDays(38) (magic numbers: 8 giorni indietro, 38 avanti dal primo del mese selezionato). Influenza quali prenotazioni sono visibili e quindi il set su cui opera l'anti-sovrapposizione UI. Evidenza: Schedule.ascx.cs:190-192.


Sintesi rischi (flag)

  • Solo-UI (bypassabili): BR-BOOK-001, 002, 003 (anti-overlap), 004, 012, 013, 014, 017.
  • Solo-DB (invisibili alla UI): BR-BOOK-008 (NOT NULL ID_USER/ID_CDP), BR-BOOK-009 (NOT NULL date + FK).
  • Gap di vincolo DB: BR-BOOK-010 (nessun trigger/unique anti-doppia-prenotazione).
  • Transazionalità: BR-BOOK-011 (domanda orfana possibile).
  • Magic numbers / hard-coded id: BR-BOOK-020 (stati/attività/GUID), BR-BOOK-022 (finestra ±8/38 gg), BR-BOOK-021 (IdTimeType=0, service -1).
  • Date-sensitive: BR-BOOK-004, 005, 022.
  • Customer-specific: BR-BOOK-018 (notifica consumi), BR-BOOK-019 (soglie comfort/energia).
  • Bypass di path: BR-BOOK-021 (WCF salta validazioni e anti-overlap del path UI).

Open questions

  • Da dove provengono a runtime gli id di stato Approved/Confirmed usati nel filtro anti-sovrapposizione, dato che l'enum Status in Workflow.cs li ha commentati (solo Booked=21/Canceled=22)? Possibile disallineamento tra sorgente ispezionato e binario in esercizio.
  • GetActorListByCan/SetPermissionToWorkflow sono richiamati (Schedule.ascx.cs:671,1030) ma definiti solo in forma commentata nel Workflow.cs ispezionato: verificare l'esistenza di una definizione attiva (partial/altro file) o confermare che si tratta di uno snapshot non compilabile.
  • Comportamento reale di cleanup della BOOK_DEMAND in caso di fallimento di InsertScheduleWithElement (BR-BOOK-011), da verificare a runtime.
  • Le tabelle DEM esatte toccate da WorkflowCreatingActivity.Run in questo flusso sono assunte per analogia con FLOW-REQ-001 (BR-BOOK-006).