Table of Contents

BR-MNT — Regole di business del dominio Manutenzione / Maintenance

Regole estratte dal dominio Manutenzione / Maintenance di Infocad, ancorate al flusso pilota FLOW-MNT-001 (creazione di un Ordine di Lavoro / ODL a partire da un Piano di manutenzione) e alla relativa evidenza. Sistema: Infocad (Descor), backend Oracle INFOCAD_TEST38, front-end ASP.NET Web Forms (VB.NET) ScheduleWeb/ScheduleCenter + servizio server (Controller/BL/DAL), nessun ORM (stored procedure via DAL Execute*StoredProcedure).

La creazione ODL ha tre entry-point che convergono sullo stesso WorkOrderController.CreateWorkOrderWorkOrder_BLWorkOrder_DAL → SP MNT_GETNEWPROTOCOL + MNT_ADDWORKORDER: (1) scheda interattiva WorkOrdersNew.aspx, (2) WCF ScheduleReaderWCF.CreateWorkOrder, (3) processo batch di schedulazione (Plan_BL.SchedulePlan/Replan). Le regole sotto coprono: permessi/accesso, idempotenza per piano, transizioni di stato di Piano/ODL, logica di data, denormalizzazione e vincoli DB, la formula-protocollo customer-specific e le varianti del path batch.

Legenda enforcement: UI = validato solo lato interfaccia/code-behind · BL = logica applicativa (controller/BL/DAL) · DB = vincolo/logica in stored procedure o constraint · mixed = più livelli. Legenda confidence: VERIFIED = catena di codice + controprova indipendente (sorgente DB su USER_SOURCE) · SUPPORTED = evidenza di codice/sorgente coerente ma un anello non eseguito a runtime · INFERRED = dedotto dalla struttura, non testato.

Le stored procedure MNT_* citate sono state confermate con lookup read-only su USER_SOURCE dello schema INFOCAD_TEST38 (driver oracledb thin, sola lettura del testo delle procedure — nessun accesso a dati di business, nessuna DML/DDL, nessuna credenziale stampata).


Registro regole

ID Regola Tipo Enforcement Conf.
BR-MNT-001 Creazione ODL da scheda: grant di sezione 3630 oppure SuperAdmin permission UI ⚠️ VERIFIED
BR-MNT-002 Path WCF: sessione valida (DecryptLoginId ≠ Guid.Empty + ValidateClientSession) permission BL VERIFIED
BR-MNT-003 Idempotenza per piano: se P.ID_ODL > 0 ritorna l'ODL esistente, nessuna scrittura validation BL/DAL VERIFIED
BR-MNT-004 ODL creato con STATUS = 0 (stato iniziale) state-transition BL/DB VERIFIED
BR-MNT-005 La creazione ODL porta il Piano di origine a STATE = 2 e ne valorizza ID_ODL state-transition DB VERIFIED
BR-MNT-006 OPEN_DATE dell'ODL da Plan_Date solo se EnableStartDateOnODLCreation, altrimenti NULL config-flag BL VERIFIED
BR-MNT-007 Protocollo ODL generato da formula configurata in MAINT_PROTOCOLFORMAT (EXECUTE IMMEDIATE) calculation DB ⚠️ VERIFIED
BR-MNT-008 Alla creazione: CREATION_DATE = Today, CLOSE_DATE = NULL date-logic BL VERIFIED
BR-MNT-009 MNT_ADDWORKORDER esige joblist e oggetto esistenti (SELECT INTO → NO_DATA_FOUND) validation DB ⚠️ INFERRED
BR-MNT-010 Nome/descrizione di joblist e oggetto denormalizzati nella riga MAINT_ODL calculation DB VERIFIED
BR-MNT-011 Feedback dell'ODL inizializzato a 0 alla creazione (DELETE+INSERT MAINT_FEEDBACK_ODL) state-transition DB SUPPORTED
BR-MNT-012 Attività e asset dell'ODL materializzati da joblist/oggetto (MNT_SETODLACTIVITY/MNT_SETODLASSET) calculation DB SUPPORTED
BR-MNT-013 Batch: ODL generato solo se l'impianto NON è in fermo permanente (WorkingStatus < 3) validation BL ⚠️ VERIFIED
BR-MNT-014 Batch: impianto in fermo temporaneo (=2) + Plan_Date < Now → ODL archiviato automaticamente (feedback 3) state-transition BL ⚠️ VERIFIED
BR-MNT-015 Batch: assegnatario dell'ODL = OJ.IdContactAssigned calculation BL VERIFIED
BR-MNT-016 Autore dell'ODL = contatto dell'utente loggato (usrSettings.Id_Contact) calculation BL VERIFIED
BR-MNT-017 Replan: nuovo Piano State = 2, date traslate dello stesso gap, ODL al responsabile del Management state-transition BL VERIFIED
BR-MNT-018 Stamping di audit via sessione DB (DBUSERSESSION = utente, DBSOURCESESSION = "INFOCADSERVER") config-flag BL/DB VERIFIED
BR-MNT-019 PROTOCOL limitato a 15 caratteri (parametro OUT VARCHAR2(15)) validation BL ⚠️ VERIFIED
BR-MNT-020 Visibilità/ricerca ODL filtrata per contatto dell'utente, salvo SuperAdmin (contatto = 0) permission BL VERIFIED
BR-MNT-021 Path batch/replan crea l'ODL con throwExceptionIfExists = False (nessuna eccezione su piano già evaso) config-flag BL VERIFIED

