BR-ENE — Regole di business del dominio Energy / Energia
Regole di business estratte dal dominio Energy / Energia di Infocad (Descor), ancorate al flusso pilota
FLOW-ENE-001(inserimento manuale di una lettura contatore,EnergyCenterWeb→NRG_INSERTDATACOLLECTOR) e verificate sul sorgente C# + sul PL/SQL Oracle (USER_SOURCE/USER_TRIGGERS/USER_CONSTRAINTS, schemaINFOCAD_TEST38, lookup read-only bounded).Backend Oracle, ASP.NET Web Forms (C#, EnergyCenterWeb) + Controller/BL/DAL su Windows Service via .NET Remoting, nessun ORM (stored procedure ODP.NET).
Legenda
- Tipo:
validation/state-transition/permission/calculation/date-logic/config-flag/customer-specific. - Enforcement:
UI(code-behind Web Forms),BL(Business Logic / Controller / DAL C#),DB(procedura/trigger/constraint Oracle),mixed. - Confidence:
VERIFIED(letto direttamente su codice + DB),SUPPORTED(dedotto da evidenza forte),INFERRED(ipotesi ragionata).
⚠️ Nota trasversale di rischio (BR-ENE-022): sulla tabella radice
NRG_DATACOLLECTORnon esiste alcun CHECK constraint (solo la PK). Tutte le regole di validità della lettura (ordine di data, valore non decrescente, valore ammesso diCOLLECTSOURCE) sono applicate solo nell'applicazione (UI o procedura), mai dal vincolo di schema. Vedi BR-ENE-022.
Registro delle regole
| ID | Regola | Tipo | Enforcement | Conf |
|---|---|---|---|---|
| BR-ENE-001 | Inserimento lettura richiede grant 15020; modifica richiede 15010; SuperAdmin bypassa |
permission | UI | VERIFIED |
| BR-ENE-002 | La lettura creata dalla UI/WCF è sempre forzata a COLLECTSOURCE = 'M' (manuale) |
config-flag | mixed (UI+BL) | VERIFIED |
| BR-ENE-003 | Insert bloccato se data ≤ ultima lettura manuale oppure valore < ultimo valore manuale | validation | UI (solo UI) | VERIFIED |
| BR-ENE-004 | Il riferimento "ultima lettura" considera solo le letture con COLLECTSOURCE = 'M' |
date-logic | DB | VERIFIED |
| BR-ENE-005 | Consumo MEASUREAMOUNT = MEASUREREAD − ultima MEASUREREAD; se amount/read = 0 → 0 |
calculation | DB | VERIFIED |
| BR-ENE-006 | Spalmatura: se esistono letture precedenti e giorni intercorsi ≥ 1, il consumo è ripartito per giorno (righe intermedie source 'm', riga finale 'M') |
calculation | DB | VERIFIED |
| BR-ENE-007 | Il calcolo consumo/ultima lettura considera solo contatori ISACTIVE = 1 AND ISCANCELLED = 0 |
validation | DB | VERIFIED |
| BR-ENE-008 | L'immagine è scritta in NRG_READINGS_IMG solo se COLLECTSOURCE = 'M' e id > 0 |
state-transition | DB | VERIFIED |
| BR-ENE-009 | PK ID_DATACOLLECTOR assegnata dal trigger BEFORE INSERT da SEQ_NRG_DATACOLLECTOR; se id esplicito, la sequence viene riallineata |
state-transition | DB | VERIFIED |
| BR-ENE-010 | AREA/CUBATURE/PERSON denormalizzati sulla lettura da EDIFICI/COMPRENSORI_, con nomi colonna letti da NRG_DICTIONARY (ID_KEY='FIELDUNIT'); default 1 se nessun edificio |
calculation | DB | VERIFIED |
| BR-ENE-011 | Lettura multi-canale: MEASUREREAD = A1 + A2 + A3 |
calculation | mixed (UI+BL) | VERIFIED |
| BR-ENE-012 | Immagine di lettura ridimensionata a max 1024×768 @72dpi e salvata come JPEG | calculation | UI | VERIFIED |
| BR-ENE-013 | La modifica di una lettura cancella i record esistenti del contatore (anche gli spalmati 'm') e li reinserisce; non è incrementale |
state-transition | DB | VERIFIED |
| BR-ENE-014 | In modifica è editabile solo l'ultima lettura: il pulsante Salva è nascosto se la data è antecedente alla penultima | permission | UI | VERIFIED |
| BR-ENE-015 | La validazione data in update varia per control: ReadingDetail blocca solo se data < penultima; ReadingCounterImgsDetail è incondizionata (check deprecato 24/10/2014) |
validation | UI | VERIFIED |
| BR-ENE-016 | La guardia data in insert è incoerente tra i control: ReadingDetail usa > (stessa data ammessa), ReadingCounter* usa >= (stessa data bloccata) |
validation | UI (rischio) | VERIFIED |
| BR-ENE-017 | WCF mobile: se readTime = data ultima lettura → Update, altrimenti Insert |
date-logic | BL | VERIFIED |
| BR-ENE-018 | WCF richiede loginkey decifrabile + sessione client validata, altrimenti ritorna −1/null | permission | BL | VERIFIED |
| BR-ENE-019 | Il selettore contatori di ReadingDetail è forzato a IdMeterType = 2 (Misuratore) |
config-flag | UI | VERIFIED |
| BR-ENE-020 | Il parametro PACCURACY (colonna ACCURACY) è popolato con IdImportSource, non con l'accuratezza |
calculation | BL/DAL (anomalia) | SUPPORTED |
| BR-ENE-021 | MEASUREAVG, MEASUREAMOUNT, A1..A3 salvati con ROUND(NVL(x,0),4); consumo spalmato ROUND(...,8) |
calculation | DB | VERIFIED |
| BR-ENE-022 | Nessun CHECK constraint su NRG_DATACOLLECTOR: validità lettura enforced solo app-side |
validation | DB (assenza) | VERIFIED |
| BR-ENE-023 | Alla creazione la data lettura è preimpostata a oggi (DateTime.Today) |
date-logic | UI | VERIFIED |
Dettaglio delle regole
BR-ENE-001 — Grant di inserimento/modifica lettura
- Statement: Il pulsante Salva della finestra di dettaglio lettura è visibile solo se l'utente ha il grant
15020(creazione) o15010(modifica), oppure è SuperAdmin. In sola visualizzazione il pulsante è nascosto. - Tipo: permission · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
EnergyCenterWeb/UserControls/Details/ReadingDetail.ascx.cs:124—btnSave.Visible = HasUserGrant("15020") | WS.SessionProfile.SuperAdmin;(Crea)ReadingDetail.ascx.cs:115—HasUserGrant("15010")(Modifica);:109Salva nascosto in Visualizza- Stessi grant in
ReadingCounterDetail.ascx.cs:148,158eReadingCounterImgsDetail.ascx.cs:215,230
- Rischio: controllo di autorizzazione solo lato UI (visibilità pulsante). Non risulta un enforcement server-side sul metodo
InsertDataCollectdel Controller/BL/DAL: un client che invochi direttamente il Controller/WCF non passa per questo gate (vedi BR-ENE-018 per il gate WCF, che è però solo di sessione, non di grant).15020/15010sono id di grant hard-coded come stringhe.
BR-ENE-002 — Origine lettura forzata a 'M'
- Statement: Ogni lettura creata dai control interattivi e dalla WCF mobile è marcata
COLLECTSOURCE = 'M'(manuale). Questo attiva a valle il salvataggio immagine (BR-ENE-008) e definisce l'insieme di riferimento dell'"ultima lettura" (BR-ENE-004). - Tipo: config-flag · Enforcement: mixed (UI+BL) · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:293—this.CurrentReading.CollectSourceString = "M";ReadingCounterDetail.ascx.cs:354,ReadingCounterImgsDetail.ascx.cs:657- WCF:
EnergyReaderWCF.svc.cs:126,197— costruttoreDataCollector(... CollectSourceEnum.Manuale ...)
- Nota: il codice
'm'minuscolo è riservato dal DB alle righe intermedie di spalmatura (BR-ENE-006); gli import massivi usano altri codici (pathNRG_ADDMEASUREMENTDATA, fuori da questo flow).
BR-ENE-003 — Guardia data/valore in inserimento (SOLO UI)
- Statement: L'inserimento è bloccato con messaggio
invalidDateOrMeasureMsg(nessuna scrittura) se la data scelta è ≤ alla data dell'ultima lettura manuale, oppure se il valore letto è < all'ultimo valore letto manuale. - Tipo: validation · Enforcement: UI (solo UI) · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:256—if (Convert.ToDateTime(hdnMaxDate.Value) > this.CurrentReading.CollectDate || Convert.ToDouble(hdnMeasureRead.Value) > this.CurrentReading.MeasureRead)- valori di confronto popolati da
checkCollectDate()(:160-199) viagetLastMeasureRead(BR-ENE-004)
- Rischio elevato: questa è una regola UI-only. Il DB non ha alcun vincolo che impedisca una data antecedente o un valore decrescente (vedi BR-ENE-022). La procedura
NRG_INSERTDATACOLLECTORaccetta e calcola comunque il consumo (che potrebbe risultare negativo). Un accesso via WCF non applica questa guardia (BR-ENE-017 gestisce solo insert-vs-update sulla base della data, non l'ordinamento).
BR-ENE-004 — "Ultima lettura" = solo COLLECTSOURCE='M'
- Statement: La lettura di riferimento per data e valore precedenti considera esclusivamente i record con
COLLECTSOURCE = 'M', ordinati per data decrescente (ultima e penultima). - Tipo: date-logic · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza: procedura
NRG_GETLASTMEASUREREAD(USER_SOURCE,INFOCAD_TEST38):... FROM NRG_DATACOLLECTOR ND WHERE ND.ID_METER = PIDMETER AND ND.COLLECTSOURCE = 'M' ORDER BY COLLECTDATE DESC. Consumata daEnergyDataCollector_DAL.getLastMeasureRead(:472-514). - Nota: le righe intermedie di spalmatura (
'm') e le letture di import sono quindi escluse dal confronto UI, ma incluse nel calcoloMAX(MEASUREREAD)della procedura di insert (BR-ENE-005, che filtra solo su meter attivo/non cancellato, non su source). Discrepanza di perimetro tra UI e DB.
BR-ENE-005 — Calcolo del consumo
- Statement: Se
PMEASUREAMOUNTè nullo o 0 ePMEASUREREAD > 0, il consumoPAMOUNT = PMEASUREREAD − PLASTMEASUREREADdovePLASTMEASUREREAD = NVL(MAX(MEASUREREAD),0)sulle letture precedenti del contatore (attivo, non cancellato,COLLECTDATE < PCOLLECTDATE). Se amount/read = 0 → consumo 0; se amount già valorizzato → si usa quello. - Tipo: calculation · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_INSERTDATACOLLECTOR(USER_SOURCE): bloccoIF (PMEASUREAMOUNT IS NULL OR PMEASUREAMOUNT = 0) AND PMEASUREREAD > 0 THEN SELECT NVL(MAX(MEASUREREAD),0) INTO PLASTMEASUREREAD ... ; PAMOUNT := PMEASUREREAD - PLASTMEASUREREAD; - Nota: nessun clamp a 0 del consumo → possibile valore negativo se BR-ENE-003 non è stata applicata (es. via WCF).
BR-ENE-006 — Spalmatura del consumo sui giorni intercorsi
- Statement: Se esistono letture precedenti (
PEXIST > 0) e i giorni intercorsi dall'ultima lettura sono ≥ 1, il consumo è ripartito: per ogni giorno intercorso viene inserita una riga conCOLLECTSOURCE = 'm'e valore progressivoPLASTMEASUREREAD + PAMOUNT*I, seguita da una riga finale con la lettura reale eCOLLECTSOURCE = 'M'. Altrimenti (0 giorni o nessuna data precedente) viene inserita una singola riga. - Tipo: calculation · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_INSERTDATACOLLECTOR:PNUMGIORNI := NVL(TRUNC(PCOLLECTDATE - MAX(COLLECTDATE)),0) - 1PREADAMOUNT := ROUND(PMEASUREREAD/(PNUMGIORNI+1),8); PAMOUNT := ROUND(PAMOUNT/(PNUMGIORNI+1),8);FOR I IN 1 .. PNUMGIORNI + 1 LOOP NRG_ADDDATACOLLECTOR(..., 'm', ...); END LOOP;poiNRG_ADDDATACOLLECTOR(..., PAMOUNT*(PNUMGIORNI+1), ..., 'M', ...)
- Magic numbers: arrotondamento a 8 decimali; branch su
PNUMGIORNI < 1. Effetto collaterale: una singola lettura manuale genera N+2 righe inNRG_DATACOLLECTOR.
BR-ENE-007 — Solo contatori attivi e non cancellati
- Statement: Tutte le SELECT di
MAX(MEASUREREAD)eCOUNT(*)per il calcolo/spalmatura filtranoMT.ISACTIVE = 1 AND MT.ISCANCELLED = 0. - Tipo: validation · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_INSERTDATACOLLECTOR(joinNRG_METERS MT ... AND MT.ISACTIVE = 1 AND MT.ISCANCELLED = 0); idemNRG_UPDATEDATACOLLECTOR. - Magic flags:
ISACTIVE = 1,ISCANCELLED = 0(colonne nullable a livello di schema — vedi tabellaNRG_METERS).
BR-ENE-008 — Salvataggio immagine solo per letture manuali
- Statement: L'INSERT su
NRG_READINGS_IMGavviene solo sePCOLLECTSOURCE = 'M'e l'id generato è > 0. Le righe intermedie di spalmatura ('m') e gli import non generano immagini. - Tipo: state-transition · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_ADDDATACOLLECTOR(USER_SOURCE):IF PCOLLECTSOURCE = 'M' AND PIDENTITY > 0 THEN NRG_ADDREADINGIMAGES(PIDENTITY, PIMAGEREAD, PIMAGEREADA1, PIMAGEREADA2, PIMAGEREADA3); END IF;.NRG_ADDREADINGIMAGES:INSERT INTO NRG_READINGS_IMG (ID_DATACOLLECTOR, IMAGEREADA1, IMAGEREADA2, IMAGEREADA3, IMAGEREAD) VALUES (...). - Vincolo DB:
NRG_READINGS_IMGha FKFK_NRG_READINGS_IMG → PK_NRG_DATACOLLECTOReID_DATACOLLECTOR NOT NULL(USER_CONSTRAINTS). Le colonne immagine sono tutte nullable → è ammesso un record immagine "vuoto".
BR-ENE-009 — Assegnazione PK via sequence (trigger) e riallineamento
- Statement: Il trigger
NRG_DATACOLLECTORBEFORE INSERT FOR EACH ROW valorizzaID_DATACOLLECTORdaSEQ_NRG_DATACOLLECTOR.NEXTVALquando l'id è NULL; se invece l'id è fornito esplicitamente, avanza la sequence finché supera l'id inserito (riallineamento). - Tipo: state-transition · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
USER_TRIGGERSNRG_DATACOLLECTOR(BEFORE EACH ROW,INSERT, ENABLED):IF (:NEW."ID_DATACOLLECTOR" IS NULL) THEN SELECT SEQ_NRG_DATACOLLECTOR.NEXTVAL INTO :NEW ... ELSE ... WHILE (last_InsertID > last_Sequence) LOOP SELECT SEQ_NRG_DATACOLLECTOR.NEXTVAL ... END LOOP; END IF;
BR-ENE-010 — Denormalizzazione Mq/Mc/Persone da dizionario configurabile
- Statement: All'insert, i valori
AREA,CUBATURE,PERSONsono letti dall'edificio del contatore (EDIFICIjoinCOMPRENSORI_suBUILDINGCODE=NRG_METERS.BUILDINGCODE). I nomi delle colonne da leggere sono presi daNRG_DICTIONARYconID_KEY = 'FIELDUNIT'eID_ITEMin (AREA,CUBATURE,PERSON), tramite SQL dinamico (EXECUTE IMMEDIATE). Se nessun edificio corrisponde, i valori restano al default 1. - Tipo: calculation · Enforcement: DB · Confidence: VERIFIED · customer_specific: true
- Evidenza:
NRG_ADDDATACOLLECTOR:SELECT ND.ITEM_VALUE INTO PFIELDAREA FROM NRG_DICTIONARY ND WHERE ND.ID_KEY = 'FIELDUNIT' AND ID_ITEM = 'AREA'(idem CUBATURE/PERSON);tmpSql := 'SELECT ED.'||PFIELDAREA||', ED.'||PFIELDCUBATURE||', C.'||PFIELDPERSON||...';PVALUEAREA/PVALUECUBATURE/PVALUEPERSON := 1di default. - Customer-specific / hard-coded: la chiave
'FIELDUNIT'e gli itemAREA/CUBATURE/PERSONsono hard-coded nella procedura, ma quali colonne diEDIFICI/COMPRENSORI_vengono lette dipende dai valori configurati inNRG_DICTIONARY(mappatura per installazione). SQL dinamico costruito per concatenazione → dipende dall'integrità del dizionario (potenziale rischio se il valore contiene testo arbitrario).
BR-ENE-011 — Lettura multi-canale: somma A1+A2+A3
- Statement: Per la lettura multi-canale (
ReadingCounterDetail,ReadingCounterImgsDetail, WCFSetMeterMultiRead), il valore complessivoMeasureReadè la somma dei tre canaliA1 + A2 + A3. - Tipo: calculation · Enforcement: mixed (UI+BL) · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingCounterDetail.ascx.cs:346,ReadingCounterImgsDetail.ascx.cs:595—MeasureRead = MeasureReadA1 + MeasureReadA2 + MeasureReadA3;- WCF
EnergyReaderWCF.svc.cs:197—... last1 + last2 + last3 ...
BR-ENE-012 — Ridimensionamento immagine
- Statement: L'immagine caricata viene ridimensionata a un massimo di 1024×768 px e forzata a 72 dpi se superiore, quindi salvata in formato JPEG prima di essere passata come BLOB.
- Tipo: calculation · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingCounterImgsDetail.ascx.cs—ImgRedim(:410-460):int MaxH = 768; int MaxW = 1024; ... if (f.Width > MaxW || f.Height > MaxH || bmp.HorizontalResolution > 72) ...; salvataggioredimImage.Save(msRedim, ImageFormat.Jpeg)(:580,609,627,645). - Magic numbers: 1024, 768, 72.
BR-ENE-013 — Modifica lettura = delete + reinsert (non incrementale)
- Statement: L'update di una lettura non aggiorna in-place: la procedura cancella i record del contatore a partire dalla data pertinente (inclusi i record spalmati
'm') e li reinserisce ricalcolando consumo e spalmatura. La logica di individuazione della data di taglio è stata modificata a luglio 2018. - Tipo: state-transition · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_UPDATEDATACOLLECTOR(USER_SOURCE): commento--**CANCELLO TUTTI I DATI DELLA LETTURA CHE STO MODIFICANDO, ANCHE I RECORD SPALMATI;DELETE FROM NRG_DATACOLLECTOR ND WHERE ND.ID_METER = PIDMETER AND ND.COLLECTSOURCE = 'M'(ramoPLASTMANINSERTDATE IS NULL) o... COLLECTDATE > PLASTMANINSERTDATE/>= PCOLLECTDATE; commenti datati--M.A. 07/2018. - Date-sensitive logic: presenza di blocchi commentati datati (
07/2018) e comportamento dipendente dalla data della penultima lettura manuale.PLASTMANINSERTDATEfiltraCOLLECTSOURCE='M'eCOLLECTDATE <= PCOLLECTDATE AND COLLECTDATE < PDATE.
BR-ENE-014 — Solo l'ultima lettura è modificabile
- Statement: In modalità Modifica, se la lettura selezionata ha data antecedente alla penultima lettura manuale (
hdnMaxDate_0), il pulsante Salva viene nascosto: non è possibile modificare letture diverse dall'ultima. - Tipo: permission · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:156-157—if (this.CurrentReading.CollectDate < DateTime.ParseExact(hdnMaxDate_0.Value, "dd/MM/yyyy", ...)) btnSave.Visible = false; - Rischio: enforcement solo UI (nasconde il pulsante), non a livello di procedura.
BR-ENE-015 — Validazione update dipendente dal control
- Statement: La validazione dell'update non è uniforme:
ReadingDetail.UpdateDataCollectorblocca l'update solo sehdnMaxDate_0 > CollectDate(data antecedente alla penultima);ReadingCounterImgsDetail.UpdateDataCollectornon applica alcuna validazione (la modifica è incondizionata, con il check originale marcato "Deprecato 24/10/2014"). - Tipo: validation · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:223-227— guardia suhdnMaxDate_0ReadingCounterImgsDetail.ascx.cs:490-521— blocco/* Deprecato 24/10/2014 la modifica di una lettura è incondizionata ... */e update diretto senza controllo
- Date-sensitive / variante: comportamento divergente tra control con annotazione datata.
BR-ENE-016 — Incoerenza operatore guardia insert (> vs >=)
- Statement: La guardia sulla data in inserimento usa operatori diversi tra i control:
ReadingDetailusa>(una lettura con la stessa data dell'ultima è ammessa), mentreReadingCounterDetail/ReadingCounterImgsDetailusano>=(stessa data bloccata). - Tipo: validation · Enforcement: UI (rischio incoerenza) · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:256—hdnMaxDate.Value > this.CurrentReading.CollectDateReadingCounterDetail.ascx.cs:306eReadingCounterImgsDetail.ascx.cs:536—hdnMaxDate.Value >= this.CurrentReading.CollectDate
BR-ENE-017 — WCF: insert vs update in base alla data
- Statement: Nelle operazioni WCF
SetMeterMonoRead/SetMeterMultiRead, se la data di lettura (readTime) coincide con la data dell'ultima lettura esistente si chiamaUpdateDataCollect, altrimentiInsertDataCollect. Se non esistono letture precedenti si esegue comunque Insert. - Tipo: date-logic / state-transition · Enforcement: BL · Confidence: VERIFIED · customer_specific: false
- Evidenza:
EnergyReaderWCF.svc.cs:153-156—if (readTime.CompareTo(collectDate) == 0) return dcc.UpdateDataCollect(dataC); else return dcc.InsertDataCollect(dataC);; fallback:164return dcc.InsertDataCollect(dataC);. IdemSetMeterMultiRead(:223-233).
BR-ENE-018 — Autenticazione WCF (sessione, non grant)
- Statement: Ogni operazione WCF decifra
loginkeyda header SOAPr1; se il GUID è vuoto o la sessione client non è validata, ritorna −1 (setter) o null/lista vuota (getter), senza toccare il DB. - Tipo: permission · Enforcement: BL · Confidence: VERIFIED · customer_specific: false
- Evidenza:
EnergyReaderWCF.svc.cs:23-38(DecryptLoginId,ValidateClientSession), guardie:118-122,166,168(mono),:190-194,235,237(multi). - Nota: il gate WCF è di sessione, non di grant
15020/15010: la separazione insert/modifica di BR-ENE-001 non è replicata sul canale WCF.
BR-ENE-019 — Selettore contatori forzato a Misuratore
- Statement: Nel dettaglio lettura interattivo il filtro contatori è forzato a
IdMeterType = 2(Misuratore). - Tipo: config-flag · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:92—_NRGFS.IdMeterType = 2; //Misuratore - Magic number:
2.
BR-ENE-020 — ACCURACY popolato con IdImportSource (anomalia)
- Statement: Nel DAL, il parametro
PACCURACYpassato alle procedure è valorizzato condata.IdImportSource, non con un valore di accuratezza; la colonnaACCURACYdiNRG_DATACOLLECTORriceve quindi l'id sorgente di import. - Tipo: calculation (anomalia di mappatura) · Enforcement: BL/DAL · Confidence: SUPPORTED · customer_specific: false
- Evidenza:
EnergyDataCollector_DAL.cs:406(InsertDataCollect),:172(AddDataCollect),:259(UpdateDataCollect) —new OracleParameter("PACCURACY", OracleDbType.Int32, data.IdImportSource, ParameterDirection.Input). La procedura scrivePACCURACYin colonnaACCURACYsenza trasformazioni. - Nota: probabile refuso storico; segnalato come rischio dati, non come regola voluta. Da confermare con il team.
BR-ENE-021 — Arrotondamenti e NVL sui valori scritti
- Statement: In
NRG_ADDDATACOLLECTORi valori numerici sono normalizzati:MEASUREREAD = NVL(x,0),MEASUREAVG/MEASUREAMOUNT/A1..A3/PREV1..3 = ROUND(NVL(x,0),4),INSERTDATE = SYSDATE. In spalmatura il consumo è arrotondato a 8 decimali (BR-ENE-006). - Tipo: calculation · Enforcement: DB · Confidence: VERIFIED · customer_specific: false
- Evidenza:
NRG_ADDDATACOLLECTORVALUES (..., NVL(PMEASUREREAD,0), ROUND(NVL(PMEASUREAVG,0),4), ROUND(NVL(PMEASUREAMOUNT,0),4), ... SYSDATE, ...).
BR-ENE-022 — Assenza di CHECK constraint sulla lettura (rischio)
- Statement: La tabella
NRG_DATACOLLECTORha come unico vincolo la PK; nessun CHECK vincola i valori ammessi diCOLLECTSOURCE, la non-negatività dei consumi/letture o l'ordinamento delle date. Tutte queste regole vivono solo nel codice applicativo. - Tipo: validation · Enforcement: DB (assenza di enforcement) · Confidence: VERIFIED · customer_specific: false
- Evidenza:
USER_CONSTRAINTSperNRG_DATACOLLECTOR→ soloPK_NRG_DATACOLLECTOR(tipoP), nessun constraintC. Quasi tutte le colonne (incl.COLLECTSOURCE,COLLECTDATE,MEASUREREAD) sonoNULLABLE = Y. - Rischio: combinato con BR-ENE-003 (UI-only) e BR-ENE-018 (WCF senza guardia di ordinamento), consente in linea di principio letture con data/valore incoerenti o
COLLECTSOURCEarbitrario tramite chiamate dirette al BL. Presente anche colonnaMEASUREAMOUNT_Mnon popolata da questo flusso (possibile campo residuo).
BR-ENE-023 — Data lettura preimpostata a oggi
- Statement: All'apertura in creazione, il selettore data lettura è inizializzato a
DateTime.Today. - Tipo: date-logic · Enforcement: UI · Confidence: VERIFIED · customer_specific: false
- Evidenza:
ReadingDetail.ascx.cs:126—this.rdpCollectDate.SelectedDate = DateTime.Today;
Regole enforced solo in UI (rischio)
- BR-ENE-003 (guardia data/valore insert), BR-ENE-014 (solo ultima lettura modificabile), BR-ENE-015/BR-ENE-016 (validazioni update/insert divergenti), BR-ENE-019 (filtro Misuratore), BR-ENE-023 (default data), BR-ENE-001 (grant come visibilità pulsante). Nessuna di queste è replicata a livello di procedura/constraint.
Regole enforced solo in SQL (procedura/trigger/constraint)
- BR-ENE-004 (perimetro 'M'), BR-ENE-005/BR-ENE-006 (consumo e spalmatura), BR-ENE-007 (meter attivo), BR-ENE-008 (immagine solo 'M'), BR-ENE-009 (PK/sequence via trigger), BR-ENE-010 (denormalizzazione da dizionario), BR-ENE-013 (delete+reinsert in update), BR-ENE-021 (arrotondamenti). Vincolo di integrità: FK
NRG_READINGS_IMG → NRG_DATACOLLECTOR.
Magic number / id hard-coded
- Grant
15020(insert),15010(modifica) — BR-ENE-001. IdMeterType = 2(Misuratore) — BR-ENE-019.- Chiave dizionario
'FIELDUNIT'+ itemAREA/CUBATURE/PERSON— BR-ENE-010. - Codici
COLLECTSOURCE'M'/'m'— BR-ENE-002/006/008. - Flag
ISACTIVE=1,ISCANCELLED=0— BR-ENE-007. - Arrotondamenti a 4 / 8 decimali — BR-ENE-021/006.
- Immagine 1024×768 @72dpi — BR-ENE-012.
Logica sensibile alla data / annotazioni datate
NRG_UPDATEDATACOLLECTOR: rework--M.A. 07/2018(BR-ENE-013).ReadingCounterImgsDetail: check update "Deprecato 24/10/2014" (BR-ENE-015).
Varianti customer-specific / configurabili
- BR-ENE-010: mappatura colonne
EDIFICI/COMPRENSORI_viaNRG_DICTIONARY(FIELDUNIT) — configurabile per installazione (customer_specific).
Open questions
- Esiste un enforcement server-side dei grant
15020/15010oltre alla visibilità del pulsante Salva? (allo stato risulta solo UI) MEASUREAMOUNT_MinNRG_DATACOLLECTOR: da quale flusso è popolata (non daNRG_ADDDATACOLLECTOR)?- BR-ENE-020: la mappatura
PACCURACY = IdImportSourceè voluta o un refuso? - Comportamento in PROD (analisi condotta su
INFOCAD_TEST38); eventuali CHECK aggiuntivi presenti in altri ambienti? NRG_READINGS_IMG: politica su record immagine "vuoti" (tutte le colonne BLOB nullable) e su letture multi-immagine.