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 OracleINFOCAD_TEST38, front-end ASP.NET Web Forms (VB.NET) ScheduleWeb/ScheduleCenter + servizio server (Controller/BL/DAL), nessun ORM (stored procedure via DALExecute*StoredProcedure).La creazione ODL ha tre entry-point che convergono sullo stesso
WorkOrderController.CreateWorkOrder→WorkOrder_BL→WorkOrder_DAL→ SPMNT_GETNEWPROTOCOL+MNT_ADDWORKORDER: (1) scheda interattivaWorkOrdersNew.aspx, (2) WCFScheduleReaderWCF.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: sì
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 authorContactId →
PAUTHOR → MAINT_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 = 2del piano) e BR-MNT-009/010 (esistenza + denormalizzazione joblist/oggetto) vivono interamente inMNT_ADDWORKORDER; non hanno controparte applicativa. - Magic numbers / hard-coded id: grant
3630;STATUS = 0;STATE = 2; WorkingStatus2/3; feedback archiviazione3; feedback iniziale0;PROTOCOLsize15; 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(defaultTrue) e gli altri flag diMaintenanceSettings(EnableTimeTrack,UseTermDaysForEndDate) che governano il calcolo diPlan_Endnel 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.