⚠️ = regola a rischio (solo-UI, solo-DB, magic number, hard-coded id, o eccezione DB non intercettata).


Dettaglio regole

BR-MNT-001 — Accesso alla creazione ODL: grant 3630 o SuperAdmin

Tipo: permission · Enforcement: UI ⚠️ · Conf.: VERIFIED · customer_specific: no Nella scheda WorkOrdersNew.aspx, WorkOrdersNew_Init verifica HasUserGrant("3630"); se il grant è assente e l'utente non è SuperAdmin → ThrowSectionAccessException(). Grant hard-coded (magic id 3630). Regola solo-UI: il controller/BL non ri-verifica il grant, quindi un chiamante server-side (es. batch) non è soggetto a questo gate. Evidenza: ScheduleWeb/UserControls/WorkOrders/WorkOrdersNew.aspx.vb:75-79.

BR-MNT-002 — Path WCF: sessione valida

Tipo: permission · Enforcement: BL · Conf.: VERIFIED · customer_specific: no ScheduleReaderWCF.CreateWorkOrder(loginkey, id_plan, ...) richiede DecryptLoginId(loginkey) ≠ Guid.Empty e ValidateClientSession(loginId) non nullo prima di inoltrare a WorkOrderController.CreateWorkOrder. È il gate del path programmatico equivalente (in sostituzione del grant di sezione UI). Evidenza: CommonWeb/ScheduleCenter/WebServices/ScheduleReaderWCF.svc.vb:902-906.

BR-MNT-003 — Idempotenza per piano

Tipo: validation · Enforcement: BL/DAL · Conf.: VERIFIED · customer_specific: no WorkOrder_BL.CreateWorkOrder carica il Piano P; se P.ID_ODL > 0 l'ODL esiste già e viene restituito senza alcuna scrittura (SelectById(P.ID_ODL)). La DAL applica lo stesso guardiano: il blocco di insert è racchiuso in If P.ID_ODL = 0 Then. Un piano genera quindi al più un ODL. Evidenza: MaintenanceBL/WorkOrder_BL.vb:50-51; MaintenanceDAL/OracleODP/WorkOrder_DAL.vb:91.

BR-MNT-004 — Stato iniziale STATUS = 0

Tipo: state-transition · Enforcement: BL/DB · Conf.: VERIFIED · customer_specific: no La DAL passa PSTATUS = 0 (parametro statusParam) e MNT_ADDWORKORDER lo scrive tal quale in MAINT_ODL.STATUS. Magic number 0 = stato "creato/aperto" iniziale dell'ODL. Evidenza: WorkOrder_DAL.vb:108; MNT_ADDWORKORDER src:3,32-35 (STATUS ... VALUES (... PSTATUS ...)).

BR-MNT-005 — Piano di origine portato a STATE = 2

