Table of Contents

FLOW-MNT-001 — Creazione di un Ordine di Lavoro (ODL / Work Order) da Piano di manutenzione

Flusso end-to-end di creazione di un Ordine di Lavoro (ODL) del modulo Manutenzione / Maintenance a partire da un Piano (Plan). Path pilota: scheda WorkOrdersNew.aspx (ScheduleWeb / ScheduleCenter) — l'operatore genera manualmente l'ODL per un piano schedulato. Backend Oracle INFOCAD_TEST38, accesso via stored procedure ODP.NET (nessun ORM). L'entità è persistita nella tabella MAINT_ODL (protocollo generato da MNT_GETNEWPROTOCOL).

  • Flow ID: FLOW-MNT-001
  • Repository: InfocadWeb (ASP.NET Web Forms, VB.NET, ScheduleWeb + CommonWeb/ScheduleCenter) + InfocadServer (MaintenanceControllers/BL/DAL, VB.NET)
  • Operazione: WRITE (create) — creazione ODL
  • Confidence complessiva: VERIFIED (catena UI → code-behind → controller → BL → DAL → stored procedure, confermata su codice e su sorgente DB via USER_SOURCE; tabelle target confermate su USER_TABLES/USER_TAB_COLUMNS)

Obiettivo di business

Consentire a un operatore della Manutenzione (o a un'integrazione programmatica / batch di schedulazione) di materializzare un Ordine di Lavoro a partire da un Piano di manutenzione schedulato. L'ODL rappresenta l'ordine operativo assegnato a un contatto/tecnico per l'esecuzione delle attività (MAINT_ODL_ACTIVITY) su un insieme di asset (MAINT_ODL_ASSET), con protocollo univoco e stato di lavorazione. Al termine l'ODL esiste in MAINT_ODL, il Piano di origine è collegato all'ODL (MAINT_PLAN.ID_ODL) e portato in stato "eseguito" (STATE = 2).

Attori

  • Operatore Manutenzione / Schedulazione (utente autenticato con grant 3630 sulla sezione "crea ODL", oppure SuperAdmin) — path interattivo scheda WorkOrdersNew.aspx.
  • Sistemi esterni / integrazioni — WCF ScheduleReaderWCF.svc (CreateWorkOrder(loginkey, id_plan, ...)), che dopo validazione della sessione richiama lo stesso WorkOrderController.CreateWorkOrder.
  • Processo batch di schedulazione (generazione automatica piani → ODL) — Plan_BL (SchedulePlan/ processo OJ), che per ogni piano generato invoca WorkOrderDAL.CreateWorkOrder(...) (stessa DAL).
  • Oracle INFOCAD_TEST38 (hub manutenzione; procedure standalone MNT_ADDWORKORDER, MNT_GETNEWPROTOCOL e nested MNT_SETODLACTIVITY/MNT_SETODLASSET/MNT_SETODLFEEDBACK).

Trigger

Click sul pulsante Applica/Crea ODL della scheda WorkOrdersNew.aspx: evento btnApply_Click gestito in WorkOrdersNew.aspx.vb:101, che invoca WorkOrderController.CreateWorkOrder(UserName, ID_DTO, SelectedContactID) (:104), dove ID_DTO è l'ID_PLAN del piano (passato via querystring IDP).

Frontend entry point

  • Shell: ScheduleCenter (modello shell-page CASSANDRA).
  • Control scheda: InfocadWeb/WebMachine/CASSANDRA/ScheduleWeb/UserControls/WorkOrders/WorkOrdersNew.aspx (+ code-behind WorkOrdersNew.aspx.vb). Il piano viene caricato in WorkOrdersNew_DataBinding (:61) via PlanController.SelectById, e la lista contatti/aziende assegnabili è popolata da ContactListShort1.
  • Gate di accesso (UI): WorkOrdersNew_Init (:75) verifica HasUserGrant("3630") — se assente e non SuperAdmin → ThrowSectionAccessException() (:76-78).

Sequenza principale (main sequence)

  1. Operatore apre WorkOrdersNew.aspx?IDP=<id_plan>; Page_Load (:81) imposta ID_DTO dalla querystring e fa DataBind (carica il Plan e i contatti assegnabili).
  2. Operatore seleziona il contatto/tecnico assegnatario e preme ApplicabtnApply_Click (WorkOrdersNew.aspx.vb:101).
  3. btnApply_Click istanzia WorkOrderController e chiama CreateWorkOrder(UserName, ID_DTO, ContactListShort1.SelectedContactID) (:104).
  4. WorkOrderController.CreateWorkOrder (WorkOrderController.vb:12) inoltra al BL/DAO: DirectCast(Me.DAO, IWorkOrder_BL).CreateWorkOrder(...) (:14).
  5. WorkOrder_BL.CreateWorkOrder (WorkOrder_BL.vb:44):
    • carica il piano P via Plan_BL.SelectById(username, id_plan) (:47);
    • se P.ID_ODL > 0 l'ODL esiste già → ritorna l'ODL esistente (SelectById, :51) — nessuna scrittura;
    • altrimenti risolve il contatto dell'utente (InfocadLoginSettingsProvider.LoadByUsernameusrSettings.Id_Contact, :53-54) e chiama la DAL: WorkOrderDAL.CreateWorkOrder(username, P, usrSettings.Id_Contact, assignedUserID, throwExceptionIfExists) (:55);
    • ricarica e restituisce il WorkOrder appena creato via SelectById(idWO) (:56).
  6. WorkOrder_DAL.CreateWorkOrder (WorkOrder_DAL.vb:84) apre un DataLayer con parametri di sessione DB DBUSERSESSION=username, DBSOURCESESSION="INFOCADSERVER" (:85-88) e, se P.ID_ODL = 0 (:91):
    • genera il protocollo: parametri P_IDOJ = P.ID_OJ (IN), P_PROTOCOL (OUT VARCHAR2 size 15) → ExecuteNonQueryStoredProcedure("MNT_GETNEWPROTOCOL") (:92-99); legge il protocollo (:102);
    • ClearParameter() (:105) e prepara i parametri dell'insert: PIDPLAN = P.ID_DTO, PPROTOCOL, PSTATUS = 0, PIDOBJ = P.ID_Obj, PIDJL = P.ID_JL, PCREATIONDATE = Today, PASSIGNED = assignedUserID, POPENDATE (= P.Plan_Date se EnableStartDateOnODLCreation, altrimenti NULL, :114-118), PCLOSEDATE = NULL, PAUTHOR = authorContactId, PIDODL (OUT) (:106-133);
    • crea l'ODL: ExecuteNonQueryStoredProcedure("MNT_ADDWORKORDER") (:135);
    • ritorna il nuovo id da PIDODL (:137).
  7. Oracle MNT_GETNEWPROTOCOL (INFOCAD_TEST38): legge la formula protocollo da MAINT_PROTOCOLFORMAT (src:8) e la esegue via EXECUTE IMMEDIATE ... USING P_IDOJ (o senza parametri) restituendo il protocollo in P_PROTOCOL (src:11-17).
  8. Oracle MNT_ADDWORKORDER (INFOCAD_TEST38, procedura standalone):
    • denormalizza nome/descrizione della joblist da MAINT_JOBLISTS (src:19-24) e dell'oggetto/impianto da GLOBAL_OBJECTS (src:25-30);
    • INSERT INTO MAINT_ODL con ID_ODL = SEQ_MAINT_ODL.NEXTVAL, RETURNING ID_ODL INTO PIDODL (src:32-35);
    • UPDATE MAINT_PLAN SET ID_ODL = PIDODL, STATE = 2 WHERE ID_PLAN = PIDPLAN (src:37-39);
    • popola le attività dell'ODL via MNT_SETODLACTIVITY(PIDODL, PIDJL) → INSERT MAINT_ODL_ACTIVITY (src:41);
    • popola gli asset dell'ODL via MNT_SETODLASSET(PIDODL, PIDOBJ) → INSERT MAINT_ODL_ASSET (src:42);
    • inizializza il feedback via MNT_SETODLFEEDBACK(PIDODL, 0) → DELETE+INSERT MAINT_FEEDBACK_ODL (src:43).
  9. La DAL legge PIDODL come nuovo id e lo propaga al BL, che ricarica l'ODL e lo restituisce.
  10. Post-salvataggio (UI): RegisterStartupScript("SubmitWindow(<ID_DTO>)") (:105); in caso di eccezione, il messaggio è mostrato in divError.InnerText (:107).

API / service

  • Path interattivo: nessun servizio SOAP/WCF — postback ASP.NET Web Forms diretto sulla scheda WorkOrdersNew.aspx; il controller server è richiamato in-process (referenza DLL Descor.Maintenance.MaintenanceControllers).
  • Path programmatico equivalente (stesso controller → stesso BL/DAL → stessa stored procedure): WCF ScheduleReaderWCF.svc (CommonWeb/ScheduleCenter/WebServices/ScheduleReaderWCF.svc.vb): CreateWorkOrder(loginkey, id_plan, assignedUserID, throwExceptionIfExists) (:902) — previa DecryptLoginId(loginkey) + ValidateClientSession(loginId) (:903-906).

Backend

  • UI/Code-behind: WorkOrdersNew.aspx.vb (ScheduleWeb).
  • Controller server: Descor.Maintenance.MaintenanceControllers.WorkOrderController (InfocadServer/MaintenanceControllers/WorkOrderController.vb), eredita Ctrl_EntityBase, attiva il DAO con DaoActivate(enControllers.Ctrl_WorkOrder) (:9) e inoltra via Me.DAO.
  • Business layer: Descor.Maintenance.MaintenanceBL.WorkOrder_BL (InfocadServer/MaintenanceBL/WorkOrder_BL.vb), con dipendenza da Plan_BL (caricamento piano) e InfocadLoginSettingsProvider (contatto autore).
  • DAO/DAL: MaintenanceDAL.OracleODP.WorkOrder_DAL (InfocadServer/MaintenanceDAL/OracleODP/WorkOrder_DAL.vb), ottenuto via MaintenanceDALFactory.GetWorkOrderDAL.
  • Pattern DAL: Dim dl As New DataLayer(My.Settings.ConnectionName, dbParams)dl.Parameters.Add(New OracleParameter(...))dl.ExecuteNonQueryStoredProcedure("MNT_ADDWORKORDER"); identity restituita via parametro OUT PIDODL (NUMBER). Sessione DB annotata con DBUSERSESSION/DBSOURCESESSION (audit trigger lato DB).

Query / stored procedure

Passo Stored procedure (Oracle) Chiamata da (DAL)
Generazione protocollo ODL INFOCAD_TEST38.MNT_GETNEWPROTOCOL (OUT P_PROTOCOL) WorkOrder_DAL.vb:99
Creazione ODL (INSERT MAINT_ODL + UPDATE MAINT_PLAN) INFOCAD_TEST38.MNT_ADDWORKORDER (OUT PIDODL) WorkOrder_DAL.vb:135
Popolamento attività ODL (nested) INFOCAD_TEST38.MNT_SETODLACTIVITY MNT_ADDWORKORDER src:41
Popolamento asset ODL (nested) INFOCAD_TEST38.MNT_SETODLASSET MNT_ADDWORKORDER src:42
Inizializzazione feedback ODL (nested) INFOCAD_TEST38.MNT_SETODLFEEDBACK MNT_ADDWORKORDER src:43
Rilettura ODL creato (READ-ONLY) INFOCAD_TEST38.MNT_GETWORKORDER WorkOrder_DAL.vb:31

Tabelle lette (read)

  • INFOCAD_TEST38: MAINT_PROTOCOLFORMAT (formula protocollo, in MNT_GETNEWPROTOCOL src:8), MAINT_JOBLISTS (nome/descrizione joblist, MNT_ADDWORKORDER src:19-24), GLOBAL_OBJECTS (nome/descrizione oggetto/impianto, MNT_ADDWORKORDER src:25-30).
  • Letture applicative a monte (BL): piano via Plan_BL.SelectById; contatto utente via InfocadLoginSettingsProvider (schema identità).

Tabelle modificate (write)

  • INFOCAD_TEST38: MAINT_ODL (RW — riga-radice dell'ODL: INSERT con SEQ_MAINT_ODL.NEXTVAL e RETURNING ID_ODL; VERIFIED su sorgente e su USER_TAB_COLUMNS), MAINT_PLAN (UPDATE ID_ODL, STATE = 2 sul piano di origine), MAINT_ODL_ACTIVITY (INSERT — attività dell'ODL, via MNT_SETODLACTIVITY), MAINT_ODL_ASSET (INSERT — asset dell'ODL, via MNT_SETODLASSET), MAINT_FEEDBACK_ODL (DELETE + INSERT — inizializzazione feedback, via MNT_SETODLFEEDBACK).
  • Effetto indiretto: avanzamento sequenza SEQ_MAINT_ODL.

Validazione

  • Lato UI: grant di sezione HasUserGrant("3630") (o SuperAdmin) in WorkOrdersNew_Init (WorkOrdersNew.aspx.vb:76); in assenza → ThrowSectionAccessException.
  • Lato WCF: DecryptLoginId(loginkey)Guid.Empty + ValidateClientSession(loginId) non nullo (ScheduleReaderWCF.svc.vb:903-906).
  • Lato BL: idempotenza sul piano — se P.ID_ODL > 0 l'ODL già esiste e non viene creato un duplicato (WorkOrder_BL.vb:50-51); il parametro throwExceptionIfExists propagato alla DAL.
  • Lato DAL: la creazione avviene solo se P.ID_ODL = 0 (WorkOrder_DAL.vb:91).
  • Lato DB: MNT_ADDWORKORDER assume presenza di joblist (PIDJL) e oggetto (PIDOBJ); le SELECT ... INTO su MAINT_JOBLISTS/GLOBAL_OBJECTS (src:19-30) sollevano NO_DATA_FOUND se gli id non esistono (rollback della transazione ODP.NET).

Side effects

  • Generazione protocollo univoco tramite formula configurata (MAINT_PROTOCOLFORMAT).
  • Aggiornamento di stato del Piano di origine (MAINT_PLAN.STATE = 2, collegamento ID_ODL).
  • Materializzazione di attività (MAINT_ODL_ACTIVITY) e asset (MAINT_ODL_ASSET) dalla joblist/oggetto.
  • Inizializzazione della struttura di feedback (MAINT_FEEDBACK_ODL, feedback = 0).
  • Stamping di audit via sessione DB (DBUSERSESSION/DBSOURCESESSION, WorkOrder_DAL.vb:85-88).
  • Nel path batch (Plan_BL): se l'impianto è in fermo temporaneo, l'ODL appena creato con data passata viene subito archiviato (ArchiveWorkOrder, Plan_BL.vb:1723-1728).

Percorsi alternativi / di errore

  • WCF programmatico: ScheduleReaderWCF.CreateWorkOrder (:902) → stesso WorkOrderController.CreateWorkOrder.
  • Batch di schedulazione: Plan_BL (generazione piani da OJ) chiama daoODL.CreateWorkOrder(username, P.ID_DTO, OJ.IdContactAssigned, False) (Plan_BL.vb:1718) e, per i replan, WOBL.CreateWorkOrder(username, replannedPlan.ID_DTO, idResp, False) (:1772) — stessa DAL/SP. Questo è il path che si collega alla logica ODL/OJ (tabella Maint_OJ_PROCESS, script DDL SQLScript/VERSION T0/Schedule/Create/Tabella Maint_OJ_PROCESS.sql).
  • ODL già esistente: WorkOrder_BL.CreateWorkOrder ritorna l'ODL esistente senza scrivere (WorkOrder_BL.vb:50-51).
  • Errore: eccezione loggata (Infrastructure.LogManager.ExceptionLogger.LogException) e ri-sollevata lungo tutta la catena BL→Controller; in UI mostrata in divError (WorkOrdersNew.aspx.vb:107).

Diagramma di sequenza

sequenceDiagram
    actor Op as Operatore Manutenzione
    participant UI as WorkOrdersNew.aspx (ScheduleWeb)
    participant CB as WorkOrdersNew.aspx.vb (btnApply_Click)
    participant WC as WorkOrderController.CreateWorkOrder
    participant BL as WorkOrder_BL.CreateWorkOrder
    participant PL as Plan_BL.SelectById
    participant DAL as WorkOrder_DAL.CreateWorkOrder
    participant DB as Oracle INFOCAD_TEST38

    Op->>UI: seleziona contatto + click Applica
    UI->>CB: btnApply_Click
    CB->>WC: CreateWorkOrder(user, ID_DTO=id_plan, contactId)
    WC->>BL: CreateWorkOrder(user, id_plan, assignedUserID)
    BL->>PL: SelectById(user, id_plan)
    PL-->>BL: Plan P
    alt P.ID_ODL > 0 (ODL esistente)
        BL-->>WC: WorkOrder esistente (nessuna scrittura)
    else P.ID_ODL = 0 (crea)
        BL->>DAL: CreateWorkOrder(user, P, authorContactId, assignedUserID)
        DAL->>DB: MNT_GETNEWPROTOCOL(P_IDOJ) -> OUT P_PROTOCOL
        DB->>DB: SELECT MAINT_PROTOCOLFORMAT; EXECUTE IMMEDIATE
        DAL->>DB: MNT_ADDWORKORDER(PIDPLAN, PPROTOCOL, ...) -> OUT PIDODL
        DB->>DB: INSERT MAINT_ODL (SEQ_MAINT_ODL.NEXTVAL) RETURNING ID_ODL
        DB->>DB: UPDATE MAINT_PLAN SET ID_ODL, STATE=2 WHERE ID_PLAN
        DB->>DB: MNT_SETODLACTIVITY -> INSERT MAINT_ODL_ACTIVITY
        DB->>DB: MNT_SETODLASSET -> INSERT MAINT_ODL_ASSET
        DB->>DB: MNT_SETODLFEEDBACK -> DELETE+INSERT MAINT_FEEDBACK_ODL
        DB-->>DAL: PIDODL (nuovo id)
        DAL-->>BL: idWO
        BL->>PL: SelectById(idWO)
        BL-->>WC: WorkOrder creato
    end
    WC-->>CB: WorkOrder
    CB-->>Op: SubmitWindow(ID_DTO) / oppure divError

Matrice di tracciabilità

Layer Artefatto Evidenza (file:riga)
UI WorkOrdersNew.aspx (scheda crea ODL) + grant 3630 WorkOrdersNew.aspx.vb:75-79
Code-behind btnApply_ClickCreateWorkOrder WorkOrdersNew.aspx.vb:101,104
WCF (programmatico) ScheduleReaderWCF.CreateWorkOrder ScheduleReaderWCF.svc.vb:902,906
Controller WorkOrderController.CreateWorkOrderMe.DAO WorkOrderController.vb:9,12,14
Business layer WorkOrder_BL.CreateWorkOrder (idempotenza + autore) WorkOrder_BL.vb:44,47,50,55,56
Batch (alt) Plan_BLdaoODL/WOBL.CreateWorkOrder Plan_BL.vb:1718,1772
DAL WorkOrder_DAL.CreateWorkOrder → SP protocollo + insert WorkOrder_DAL.vb:84,91,99,135,137
DB MNT_GETNEWPROTOCOL (protocollo da MAINT_PROTOCOLFORMAT) USER_SOURCE MNT_GETNEWPROTOCOL src:8,11-17
DB MNT_ADDWORKORDER (INSERT MAINT_ODL + UPDATE MAINT_PLAN) USER_SOURCE MNT_ADDWORKORDER src:32-39
DB nested INSERT MAINT_ODL_ACTIVITY/MAINT_ODL_ASSET, DELETE+INSERT MAINT_FEEDBACK_ODL src:41,42,43 + MNT_SETODL* USER_SOURCE
DB (schema) MAINT_ODL (ID_ODL, PROTOCOL, STATUS, ID_OBJ, ID_JL, ID_ASSIGNED, ID_AUTHOR, ...) USER_TAB_COLUMNS (48 colonne)

Reverse trace (dal DB/controller ai chiamanti)

  • WorkOrderController.CreateWorkOrder è raggiunto da: scheda interattiva (WorkOrdersNew.aspx.vb:104) e WCF ScheduleReaderWCF.CreateWorkOrder (:902).
  • WorkOrder_DAL.CreateWorkOrder (stessa firma con Plan) è invocata sia dal BL (WorkOrder_BL.vb:55) sia direttamente dal processo batch di schedulazione (Plan_BL.vb:1718,1772, generazione automatica ODL da piani/OJ).
  • MNT_ADDWORKORDER è l'unico punto di INSERT su MAINT_ODL raggiunto da questo flusso (verificato: la creazione ODL non passa per PRP_MANAGEENTITY né per altre procedure di upsert generiche; è una procedura dedicata del dominio Manutenzione).
  • Forward e reverse concordano (scheda WorkOrdersNewCreateWorkOrderMNT_ADDWORKORDER con INSERT MAINT_ODL / UPDATE MAINT_PLAN) → NO CONFLICTING.
  • La creazione ODL è idempotente per piano: un piano con ID_ODL > 0 non genera un nuovo ODL (WorkOrder_BL.vb:50; WorkOrder_DAL.vb:91).
  • La creazione ODL porta il Piano allo stato STATE = 2 ("eseguito"/con ODL) — MNT_ADDWORKORDER src:38.
  • Il protocollo è generato da formula configurabile (MAINT_PROTOCOLFORMAT), quindi dipende dalla configurazione tenant/impianto (MNT_GETNEWPROTOCOL).
  • La data di apertura ODL dipende dal setting EnableStartDateOnODLCreation (WorkOrder_DAL.vb:114-118): se attivo usa P.Plan_Date, altrimenti NULL.

Evidenza (file:line)

Punti chiave (codice): WorkOrdersNew.aspx.vb:75-79,81,101,104,105,107; ScheduleReaderWCF.svc.vb:902-906; WorkOrderController.vb:9,12,14; WorkOrder_BL.vb:44,47,50,51,53-56; Plan_BL.vb:1710,1718,1772; WorkOrder_DAL.vb:84,85-88,91,92-99,102,105,106-133,135,137.

Punti chiave (DB, INFOCAD_TEST38, letti in sola lettura via USER_SOURCE/USER_TABLES/USER_TAB_COLUMNS): MNT_ADDWORKORDER firma src:1-11; SELECT denormalizzazione src:19-30; INSERT MAINT_ODL + RETURNING src:32-35; UPDATE MAINT_PLAN src:37-39; nested calls src:41-43. MNT_GETNEWPROTOCOL src:8,11-17. MNT_SETODLACTIVITY → INSERT MAINT_ODL_ACTIVITY (src:6); MNT_SETODLASSET → INSERT MAINT_ODL_ASSET (src:6); MNT_SETODLFEEDBACK → DELETE (src:23) + INSERT MAINT_FEEDBACK_ODL (src:26). Catalogo: MNT_ADDWORKORDER, MNT_GETNEWPROTOCOL sono PROCEDURE standalone di INFOCAD_TEST38 (database-catalog.jsonINFOCAD_TEST38.user_procedures); tabelle target confermate esistenti su USER_TABLES (MAINT_ODL, MAINT_PLAN, MAINT_JOBLISTS, GLOBAL_OBJECTS, MAINT_PROTOCOLFORMAT).

Confidence

  • VERIFIED: catena UI → code-behind → controller → BL → DAL → nomi stored procedure (letti sui sorgenti) e sorgente delle stored procedure MNT_ADDWORKORDER/MNT_GETNEWPROTOCOL (INSERT MAINT_ODL, UPDATE MAINT_PLAN) letto da USER_SOURCE; esistenza tabelle/colonne da catalogo live.
  • SUPPORTED: scritture su MAINT_ODL_ACTIVITY, MAINT_ODL_ASSET, MAINT_FEEDBACK_ODL — confermate dal sorgente delle nested procedure (MNT_SETODL*) ma senza esecuzione runtime end-to-end.
  • INFERRED: comportamento eccezionale su NO_DATA_FOUND per joblist/oggetto assenti (dedotto dalla semantica SELECT ... INTO, non testato).

Open questions

  • Colonne effettivamente valorizzate a runtime in MAINT_ODL_ACTIVITY/MAINT_ODL_ASSET (dipendono dal contenuto della joblist/oggetto — non ispezionate riga per riga le nested MNT_SETODL*).
  • Relazione precisa tra Maint_OJ_PROCESS (tabella/processo OJ) e la generazione batch degli ODL in Plan_BL (documentato il punto di chiamata, non l'intero orchestratore di schedulazione).
  • Se MAINT_PROTOCOLFORMAT contenga sempre una sola riga (la SELECT ... INTO in MNT_GETNEWPROTOCOL assume cardinalità 1).
  • Path RequestCenter → ODL: la manutenzione può emergere anche da RequestCenter (SetRCProtocolInOdl, WorkOrderController.vb:555) ma il collegamento avviene su ODL già esistente, non come entry di creazione.
  • Comportamento in configurazioni PROD (osservato solo ambiente TEST38).