Table of Contents

BR-QC — Regole di business del dominio QualityCheck / Controllo qualità

Regole estratte dal dominio QualityCheck / Controllo qualità di Infocad, ancorate al flusso pilota FLOW-QC-001 (registrazione dell'esito di un controllo — esecuzione di un check: salvataggio delle risposte e chiusura con data/utente di esecuzione) e alla relativa evidenza. Sistema: Infocad (Descor), backend Oracle INFOCAD_TEST38, front-end ASP.NET Web Forms (VB.NET) QualityCheckCenter + servizio WCF QualityCheckReaderWCF (client mobile) + server (Controller/DAL C#), nessun ORM (stored procedure via DAL Execute*StoredProcedure).

L'esecuzione di un controllo ha due entry-point con semantica equivalente ma implementazione divergente:

  1. Path mobile/WCFQualityCheckReaderWCF.DoCheckQualityCheckController.DoCheckQualityCheck_DAL.DoCheck → SP QCK_DOCHECK (che chiama QCK_SAVERESPONSES + UPDATE di chiusura su QCHECK_CHECK).
  2. Path web/schedaCheckSurveyControl.ascx (bottone Eseguito) → SaveResponses(QCK_SAVERESPONSES) + UpdateCheck(QCK_UPDATECHECK).

Aspetto centrale del dominio: si tratta di WRITE/UPDATE in-place di un check preesistente (mai creazione di un check standalone in questo flusso); di guardie di stato (Suspenddate / ExecutionDate / CancelDate); del gate WCF ValidateLoginKey; del trigger QCHECK_CHECK_SCHEDULE che sincronizza il contatore controlli aperti dell'ODL (MAINT_ODL.COUNT_QCHECKS); e di un'importante divergenza mobile vs web (log, ricalcolo aggregati di gruppo, IGC, transazionalità).

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

Le stored procedure/trigger QCK_*/QCHECK_* citati sono stati confermati con lookup read-only su USER_SOURCE/USER_TRIGGERS dello schema INFOCAD_TEST38 (driver oracledb thin, sola lettura del testo — nessun accesso a dati di business, nessuna DML/DDL, nessuna credenziale stampata).


Registro regole

ID Regola Tipo Enforcement Conf.
BR-QC-001 Path WCF DoCheck: sessione valida (ValidateLoginKey), altrimenti AccessDenied permission BL VERIFIED
BR-QC-002 Guardia stato: check sospeso (Suspenddate valorizzata) → esecuzione bloccata validation BL VERIFIED
BR-QC-003 Guardia stato: check già eseguito (ExecutionDate valorizzata) → nessuna ri-esecuzione validation BL VERIFIED
BR-QC-004 Guardia stato: check annullato (CancelDate valorizzata) → NoDataFound validation BL VERIFIED
BR-QC-005 DoCheck opera in-place su un check preesistente (solo UPDATE), mai crea un check state-transition DB/BL VERIFIED
BR-QC-006 Esecuzione = salva risposte + stamping EXECUTIONDATE=SYSDATE, EXECUTIONUSER=utente state-transition DB VERIFIED
BR-QC-007 Le risposte sono isolate per check: UPDATE ... WHERE IDDETAILS=... AND CHECKID=PIDCHECK validation DB VERIFIED
BR-QC-008 Successo = POUT/nrow ≠ 0 (righe risposte aggiornate); 0 → errore generico validation BL/DB VERIFIED
BR-QC-009 Accoppiamento posizionale array PIDDETAILS(I)PRESPONSEVALUES(I); loop su FIRST..LAST calculation DB VERIFIED
BR-QC-010 Trigger: chiusura check SCHEDULE (EXECUTIONDATE NULL→valorizzata) → MAINT_ODL.COUNT_QCHECKS -1 state-transition DB VERIFIED
BR-QC-011 Trigger simmetrico: riapertura/annullo/insert/delete/riassegnazione riallineano COUNT_QCHECKS state-transition DB VERIFIED
BR-QC-012 Path web: salva/esegui con grant 22540 o SuperAdmin; reset/annulla con grant 22550 permission UI ⚠️ VERIFIED
BR-QC-013 Path web: check compilabile solo se Startdate valorizzata e Suspenddate non valorizzata validation UI ⚠️ VERIFIED
BR-QC-014 Path web: ogni domanda deve avere risposta (o motivazione se N/A) prima di Eseguito validation UI ⚠️ VERIFIED
BR-QC-015 Path web: stamping ExecutionDate=DateTime.Now, utente di sessione, ActionCheck='ActionExecuted' state-transition UI/BL VERIFIED
BR-QC-016 QCK_UPDATECHECK (solo web): logga l'azione in QCHECK_CHECK_LOG per ActionExecuted/ActionPlanned side-effect DB VERIFIED
BR-QC-017 QCK_UPDATECHECK (solo web): ricalcola aggregati di gruppo; gruppo completato → IDSTATE=3 calculation DB VERIFIED
BR-QC-018 IGC calcolato lato UI (web); il path mobile QCK_DOCHECK non aggiorna l'IGC calculation UI ⚠️ SUPPORTED
BR-QC-019 Transazionalità: QCK_DOCHECK senza COMMIT; QCK_UPDATECHECK/SaveResponses con COMMIT esplicito config-flag DB/BL ⚠️ VERIFIED
BR-QC-020 Annullamento web: salva risposte + CancelDate=DateTime.Now via UpdateCheck state-transition UI/DB VERIFIED
BR-QC-021 Avvio check (WCF StartCheck): bloccato se Startdate già valorizzata validation BL VERIFIED

⚠️ = regola a rischio (solo-UI, solo-DB, magic number/hard-coded id, date-logic app-side, divergenza tra path).


Dettaglio regole

BR-QC-001 — Path WCF: sessione valida

Tipo: permission · Enforcement: BL · Conf.: VERIFIED · customer_specific: no L'operazione WCF DoCheck(loginkey, idCheck, idsDetail, responses) è gateata da ValidateLoginKey(loginkey): se la sessione non è valida ritorna setAsAccessDenied() senza toccare il DB. È il gate del path programmatico/mobile (equivalente ai grant di sezione UI del path web). Non risulta un controllo grant azione (es. 22540) ripetuto lato WCF oltre alla validazione sessione (vedi Open questions del flusso). Evidenza: QualityCheckReaderWCF.svc.vb:257,278.

BR-QC-002 — Guardia di stato: check sospeso

Tipo: validation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Prima di eseguire, il WCF ricarica lo stato con ctrl.GetCheckByID(idCheck): se Suspenddate è valorizzata → setAsERROR con messaggio SuspendCheckLbl e nessuna scrittura. Un controllo sospeso non è eseguibile finché non viene riattivato. Evidenza: QualityCheckReaderWCF.svc.vb:259-261.

BR-QC-003 — Guardia di stato: check già eseguito (idempotenza)

Tipo: validation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Se ExecutionDate è già valorizzata → setAsERROR (CheckStringStatusClosed). Impedisce la ri-esecuzione di un controllo già chiuso: un check si esegue una sola volta. È la guardia che rende idempotente lo stamping di esecuzione. Evidenza: QualityCheckReaderWCF.svc.vb:262-263.

BR-QC-004 — Guardia di stato: check annullato

Tipo: validation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no Se CancelDate è valorizzata → setAsNoDataFound(): il controllo annullato è trattato come inesistente ai fini dell'esecuzione (nessuna scrittura). L'ordine delle guardie è SuspenddateExecutionDateCancelDate (ElseIf), quindi la sospensione prevale sulle altre. Evidenza: QualityCheckReaderWCF.svc.vb:264-265.

BR-QC-005 — Esecuzione in-place di un check preesistente

Tipo: state-transition · Enforcement: DB/BL · Conf.: VERIFIED · customer_specific: no QCK_DOCHECK esegue esclusivamente UPDATE (delle risposte in QCHECK_CHECK_DETAILS via QCK_SAVERESPONSES e dell'header QCHECK_CHECK): non crea un nuovo check né nuovi dettagli. Il flusso presuppone quindi un check e i suoi dettagli già materializzati (via StartCheck/creazione a monte). Se IDCHECK/IDDETAILS non esistono, gli UPDATE semplicemente non toccano righe (POUT=0 → BR-QC-008). Evidenza: QCK_DOCHECK USER_SOURCE:12,14-16; QCK_SAVERESPONSES USER_SOURCE:16-19.

BR-QC-006 — Stamping di esecuzione: data server + utente

Tipo: state-transition · Enforcement: DB · Conf.: VERIFIED · customer_specific: no La chiusura del controllo esegue UPDATE QCHECK_CHECK SET EXECUTIONDATE = SYSDATE, EXECUTIONUSER = PUSERNAME WHERE IDCHECK = PIDCHECK. Nel path mobile la data di esecuzione è la SYSDATE del DB (data server), mentre nel path web è DateTime.Now dell'app (BR-QC-015): divergenza di sorgente-tempo tra i due path (date-logic). Evidenza: QCK_DOCHECK USER_SOURCE:14-16.

BR-QC-007 — Isolamento delle risposte per check

Tipo: validation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no QCK_SAVERESPONSES aggiorna solo i dettagli il cui IDDETAILS è nell'array e il cui CHECKID = PIDCHECK: il doppio predicato garantisce che le risposte non possano essere scritte su dettagli appartenenti a un altro controllo, anche se un IDDETAILS errato venisse passato. Evidenza: QCK_SAVERESPONSES USER_SOURCE:16-19.

BR-QC-008 — Semantica di successo: righe aggiornate ≠ 0

Tipo: validation · Enforcement: BL/DB · Conf.: VERIFIED · customer_specific: no QCK_SAVERESPONSES accumula in POUT il numero di righe effettivamente aggiornate (SQL%ROWCOUNT). Il WCF interpreta nrow ≠ 0 come OK e nrow = 0 come errore generico (ErrorString). Conseguenza: il successo è misurato sulle risposte aggiornate, non sullo stamping di QCHECK_CHECK (che non incrementa POUT). ⚠️ magic-number: nrow<>0. Edge/date-logic: QCK_SAVERESPONSES itera PIDDETAILS.FIRST..LAST — con array di dettagli vuoto il FOR su collezione vuota solleverebbe errore PL/SQL (non gestito con guardia sull'esistenza di elementi). Evidenza: QCK_SAVERESPONSES USER_SOURCE:13,21,25; QualityCheckReaderWCF.svc.vb:267-272.

BR-QC-009 — Accoppiamento posizionale dettagli↔risposte

Tipo: calculation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Le risposte sono associate per indice: la i-esima voce di PRESPONSEVALUES è scritta sul dettaglio identificato dalla i-esima voce di PIDDETAILS. La DAL costruisce i due array PL/SQL associativi dalle due liste (idsDetail, responses) mantenendo l'ordine; l'allineamento è responsabilità del chiamante (nessun re-check di corrispondenza lato DB). ⚠️ rischio di disallineamento se le due liste non hanno stessa lunghezza/ordine. Evidenza: QualityCheck_DAL.cs:1410-1416; QCK_SAVERESPONSES USER_SOURCE:13-19.

BR-QC-010 — Trigger: decremento contatore ODL alla chiusura del check SCHEDULE

Tipo: state-transition · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Il trigger QCHECK_CHECK_SCHEDULE (INSERT OR UPDATE su QCHECK_CHECK) agisce solo se il check è legato a un ODL di manutenzione: ENTITYTABLE='SCHEDULE' e ENTITYID>0 (valutato su OLD o NEW). In UPDATING, quando oldExecDate IS NULL AND newExecDate IS NOT NULL (la chiusura prodotta da QCK_DOCHECK/QCK_UPDATECHECK) esegue UPDATE MAINT_ODL SET COUNT_QCHECKS = COUNT_QCHECKS - 1 WHERE ID_ODL = newEntityId. È il legame automatico tra esecuzione del controllo e contatore controlli aperti dell'ODL. Evidenza: USER_TRIGGERS.QCHECK_CHECK_SCHEDULE (ramo UPDATING, oldExecDate IS NULL AND newExecDate IS NOT NULL); legame MAINT_ODL in FLOW-QC-001.

BR-QC-011 — Trigger: riallineamento simmetrico del contatore ODL

Tipo: state-transition · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Lo stesso trigger mantiene coerente MAINT_ODL.COUNT_QCHECKS in tutti gli scenari: INSERT di un check con EXECUTIONDATE NULL → +1; UPDATE con EXECUTIONDATE da valorizzata a NULL (riapertura/annullo che azzera l'esecuzione) → +1; passaggio da ENTITYTABLE='SCHEDULE' ad altro → +1 sul vecchio ODL; cambio di ENTITYID tra due SCHEDULE → -1 sul vecchio e +1 sul nuovo; DELETE di un check non eseguito → -1. Il contatore riflette quindi i controlli aperti (non ancora eseguiti) associati all'ODL. Evidenza: USER_TRIGGERS.QCHECK_CHECK_SCHEDULE (rami INSERTING/UPDATING/DELETING).

BR-QC-012 — Path web: grant di azione per esecuzione e reset

Tipo: permission · Enforcement: UI ⚠️ · Conf.: VERIFIED · customer_specific: no Nella scheda CheckSurveyControl.ascx i bottoni Salva/Eseguito sono visibili solo con HasUserGrant("22540") Or SuperAdmin (e IsCompile); il bottone Reset/annulla richiede HasUserGrant("22550") Or SuperAdmin. ⚠️ solo-UI (visibilità del controllo) e magic-id hard-coded (22540, 22550): il controller/DAL non ri-verifica i grant, quindi un chiamante server-side non è soggetto a questo gate. Il path mobile usa invece ValidateLoginKey (BR-QC-001). Evidenza: CheckSurveyControl.ascx.vb:244-246,279-281.

BR-QC-013 — Path web: compilabilità = avviato e non sospeso

Tipo: validation · Enforcement: UI ⚠️ · Conf.: VERIFIED · customer_specific: no La scheda imposta IsCompile = True solo se Startdate è valorizzata e Suspenddate è nulla; altrimenti i controlli di risposta sono disabilitati. Riflette lato UI il ciclo di vita avviato→compilabile→sospeso. ⚠️ solo-UI: la regola non è ripetuta lato DB nel path web (il path mobile la copre invece con le guardie BR-QC-002/003/004). Evidenza: CheckSurveyControl.ascx.vb:348-352.

BR-QC-014 — Path web: tutte le domande devono avere risposta

Tipo: validation · Enforcement: UI ⚠️ · Conf.: VERIFIED · customer_specific: no btnExecuted_Click esegue ExecutedSurvey() solo se CheckAllWithAnswer() è vero: ogni domanda del survey deve avere una risposta (radio/numerico/check/testo) oppure, se marcata N/A, una motivazione (MotivationNA). Alla prima domanda non soddisfatta la funzione ritorna False e ripopola il survey con messaggio CheckAnswerSurvey. ⚠️ solo-UI: il completamento non è imposto dal DB (QCK_DOCHECK scrive qualunque sottoinsieme di risposte fornito). Evidenza: CheckSurveyControl.ascx.vb:999-1011,1073-1109.

BR-QC-015 — Path web: stamping di esecuzione lato applicazione

Tipo: state-transition · Enforcement: UI/BL · Conf.: VERIFIED · customer_specific: no ExecutedSurvey() salva le risposte (SaveUserResponsesQCK_SAVERESPONSES) e poi imposta sull'oggetto CurrentCheck: Igc = CDbl(txtIgc.Value), ExecutionDate = DateTime.Now, ExecutionUser = WS.SessionLogin.UserName, ActionCheck = "ActionExecuted", salvando via UpdateCheck (QCK_UPDATECHECK). A differenza del path mobile, data e IGC provengono dall'applicazione, non dal DB (date-logic app-side). Evidenza: CheckSurveyControl.ascx.vb:1201-1211,1283-1291.

BR-QC-016 — QCK_UPDATECHECK: log dell'azione (solo path web)

Tipo: side-effect · Enforcement: DB · Conf.: VERIFIED · customer_specific: no QCK_UPDATECHECK inserisce una riga in QCHECK_CHECK_LOG (IDCHECK, utente, SYSDATE, azione) quando PACTION='ActionExecuted' (utente = PEXECUTIONUSER) o PACTION='ActionPlanned' (utente = PPLANNEDUSER). ⚠️ divergenza mobile vs web: il path mobile QCK_DOCHECK non scrive alcun log di esecuzione — l'audit dell'esecuzione esiste solo per il path web. Evidenza: QCK_UPDATECHECK USER_SOURCE:46-66.

BR-QC-017 — QCK_UPDATECHECK: ricalcolo aggregati e chiusura gruppo (solo path web)

Tipo: calculation · Enforcement: DB · Conf.: VERIFIED · customer_specific: no Dopo l'update, QCK_UPDATECHECK ricalcola gli aggregati del gruppo del check (GROUPID): QCHECK_GROUP.LQRAVG = AVG(IGC) dei check eseguiti e non annullati (EXECUTIONDATE IS NOT NULL AND ISCANCELLED = 0); NCHACKSCEXECUTE = numero eseguiti; NCHACKSPLANNED = numero pianificati; e se NCHACKSCREATE = n_executecheck (tutti i check creati eseguiti) porta il gruppo a IDSTATE = 3 (gruppo chiuso/completato). ⚠️ divergenza mobile vs web: QCK_DOCHECK non ricalcola nulla a livello di gruppo → eseguire un check dall'app mobile non aggiorna LQRAVG/contatori/stato gruppo. Evidenza: QCK_UPDATECHECK USER_SOURCE:73-122 (magic-number stato IDSTATE=3 a riga 108).

BR-QC-018 — Calcolo IGC lato UI; assente nel path mobile

Tipo: calculation · Enforcement: UI ⚠️ · Conf.: SUPPORTED · customer_specific: no L'IGC (indice di gravità/conformità) è accumulato lato UI nella proprietà Rilevato (in ViewState, alimentata da NewCalculate sulle singole risposte) e salvato via txtIgcIgc in UpdateCheck. Nel path mobile QCK_DOCHECK non aggiorna la colonna IGC di QCHECK_CHECK: un controllo eseguito da mobile resta con IGC non ricalcolato (hidden-flag/divergenza). Da confermare dove/quando l'IGC venga eventualmente aggiornato per il path mobile (Open question del flusso). Evidenza: CheckSurveyControl.ascx.vb:62-72,1206; assenza di update IGC in QCK_DOCHECK USER_SOURCE:10-20.

BR-QC-019 — Transazionalità divergente tra i path

Tipo: config-flag · Enforcement: DB/BL ⚠️ · Conf.: VERIFIED · customer_specific: no QCK_DOCHECK non contiene COMMIT: il commit del path mobile è demandato al DataLayer/gestione connessione (la DAL DoCheck non apre neppure una transazione esplicita). Al contrario QCK_UPDATECHECK esegue COMMIT espliciti (due volte) e le DAL SaveResponses/UpdateCheck usano BeginTransaction/CommitTransaction. ⚠️ asimmetria di gestione transazionale tra i due path (rischio su rollback parziale mobile). Vedi Open questions del flusso. Evidenza: QCK_DOCHECK USER_SOURCE:1-20 (nessun COMMIT); QCK_UPDATECHECK USER_SOURCE:69,122; QualityCheck_DAL.cs:1402-1442 (DoCheck, no BeginTransaction) vs :3016,3038 (SaveResponses) e :1542,1602 (UpdateCheck).

BR-QC-020 — Annullamento controllo (path web)

Tipo: state-transition · Enforcement: UI/DB · Conf.: VERIFIED · customer_specific: no Il bottone Reset (btnReset_Click, gateato dal grant 22550 — BR-QC-012) invoca CancelSurvey(): salva le risposte correnti e imposta CancelDate = DateTime.Now e ExecutionUser = utente di sessione, salvando via UpdateCheck (QCK_UPDATECHECK). Coerente con la guardia BR-QC-004: un check con CancelDate non è più eseguibile dal path mobile. Evidenza: CheckSurveyControl.ascx.vb:1015-1017,1255-1265.

BR-QC-021 — Avvio check: non ri-avviabile

Tipo: validation · Enforcement: BL · Conf.: VERIFIED · customer_specific: no L'operazione WCF correlata StartCheck(loginkey, idCheck, startDate) blocca l'avvio se Startdate è già valorizzata (setAsERROR con CheckStringStatuStart), altrimenti registra la data di inizio. È la transizione di stato che precede la compilabilità (BR-QC-013): un check si avvia una sola volta. Evidenza: QualityCheckReaderWCF.svc.vb:289-298.


Note trasversali e flag

  • Divergenza mobile vs web (BR-QC-006/015, BR-QC-016, BR-QC-017, BR-QC-018, BR-QC-019): i due entry-point producono lo stesso stato "eseguito" ma con effetti collaterali diversi. Il path web (QCK_UPDATECHECK) è "ricco" (log, ricalcolo aggregati di gruppo, stato gruppo, IGC, commit espliciti); il path mobile (QCK_DOCHECK) è "minimale" (solo risposte + stamping data/utente).
  • Magic id / magic number: grant azione 22540 (esegui/compila) e 22550 (reset) hard-coded (BR-QC-012); stato gruppo IDSTATE = 3 (BR-QC-017); semantica nrow<>0 (BR-QC-008).
  • Solo-UI: BR-QC-012 (grant), BR-QC-013 (compilabilità), BR-QC-014 (completezza risposte) non sono replicate lato DB; un chiamante server-side/mobile non ne è soggetto (mitigato in parte dalle guardie di stato BR-QC-002/003/004 e da ValidateLoginKey).
  • Solo-DB: BR-QC-010/011 (contatore ODL via trigger), BR-QC-016/017 (log e aggregati di gruppo) vivono interamente in stored procedure/trigger e sono invisibili al codice applicativo.
  • date-logic: sorgente-tempo divergente (SYSDATE DB mobile vs DateTime.Now app web), BR-QC-006/015.
  • customer_specific: nessuna regola risulta specifica per un singolo cliente; comportamento di prodotto standard sullo schema INFOCAD_TEST38.