Tipo: state-transition · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Dentro MNT_ADDWORKORDER, dopo l'INSERT dell'ODL: UPDATE MAINT_PLAN SET ID_ODL = PIDODL, STATE = 2 WHERE ID_PLAN = PIDPLAN. Il Piano passa quindi allo stato "eseguito/con ODL" (magic number 2) e viene collegato all'ODL appena creato — la controparte della regola di idempotenza BR-MNT-003. Evidenza: MNT_ADDWORKORDER src:37-39.

BR-MNT-006 — OPEN_DATE condizionata da EnableStartDateOnODLCreation

Tipo: config-flag · Enforcement: BL · Conf.: VERIFIED · customer_specific: no (flag di deployment) Se il flag di configurazione EnableStartDateOnODLCreation è attivo, POPENDATE = P.Plan_Date (data pianificata); altrimenti DBNull.Value (NULL). Flag definito in MaintenanceSettings (sezione InfocadServer/Maintenance, chiave enableStartDateOnODLCreation) con default True. Hidden flag: il comportamento della data di apertura dipende dalla configurazione dell'installazione. Evidenza: WorkOrder_DAL.vb:113-118; Configuration/MaintenanceSettings.vb:15-23.

BR-MNT-007 — Protocollo da formula MAINT_PROTOCOLFORMAT

Tipo: calculation · Enforcement: DB ⚠️ · Conf.: VERIFIED · customer_specific: MNT_GETNEWPROTOCOL legge SELECT PROTOCOLFORMULA INTO tmpSelect FROM MAINT_PROTOCOLFORMAT (senza WHERE), conta i parametri con REGEXP_COUNT(..., ':[A-Za-z0-9_]+') e la esegue via EXECUTE IMMEDIATE ... INTO P_PROTOCOL [USING P_IDOJ]. Il formato del protocollo è quindi configurazione per installazione/tenant (customer-specific). ⚠️ La SELECT ... INTO senza WHERE assume cardinalità 1: se MAINT_PROTOCOLFORMAT contiene più di una riga → TOO_MANY_ROWS; se è vuota → NO_DATA_FOUND. Il protocollo è letto come OUT VARCHAR2(15) (cfr. BR-MNT-019). Evidenza: MNT_GETNEWPROTOCOL src:8,11-17; WorkOrder_DAL.vb:92-102.

BR-MNT-008 — CREATION_DATE = Today, CLOSE_DATE = NULL

Tipo: date-logic · Enforcement: BL · Conf.: VERIFIED · customer_specific: no La DAL fissa PCREATIONDATE = Today (data odierna del server applicativo) e PCLOSEDATE = DBNull.Value. L'ODL nasce quindi con data di creazione = oggi e senza data di chiusura. Evidenza: WorkOrder_DAL.vb:111,119; MNT_ADDWORKORDER src:6,9,32-35.

BR-MNT-009 — Joblist e oggetto devono esistere

Tipo: validation · Enforcement: DB ⚠️ · Conf.: INFERRED · customer_specific: no MNT_ADDWORKORDER esegue SELECT NAME, COALESCE(DESCRIPTION,'---') INTO ... FROM MAINT_JOBLISTS WHERE ID_JL = PIDJL e l'analoga su GLOBAL_OBJECTS WHERE ID_OBJ = PIDOBJ. Se PIDJL/PIDOBJ non esistono la SELECT ... INTO solleva NO_DATA_FOUND (non gestito nella procedura) → rollback della transazione ODP.NET. Regola solo-DB, dedotta dalla semantica SELECT INTO (non testata a runtime). Evidenza: MNT_ADDWORKORDER src:19-30.

BR-MNT-010 — Denormalizzazione nome/descrizione in MAINT_ODL

Tipo: calculation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Nome e descrizione di joblist (v_JlName/v_JlDesc) e oggetto (v_OiName/v_OiDesc) sono copiati nella riga MAINT_ODL (JL_NAME, JL_DESCRIPTION, OBJ_NAME, OBJ_DESCRIPTION) con fallback '---' sulla descrizione mancante. Snapshot al momento della creazione (non aggiornato se la sorgente cambia). Evidenza: MNT_ADDWORKORDER src:19-35.

BR-MNT-011 — Feedback inizializzato a 0

Tipo: state-transition · Enforcement: DB · Conf.: SUPPORTED · customer_specific: no MNT_ADDWORKORDER chiama MNT_SETODLFEEDBACK(PIDODL, 0), che esegue DELETE FROM MAINT_FEEDBACK_ODL + INSERT INTO MAINT_FEEDBACK_ODL (...) inizializzando il feedback dell'ODL a 0 (non lavorato). SUPPORTED: confermato sul sorgente della nested, non eseguito end-to-end a runtime. Evidenza: MNT_ADDWORKORDER src:43; MNT_SETODLFEEDBACK src:23,26.

BR-MNT-012 — Materializzazione attività e asset da joblist/oggetto

Tipo: calculation · Enforcement: DB · Conf.: SUPPORTED · customer_specific: no MNT_SETODLACTIVITY(PIDODL, PIDJL) popola MAINT_ODL_ACTIVITY dalle attività della joblist e MNT_SETODLASSET(PIDODL, PIDOBJ) popola MAINT_ODL_ASSET dagli asset dell'oggetto/impianto. Il contenuto dell'ODL è quindi derivato al momento della creazione da joblist + oggetto di origine. Evidenza: MNT_ADDWORKORDER src:41-42; MNT_SETODLACTIVITY src:6, MNT_SETODLASSET src:6.

BR-MNT-013 — Batch: nessun ODL se impianto in fermo permanente

Tipo: validation · Enforcement: BL ⚠️ · Conf.: VERIFIED · customer_specific: no Nella generazione batch (Plan_BL.SchedulePlan), l'ODL viene creato solo se createWorkOrder è attivo, il piano non ha già un ODL (P.ID_ODL = 0) e l'impianto non è in fermo permanente: obj.InheritedWorkingStatus < 3 AndAlso obj.WorkingStatus < 3. Magic number 3 = "fermo permanente". Regola presente solo nel path batch (non nella creazione manuale da scheda). Evidenza: MaintenanceBL/Plan_BL.vb:1710-1712,1718.

BR-MNT-014 — Batch: fermo temporaneo → archiviazione automatica ODL a data passata

Tipo: state-transition · Enforcement: BL ⚠️ · Conf.: VERIFIED · customer_specific: no Se l'impianto è in fermo temporaneo (InheritedWorkingStatus = 2 OrElse WorkingStatus = 2) e l'ODL appena generato ha Plan_Date < Now, l'ODL viene subito archiviato: ArchiveWorkOrder(username, WO.ID_DTO, 3, "Impianto in stato di fermo temporaneo", Nothing, Nothing). Magic numbers: 2 = fermo temporaneo, 3 = feedback di archiviazione. Messaggio hard-coded in italiano. Evidenza: Plan_BL.vb:1723-1728.

BR-MNT-015 — Batch: assegnatario = OJ.IdContactAssigned

Tipo: calculation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Nella generazione batch l'ODL è assegnato al contatto configurato sull'oggetto-joblist: daoODL.CreateWorkOrder(username, P.ID_DTO, OJ.IdContactAssigned, False). (Nel path interattivo l'assegnatario proviene invece dalla selezione UI ContactListShort1.SelectedContactID.) Evidenza: Plan_BL.vb:1718; WorkOrdersNew.aspx.vb:104.

BR-MNT-016 — Autore = contatto dell'utente loggato

Tipo: calculation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no WorkOrder_BL.CreateWorkOrder risolve il contatto dell'utente via InfocadLoginSettingsProvider.LoadByUsername(username).Id_Contact e lo passa come authorContactIdPAUTHORMAINT_ODL.ID_AUTHOR. L'autore dell'ODL è quindi l'identità che esegue la creazione. Evidenza: WorkOrder_BL.vb:53-55; WorkOrder_DAL.vb:120; MNT_ADDWORKORDER src:10,33.

BR-MNT-017 — Replan: clone del piano con date traslate e nuovo ODL

Tipo: state-transition · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Plan_BL.Replan clona il piano originale (ID_DTO = 0), calcola dateGap = newPlanDate - Plan_Date e trasla Plan_Date/Plan_End/Alert_Date dello stesso gap, imposta State = 2, inserisce il nuovo piano e crea l'ODL con responsabile = Management.Id_Resp (se presente). Infine collega vecchio/nuovo ODL via SetReplannedWorkOrder. Evidenza: Plan_BL.vb:1762-1774.

BR-MNT-018 — Audit stamping via sessione DB

Tipo: config-flag · Enforcement: BL/DB · Conf.: VERIFIED · customer_specific: no La DAL apre il DataLayer con parametri di sessione DBUSERSESSION = username e DBSOURCESESSION = "INFOCADSERVER" (stringa hard-coded), usati dai trigger di audit lato DB per attribuire le scritture all'utente e alla sorgente applicativa. Evidenza: WorkOrder_DAL.vb:85-88.

BR-MNT-019 — PROTOCOL limitato a 15 caratteri

Tipo: validation · Enforcement: BL ⚠️ · Conf.: VERIFIED · customer_specific: no Il parametro OUT del protocollo è dichiarato New OracleParameter("P_PROTOCOL", OracleDbType.Varchar2, 15) con nota esplicita nel codice su un bug del costruttore ODP.NET sul size. Magic number 15: un protocollo generato dalla formula più lungo di 15 caratteri verrebbe troncato/rifiutato lato client. Evidenza: WorkOrder_DAL.vb:93-95.

BR-MNT-020 — Visibilità ODL filtrata per contatto (salvo SuperAdmin)

Tipo: permission · Enforcement: BL · Conf.: VERIFIED · customer_specific: no In WorkOrder_BL.GetOdlIds il filtro di contatto passato alla DAL è CInt(IIf(usrSettings.IsSuperAdmin, 0, usrSettings.Id_Contact)): il SuperAdmin vede tutti gli ODL (contatto = 0 = nessun filtro), gli altri utenti sono ristretti agli ODL del proprio contatto. Evidenza: WorkOrder_BL.vb:83.

BR-MNT-021 — Batch/replan: throwExceptionIfExists = False

Tipo: config-flag · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Il path batch (Plan_BL.vb:1718) e il replan (Plan_BL.vb:1772) invocano CreateWorkOrder con l'ultimo parametro False, mentre il default della firma (usato dalla scheda/WCF) è True. In batch un piano già evaso non genera errore ma restituisce silenziosamente l'ODL esistente (coerente con BR-MNT-003). Evidenza: WorkOrder_BL.vb:44 (default True); Plan_BL.vb:1718,1772 (False).


Note trasversali (rischi & varianti)

  • Solo-UI: BR-MNT-001 (grant 3630) è l'unico gate di autorizzazione della creazione manuale; non ri-verificato lato BL/DB → chiamate server-side/batch non sono soggette al grant.
  • Solo-DB: BR-MNT-005 (STATE = 2 del piano) e BR-MNT-009/010 (esistenza + denormalizzazione joblist/oggetto) vivono interamente in MNT_ADDWORKORDER; non hanno controparte applicativa.
  • Magic numbers / hard-coded id: grant 3630; STATUS = 0; STATE = 2; WorkingStatus 2/3; feedback archiviazione 3; feedback iniziale 0; PROTOCOL size 15; sorgente audit "INFOCADSERVER".
  • Date logic: BR-MNT-006 (open date condizionata da flag) e BR-MNT-008 (creation=oggi, close=NULL); BR-MNT-017 (traslazione uniforme del gap in replan).
  • Hidden flags: EnableStartDateOnODLCreation (default True) e gli altri flag di MaintenanceSettings (EnableTimeTrack, UseTermDaysForEndDate) che governano il calcolo di Plan_End nel batch (Plan_BL.vb:1690-1698).
  • Varianti customer-specific: BR-MNT-007 — il formato del protocollo è dato di configurazione (MAINT_PROTOCOLFORMAT.PROTOCOLFORMULA) eseguito dinamicamente, quindi varia per installazione/tenant; l'assunzione di riga singola è un rischio operativo se la tabella viene popolata con più formule.