BR-BLK — Regole di business del dominio BulkLoader / Caricamento massivo
Regole di business estratte dal flusso pilota FLOW-BLK-001 (import massivo di anagrafiche
PERSONEda file Excel) e dai sorgenti del dominio BulkLoader. Il dominio gestisce il caricamento massivo (import batch) di entità — Persone, Aziende, Contatti, Contratti, Conduzioni, Fornitori, Centri di costo, Asset, Spaziali, Categorie, Energy, Documenti — a partire da un foglio Excel caricato dall'operatore. Tutti i loader condividono lo stesso motore di processo (classe serverBulkLoader) che traccia il ciclo di vita suGLOBAL_UPLOAD_PROCESS/GLOBAL_UPLOAD_ALERTtramite le procedureRPS_*, e dispatcha a un loader specializzato (BulkLoaderBase-derivato) per tipo-entità. La persistenza delle entità anagrafiche passa dalla stessa procedura generica di upsertPRP_MANAGEENTITYusata dal salvataggio interattivo (vedi BR-PROP).Sistema: Infocad (Descor) — backend Oracle
INFOCAD_TEST38, ASP.NET Web Forms (VB.NET) come UI (UploadProcessControl.ascx), servizio Windows InfocadServer raggiunto via .NET Remoting (BulkLoader.rem, contrattoIBulkLoad); nessun ORM (accesso via stored procedure ODP.NET).Le regole sono classificate per tipo, enforcement point (UI / BL / DB / mixed) e confidence (VERIFIED / SUPPORTED / INFERRED). Gli identificatori tecnici NON sono tradotti.
Note di metodo e provenienza dell'evidenza
- Evidenza di codice: percorsi relativi alla radice del repository
Documentation/(es.InfocadServer/BulkLoaderManager/PeopleBulkLoader.vb:333). - Evidenza DB: le procedure di processo
RPS_STARTUPLOADPROCESS/RPS_WRITEUPLOADALERT/RPS_COMPLETEUPLOADPROCESSsono state lette in sola lettura daUSER_SOURCEdurante la tracciatura di FLOW-BLK-001 (INSERT/UPDATE suGLOBAL_UPLOAD_PROCESS/GLOBAL_UPLOAD_ALERTconfermati); esistenza tabelle/colonne da catalogoUSER_OBJECTS/USER_TAB_COLUMNS. Nessuna lettura di dati applicativi, nessuna DML/DDL. - Il comportamento interno di
PRP_MANAGEENTITY(upsert dinamicoPERSONE_, binding tenant) è documentato VERIFIED in BR-PROP/FLOW-PROP-001 (stessa procedura): qui è ereditato come SUPPORTED via riuso + verifica colonnaID_N. - Il path pilota è l'entità Persone (
IMP_PERSONE/UPD_PERSONE). Le regole del motore di processo (BR-BLK-001..007, 023) valgono per tutti i loader del dominio; le regole di dominio Persone (BR-BLK-008..022, 024..028) sono verificate sulPeopleBulkLoadere possono variare per gli altri loader specializzati.
Registro delle regole (register)
| id | regola | tipo | enforcement | conf |
|---|---|---|---|---|
| BR-BLK-001 | Ogni caricamento massivo apre un record processo su GLOBAL_UPLOAD_PROCESS con STATUS='RUNNING' e restituisce ID_PROCESS (RPS_STARTUPLOADPROCESS) |
state-transition | mixed | VERIFIED |
| BR-BLK-002 | Il file caricato è persistito integralmente: come BLOB DOCUMENT_FILE nel processo e come copia temporanea su disco (bulkloadtmp, naming dedotto anti-collisione) |
side-effect | mixed | VERIFIED |
| BR-BLK-003 | Chiusura processo con stato calcolato Done/DoneWithWarnings/NotDone, END_DATE=SYSDATE e contatori TOTALOBJS/VALIDOBJS/CREATEDOBJS (RPS_COMPLETEUPLOADPROCESS) |
state-transition | mixed | VERIFIED |
| BR-BLK-004 | Ogni riga elaborata genera un alert su GLOBAL_UPLOAD_ALERT con esito ActionResults 0-4 (RPS_WRITEUPLOADALERT) |
state-transition | mixed | VERIFIED |
| BR-BLK-005 | Il messaggio d'alert è troncato a 3999 caratteri prima dell'INSERT | validation | BL | VERIFIED |
| BR-BLK-006 | Retry: RetryFileUploadProcess rilegge il processo (RPS_RETRYUPLOADPROCESS) e rilancia Import solo se il file esiste ancora su disco |
state-transition | mixed | VERIFIED |
| BR-BLK-007 | Motore unico con dispatch per tipo-entità verso un loader specializzato; tipo non riconosciuto ⇒ alert ...UNKNOWN/ENTITY UNKNOW (status NoAction) e processo comunque chiuso |
config-flag | BL | VERIFIED |
| BR-BLK-008 | Insert vs Update Persone pilotato dal ramo UI (IMP_PERSONE⇒insert / UPD_PERSONE⇒update) e propagato a SavePeople (0⇒INSERT, ID_N>0⇒UPDATE) |
state-transition | mixed | VERIFIED |
| BR-BLK-009 | Import Persone richiede le chiavi di deduplica (strPeopleKey non vuoto; in update accettata anche colonna ID_N): assenti ⇒ file rifiutato |
validation | mixed | VERIFIED |
| BR-BLK-010 | Il file deve contenere colonna VANO/CODICE_VANO e le colonne di servizio LOG_RES e LOG_DET: assenti ⇒ file rifiutato |
validation | BL | VERIFIED |
| BR-BLK-011 | Le colonne DB di PERSONE_ devono essere individuabili (getColumnsByTable); la congruenza colonne-file↔colonne-DB è però disabilitata (codice commentato) |
validation | mixed | VERIFIED |
| BR-BLK-012 | In insert ogni riga deve indicare il vano (VANO/CODICE_VANO): assente ⇒ riga scartata |
validation | BL | VERIFIED |
| BR-BLK-013 | La collocazione spaziale deve risolvere a esattamente 1 vano appartenente al tenant (0 o >1 ⇒ scarto con ActionError) |
validation | mixed | VERIFIED |
| BR-BLK-014 | Deduplica in insert: se la persona esiste già per la commessa o per altra commessa (con la chiave) l'insert è bloccato con alert | validation | BL | VERIFIED |
| BR-BLK-015 | La chiave persona è risolta da strPeopleKey: se vuoto usa ID_N di riga, altrimenti compone un filtro tipizzato e recupera ID_N solo se individua esattamente 1 persona |
calculation | BL | VERIFIED |
| BR-BLK-016 | Vengono scritti solo i campi del file mappabili sulla EntityStructure di PERSONE_ (filtrata per ruoli); esclusi campi spaziali, LOG_RES/LOG_DET, BLOB e campi che iniziano con ID_ |
validation | BL | VERIFIED |
| BR-BLK-017 | L'ID_VANO risolto è iniettato esplicitamente nei campi entità in insert |
calculation | BL | VERIFIED |
| BR-BLK-018 | Le date dei campi del file sono normalizzate a formato dd/MM/yyyy con cultura it-IT prima del salvataggio |
date-logic | BL | VERIFIED |
| BR-BLK-019 | Il DAO aggiunge ID_CHANGED_BY = <username> ai campi da salvare se assente |
validation | BL | VERIFIED |
| BR-BLK-020 | La persistenza della persona usa la procedura generica PRP_MANAGEENTITY (PERSONE/ID_N), la stessa del salvataggio interattivo |
state-transition | mixed | VERIFIED/SUPPORTED |
| BR-BLK-021 | Interpretazione del ritorno di SavePeople: numerico ⇒ successo; non numerico ⇒ errore DB con messaggio in alert ActionError |
state-transition | BL | VERIFIED |
| BR-BLK-022 | Contatori di completamento (TotalObjects/ValidObjects/CreatedObjects, warns) — CreatedObjects sovrastima perché InsertObject ritorna True anche su riga scartata (dedup/errore DB) |
state-transition | BL | VERIFIED (difetto INFERRED) |
| BR-BLK-023 | Al termine il foglio Excel è aggiornato con LOG_RES/LOG_DET per riga (UpdateDocumentFile), il file ripersistito e la copia su disco cancellata; LOG_DET troncato a 250 char, errori ORA- al solo codice (9 char) |
side-effect | mixed | VERIFIED |
| BR-BLK-024 | Multi-tenant: collocazione e deduplica sono sempre filtrate per il tenant corrente (GetCurrentTenancyID(Username)) |
permission | BL | VERIFIED |
| BR-BLK-025 | L'abilitazione delle opzioni di upload dipende dai grant utente: IMP_PERSONE richiede ADD_DELETE, UPD_PERSONE richiede EDIT — entrambi valutati sull'entità Asset — ma solo lato UI (nessun ricontrollo server-side) |
permission | UI | VERIFIED |
| BR-BLK-026 | File obbligatorio: senza file caricato (tranne rami DWG/OMI) il caricamento è interrotto con messaggio | validation | UI | VERIFIED |
| BR-BLK-027 | Update Persone: flag nascosti evaluateLocation/evaluateReleaseAsset da checkbox; con cambio vano gli asset collegati sono trasferiti (ed eventualmente rilasciati) via UpdatePeopleChangeROOM |
state-transition | mixed | VERIFIED |
| BR-BLK-028 | Update dedup: existEntityByKeyAndTenant deve ritornare code 1 (persona univoca per la commessa); code 0 (assente per la commessa) o -1 (non identificabile) ⇒ update saltato |
validation | BL | VERIFIED |
| BR-BLK-029 | Il file Excel è letto via OleDb (provider ACE/JET, connection string xls da config): selezione automatica del primo foglio con nome contenente $ e diverso da Foglio1$; provider scelto per estensione (Excel 8.0/12.0) |
config-flag | BL | SUPPORTED |
Dettaglio delle regole
BR-BLK-001 — Apertura del processo di caricamento (STATUS='RUNNING')
- Regola: ogni
StartFileUploadProcesschiamaStartProcess, che esegueRPS_STARTUPLOADPROCESS:INSERT INTO GLOBAL_UPLOAD_PROCESS (FILENAME, START_DATE, END_DATE, USERNAME, DOCUMENT_FILE, STATUS, ENTITY_TYPE) VALUES (..., SYSDATE, NULL, ..., 'RUNNING', ...) RETURNING ID_PROCESS INTO PNEWINDEX. Ilprocessidrestituito identifica il caricamento. - Tipo: state-transition · Enforcement: mixed (BL orchestra, DB inserisce) · Confidence: VERIFIED
- Evidenza (BL):
StartProcess(...)con OUTPNEWINDEXedl.ExecuteNonQueryStoredProcedure("RPS_STARTUPLOADPROCESS")—InfocadServer/BulkLoaderManager/BulkLoader.vb:791-812; invocazione sul ramo People:199-207. - Evidenza (DB):
RPS_STARTUPLOADPROCESS(USER_SOURCEsrc:9-12, letto in FLOW-BLK-001). - Nota:
FILENAMEsalvato è solo il nome base del file (filename.Substring(filename.LastIndexOf("\") + 1)), non il path — rilevante per BR-BLK-006.
BR-BLK-002 — Doppia persistenza del file sorgente (BLOB + disco)
- Regola: il file caricato è salvato (a) come BLOB
DOCUMENT_FILEnel record di processo e (b) come copia temporanea su disco sotto<AppDir>\bulkloadtmp, con naming anti-collisione (_1,_2, … se il nome esiste già). - Tipo: side-effect · Enforcement: mixed · Confidence: VERIFIED
- Evidenza:
SaveUploadedFile(exceldoc, filename)creabulkloadtmpe itera il suffisso_cnt—BulkLoader.vb:1013-1030; BLOB viaPDOCUMENTFILEinStartProcess:794-795. - Flag: il BLOB abilita
GetFileUploadSource/retry senza ri-upload; la copia su disco è invece cancellata a fine import (vedi BR-BLK-023) — divergenza rilevante per il retry (BR-BLK-006).
BR-BLK-003 — Chiusura processo con stato e contatori
- Regola: al termine di
StartImport,CompleteFileUploadProcessesegueRPS_COMPLETEUPLOADPROCESS:UPDATE GLOBAL_UPLOAD_PROCESS SET STATUS=PCOMPLETION, END_DATE=SYSDATE, TOTALOBJS=..., VALIDOBJS=..., CREATEDOBJS=... WHERE ID_PROCESS=.... Lo stato è uno traDone(nessun warning),DoneWithWarnings(almeno un warning),NotDone(file non valido). - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED
- Evidenza (BL): calcolo stato
If warns > 0 ... DoneWithWarnings Else DoneeReturn CompletionResults.NotDonesu file invalido —PeopleBulkLoader.vb:122-135; chiamataCompleteFileUploadProcess(...)—BulkLoader.vb:687-689,989-1011; enumCompletionResults {Running, Done, DoneWithWarnings, NotDone}—BulkLoaderBase.vb:1350-1355. - Evidenza (DB):
RPS_COMPLETEUPLOADPROCESS(USER_SOURCEsrc:9-11). - Flag: il parametro
PCOMPLETIONè bindato comeVarchar2a partire dal valore enum (BulkLoader.vb:993): la rappresentazione effettivamente scritta inSTATUS(nome"Done"vs ordinale) non è determinabile dal solo codice — vedi Open questions.
BR-BLK-004 — Alert per riga su GLOBAL_UPLOAD_ALERT
- Regola: per ogni riga (e per gli errori a livello file) viene scritto un alert
INSERT INTO GLOBAL_UPLOAD_ALERT (PROCESSID, ROWNUMBER, OBJECTCODE, MESSAGE, STATUS) ... RETURNING alertid. LoSTATUSè il nome dell'enumActionResults:NoAction=0,ActionWaitingForValidation=1,ActionSuccess=2,ActionError=3,ActionSuccessWithWarning=4. - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED
- Evidenza (BL):
WriteAlert(drObj, code, logs, status)→bulkCtrl.WriteUploadAlert(ProcessID, rowindex, code, logs, status.ToString)—BulkLoaderBase.vb:558-566;WriteUploadAlert→RPS_WRITEUPLOADALERT—BulkLoader.vb:954-987; enum —BulkLoaderBase.vb:1357-1363. - Evidenza (DB):
RPS_WRITEUPLOADALERT(USER_SOURCEsrc:10-13). - Flag: magic numbers (valori enum 0-4) e stringhe di stato scritte in chiaro;
ROWNUMBER= indice riga+1 (0 per alert a livello file).
BR-BLK-005 — Troncamento messaggio alert a 3999 caratteri
- Regola: se il messaggio dell'alert è ≥ 4000 caratteri viene troncato a 3999 prima dell'INSERT.
- Tipo: validation · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
If message.Length >= 4000 Then message = message.Substring(0, 3999)—BulkLoader.vb:956-958. - Flag: magic number
4000/3999(verosimilmente il limiteVARCHAR2della colonnaMESSAGE).
BR-BLK-006 — Retry condizionato alla presenza del file su disco
- Regola:
RetryFileUploadProcess(processID, username)rilegge il record processo (RPS_RETRYUPLOADPROCESS), ne estraeFILENAMEeENTITY_TYPE, ricostruisce il tipo entità e rilanciaImportsolo seSystem.IO.File.Exists(filename); altrimenti ritorna0senza fare nulla. - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED
- Evidenza:
RetryFileUploadProcess(...)e guardiaIf filename IsNot DBNull.Value AndAlso System.IO.File.Exists(filename)—BulkLoader.vb:267-285;RetryProcess→RPS_RETRYUPLOADPROCESS:814-837. - Flag: gotcha nascosto — il retry dipende dalla copia su disco, non dal BLOB persistito; ma
FILENAMEè memorizzato come nome base (BR-BLK-001) e la copia su disco viene cancellata a fine import (BR-BLK-023). Di conseguenza il retry di un processo già completato rischia di non trovare il file e ritornare0. Impatto esatto da verificare con Descor (INFERRED).
BR-BLK-007 — Motore unico e dispatch per tipo-entità
- Regola: esiste un unico motore server (
BulkLoader) che, in base al tipo dinamico dell'entità (SPATIAL/MAINT/CATEGORY/GLOBAL/DOCUMENT/TYPOLOGY/NRG/ENERGY/BOOK), istanzia il loader specializzato corrispondente (PeopleBulkLoader,CompaniesBulkLoader,AssetBulkLoader, …). Un tipo non gestito produce un alert"<AREA> UNKNOWN"/"ENTITY UNKNOW"con statusNoActione il processo viene comunque chiuso. - Tipo: config-flag (routing) · Enforcement: BL · Confidence: VERIFIED
- Evidenza: overload
Import(...)conSelect Case entityType.GetType()/getEnum()e ramiCase Else WriteUploadAlert(..., "... UNKNOWN", ..., "NoAction")—BulkLoader.vb:431-582(generale),:646-671(Costcentre/Companies),:673-692(People). Ramo People:Case BulkEntity.GLOBAL.ENTITY.PERSONE ⇒ New PeopleBulkLoader(...):677-678. - Flag: refuso hard-coded
"ENTITY UNKNOW"(manca la N finale):659,680.
BR-BLK-008 — Insert vs Update Persone pilotato dall'UI
- Regola: il ramo UI determina la modalità:
IMP_PERSONEchiama il servizio conisInsert:=True, evaluateLocation:=0, evaluateAction:=0;UPD_PERSONEconisInsert:=Falsee i flag da checkbox. Il flagisInsertselezionaInsertPeoplevsupdatePeople, eSavePeople(username, peopleID, ...)decide INSERT (peopleID=0) o UPDATE (peopleID=ID_N>0) a livelloPRP_MANAGEENTITY. - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED
- Evidenza: UI
Case "IMP_PERSONE"...StartFileUploadProcess(..., strPeopleKey, True, 0, 0)—UploadProcessControl.ascx.vb:453-460;Case "UPD_PERSONE"..., strPeopleKey, False, ...:461-468; dispatchInsertObject/InsertPeople/updatePeople—PeopleBulkLoader.vb:36-67;SavePeople(Username, 0, entityFields)(insert):406vsSavePeople(Username, CInt(peopleValueArray(1)), ...)(update):544. - Nota: coerente con BR-PROP-001 (semantica id
0/>0risolta inPRP_MANAGEENTITY).
BR-BLK-009 — Chiavi di deduplica obbligatorie
- Regola: in insert il file è rifiutato se
strPeopleKey(chiavi selezionate in UI) è vuoto; in update è accettata in alternativa la presenza della colonnaID_Nnel file. - Tipo: validation · Enforcement: mixed (UI compone, BL valida) · Confidence: VERIFIED
- Evidenza (UI): composizione
strPeopleKeydallecmbPeopleKey.CheckedItems(;-separated) —UploadProcessControl.ascx.vb:454-459,462-467. - Evidenza (BL): insert
If String.IsNullOrEmpty(_tableKey) Then valid=False ... "Specificare le chiavi..."—PeopleBulkLoader.vb:196-199; updateIf String.IsNullOrEmpty(_tableKey) AndAlso Not dt.Columns.Contains("ID_N"):245-248.
BR-BLK-010 — Colonne di file obbligatorie
- Regola: il file deve contenere la colonna
VANOoCODICE_VANO(per il posizionamento) e le due colonne di servizioLOG_RESeLOG_DET(per la scrittura dell'esito); l'assenza di una qualsiasi rende il file non valido (ValidateFile⇒ alertNoAction,StartImportritornaNotDone). - Tipo: validation · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
ValidateInsertingFile—PeopleBulkLoader.vb:191-194(VANO/CODICE_VANO),:224-232(LOG_DET/LOG_RES);ValidateFile⇒WriteAlert(Nothing, "FILE", logs, NoAction):146-149.
BR-BLK-011 — Colonne DB di PERSONE_ individuabili; congruenza file↔DB disabilitata
- Regola: se
getColumnsByTable("PERSONE_")non restituisce colonne il file è rifiutato ("Colonne della tabella PERSONE non individuate"). Il controllo che verificava che ogni colonna del file esistesse anche nel DB è invece commentato/disattivato. - Tipo: validation · Enforcement: mixed (BL + lettura catalogo DB) · Confidence: VERIFIED
- Evidenza:
Dim gs As List(Of String) = daoGS.getColumnsByTable(ENTITY)eElse valid=False ... non individuate—PeopleBulkLoader.vb:187-189,201,220-223; ciclo di congruenza colonne commentato:214-219(insert) e:262-267(update). - Flag: validazione disabilitata (dead code) — colonne del file non presenti nel DB non generano più errore; vengono semplicemente ignorate dalla mappatura (BR-BLK-016).
BR-BLK-012 — Vano obbligatorio per riga (solo insert)
- Regola: in insert ogni riga deve indicare
VANOoCODICE_VANO; se entrambi mancano/nulli la riga è scartata con alertNoAction. In update il controllo non si applica. - Tipo: validation · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
If valid And _isInsert Then If (Not ...CODICE_VANO ...) AndAlso (Not ...VANO ...) Then valid=False ... "specificare il vano..."—PeopleBulkLoader.vb:159-168.
BR-BLK-013 — Collocazione univoca e nel tenant
- Regola:
ValidateSpaceLocationcostruisce i parametri spaziali presenti nella riga (REGIONE,CITTA,COMPRENSORIO,EDIFICIO,PIANO,VANOe le variantiCODICE_*) e interrogaGetAssetLocationByParamAndTnt(param, _currenttenantID). La collocazione è valida solo se restituisce esattamente 1 riga (ID_VANO);>1⇒ "non univoca",0/nessuna tabella ⇒ "non appartenente al tenant e/o non individuabile"; in entrambi i casi alertActionErrore riga scartata. - Tipo: validation · Enforcement: mixed (BL + lettura DB) · Confidence: VERIFIED (logica BL) / INFERRED (SQL interno di
GetAssetLocationByParamAndTnt) - Evidenza:
ValidateSpaceLocation—PeopleBulkLoader.vb:285-330;Rows.Count = 1⇒ID_VANO:306-309;> 1:310-313;0/else:314-323.
BR-BLK-014 — Deduplica in insert
- Regola: prima dell'inserimento, se la chiave individua una persona già esistente per il tenant, l'insert è bloccato:
existEntityByKeyAndTenant("ID_N", "PERSONE_", "ID_N", peopleKeyValue, tenant)ritorna una stringacode,id;code=0⇒ "esiste già ... per un'altra commessa" (da far legare dal responsabile), altrimenti ⇒ "esiste già ... associata alla commessa". In entrambi i casi la persona non viene creata. - Tipo: validation · Enforcement: BL · Confidence: VERIFIED (chiamante) / INFERRED (SQL interno
PRP_EXISTENTITYBYKEYANDTENANT) - Evidenza:
peopleValue = New DAO_GenericEntity().existEntityByKeyAndTenant(...)e branch sul primo elemento dello split","—PeopleBulkLoader.vb:370-377; DAO →PRP_EXISTENTITYBYKEYANDTENANT(OUT CLOB) —DAO_GenericEntity.vb:731-763. - Flag: magic codes nel valore di ritorno (
0= altra commessa,≠0= commessa corrente).
BR-BLK-015 — Risoluzione della chiave persona
- Regola: se
strPeopleKeyè vuoto la chiave èID_Nletto direttamente dalla riga; altrimenti si compone unaWHEREa partire dai valori delle colonne-chiave (tipizzata: numerico senza apici, stringa con apici ed escaping'→'') e si recuperaID_NviaGetPeopleByFilter, solo se il filtro individua esattamente 1 persona. - Tipo: calculation · Enforcement: BL · Confidence: VERIFIED
- Evidenza: composizione
whereclauseectrlPeople.GetPeopleByFilter(whereclause)conRows.Count = 1—PeopleBulkLoader.vb:342-367. - Flag: SQL costruito per concatenazione di stringhe (superficie di injection mitigata dall'escaping
Replace("'", "''")e dalla tipizzazione delle colonne).
BR-BLK-016 — Mappatura campi per struttura entità e ruoli
- Regola: solo le colonne del file mappabili sui campi della
EntityStructurediPERSONE_(ottenuta per i ruoli dell'utente) vengono scritte. Sono esclusi: i campi spaziali (_spaceFields), le colonne di servizioLOG_RES/LOG_DET, i campi di tipoBLOBe i campi il cui nome inizia conID_. - Tipo: validation (permission-driven) · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
struct = New DAO_Metadata().GetEntityStructure(ENTITY, roles)estruct.Fields.Find(Function(f) (f.Label = col.ColumnName Or f.Field = col.ColumnName.ToUpper) AndAlso (f.DataType <> "BLOB" And Not f.Field.StartsWith("ID_")))—PeopleBulkLoader.vb:383-405;_spaceFields—:20; ruoli viaInfocadLoginSettingsProvider().GetUserRoles:337. - Flag: i campi
ID_*sono esclusi dall'import per riga (l'unica eccezione èID_VANO, aggiunto esplicitamente — BR-BLK-017).
BR-BLK-017 — Iniezione esplicita di ID_VANO in insert
- Regola: il vano risolto (
idRoom) è aggiunto ai campi entità comeID_VANOprima della mappatura degli altri campi. - Tipo: calculation · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
entityFields(...) = New String(1) {"ID_VANO", CStr(idRoom)}—PeopleBulkLoader.vb:379-381.
BR-BLK-018 — Normalizzazione date dd/MM/yyyy (it-IT)
- Regola: i valori di tipo
DateTimedel file vengono riformattati add/MM/yyyyusando la culturait-ITprima di essere passati al salvataggio. - Tipo: date-logic · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
Dim culture As CultureInfo = New CultureInfo("it-IT") ... dateValue = giorno + "/" + mese + "/" + anno—PeopleBulkLoader.vb:391-399(insert) e:499-507(update). - Flag: cultura e formato hard-coded (
it-IT,dd/MM/yyyy); si veda anche BR-PROP-024 (le NLS di sessione forzate lato DB aDD/MM/YYYY HH24:MI:SSinPRP_MANAGEENTITY). La lettura dell'Excel applica a sua volta un'euristica di conversione date (GetCellValue) dipendente dallaCurrentUICulture(BulkLoaderBase.vb:702-750).
BR-BLK-019 — Stamping ID_CHANGED_BY
- Regola:
DAO_People.SavePeopleaggiungeID_CHANGED_BY = <username>all'insieme dei campi se non già presente. - Tipo: validation (audit) · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
If Not bFound Then Array.Resize(KeyValue, ...) : KeyValue(...) = New String(1) {"ID_CHANGED_BY", username}—DAO_People.vb:233-244. - Nota: condivisa con BR-PROP-016 (stesso pattern di audit sulle entità).
BR-BLK-020 — Persistenza via PRP_MANAGEENTITY
- Regola:
SavePeople(username, peopleID, KeyValue)invocaDAO_GenericEntity.ManageEntity(username, peopleID, "ID_N", "PERSONE", "", "", KeyValue), che risolve la tabella fisicaPERSONE_e chiama la procedura genericaPRP_MANAGEENTITY(INSERT conRETURNING ID_Nin creazione, UPDATE su id in aggiornamento; binding tenant suGLOBAL_TENANCY_BINDINGS). - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED (catena) / SUPPORTED (interno procedura, ereditato da BR-PROP)
- Evidenza:
Return genCtrl.ManageEntity(username, peopleID, "ID_N", "PERSONE", String.Empty, String.Empty, KeyValue)—DAO_People.vb:247-248. Comportamento interno diPRP_MANAGEENTITY: vedi BR-PROP (BR-PROP-001..010, 024, 025).
BR-BLK-021 — Interpretazione del ritorno di SavePeople
- Regola:
idPeoplenumerico ⇒ successo (alertActionSuccess, oppureActionSuccessWithWarningse il log contiene già messaggi);idPeoplenon numerico ma non vuoto ⇒ errore DB (il messaggio è accodato al log e scritto in alertActionError). - Tipo: state-transition · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
If IsNumeric(idPeople) Then ... ActionSuccess/ActionSuccessWithWarning ElseIf idPeople <> "" Then log.Append(idPeople) ... ActionError—PeopleBulkLoader.vb:414-426(insert),:558-573(update). - Nota: coerente con BR-PROP-027 (numerico = successo, non numerico = errore DB).
BR-BLK-022 — Contatori di completamento (e sovrastima di CreatedObjects)
- Regola: durante
StartImportsi contanoTotalObjects(righe non vuote),ValidObjects(righe che superanoValidateObject),CreatedObjects(righe per cuiInsertObjectritornaTrue);warnsè incrementato quando l'insert fallisce o quando il log non contiene la stringa"senza errori". - Tipo: state-transition · Enforcement: BL · Confidence: VERIFIED (conteggio) / INFERRED (difetto)
- Evidenza: ciclo di conteggio —
PeopleBulkLoader.vb:101-120; marcatura warningIf Not log.ToString().Contains("senza errori"):108-113. - Flag: difetto —
InsertPeople/updatePeopleritornanoTrue(:427,:575) anche quando la riga è scartata (deduplica bloccante, errore DB, chiave non risolta): in questi casiCreatedObjectsviene comunque incrementato, pur avendo scritto un alertActionError. Il contatoreCREATEDOBJSpersistito può quindi sovrastimare le persone effettivamente create. Da verificare con Descor. - Flag: magic string
"senza errori"come discriminante di successo pieno.
BR-BLK-023 — Scrittura dell'esito sul foglio e ripersistenza
- Regola: al termine,
UploadLogOnUploadedFileaggiorna il foglio Excel scrivendoLOG_RES(SUCCESS/ERROR) eLOG_DET(dettaglio) per ogni riga (viaUPDATE [foglio] ... WHERE <chiavi>), ripersiste il file aggiornato nel processo (UpdateDocumentFile→RPS_UPDATEDOCUMENTFILE) e cancella la copia temporanea su disco.LOG_DETè troncato a 250 caratteri; gli erroriORA-*sono ridotti al solo codice (primi 9 caratteri). - Tipo: side-effect · Enforcement: mixed · Confidence: VERIFIED
- Evidenza:
UploadLogOnUploadedFile(...)—BulkLoaderBase.vb:1132-1232; troncamentierrLog.Substring(0, 9)eSubstring(0, 250):1180-1186;UpdateDocumentFile+File.Delete(filename):1216-1220; chiamata daStartImportconkeyVal(chiavi oID_N) —PeopleBulkLoader.vb:125-129. - Flag: dipende dal provider OleDb (vedi BR-BLK-029); la cancellazione del file su disco impatta il retry (BR-BLK-006).
BR-BLK-024 — Filtro multi-tenant
- Regola: il tenant corrente è risolto una volta a inizio import (
GetCurrentTenancyID(Username)) e usato per la risoluzione della collocazione (BR-BLK-013) e per la deduplica (BR-BLK-014). - Tipo: permission · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
_currenttenantID = tntCtrl.GetCurrentTenancyID(Username)—PeopleBulkLoader.vb:76-77; uso inGetAssetLocationByParamAndTnt(param, _currenttenantID):303eexistEntityByKeyAndTenant(..., _currenttenantID):371,472. - Nota: il binding tenant vero e proprio è propagato da
PRP_MANAGEENTITY(BR-PROP-009/010).
BR-BLK-025 — Grant di upload (solo UI, valutato sull'entità Asset)
- Regola: l'opzione
IMP_PERSONEè abilitata solo se l'utente ha grantADD_DELETE,UPD_PERSONEsolo se ha grantEDIT; entrambi i grant sono valutati sull'entità Asset (SystemFields.AssetEntity). Se il grant manca, l'opzione della dropdown è disabilitata. - Tipo: permission · Enforcement: UI · Confidence: VERIFIED
- Evidenza:
If Not HasUserGrant(IVPermission.ADD_DELETE, SystemFields.AssetEntity) Then LoadOptions.Items.FindByValue("IMP_PERSONE").Enabled = False—UploadProcessControl.ascx.vb:897-899;EDIT→UPD_PERSONE:893-895. - Flag: controllo UI-only — il servizio remoting
BulkLoader/PeopleBulkLoadernon ricontrolla alcun grant (nessunHasUserGrantlato server): la barriera è puramente cosmetica e bypassabile da un chiamante che invochi direttamente il servizio. Inoltre il permesso per l'import Persone è legato all'entità Asset (accoppiamento non ovvio) — da chiarire con Descor.
BR-BLK-026 — File obbligatorio
- Regola: se non è stato caricato alcun file (per tutti i rami tranne DWG e OMI-anagrafica) viene mostrato un messaggio e il caricamento è interrotto.
- Tipo: validation · Enforcement: UI · Confidence: VERIFIED
- Evidenza:
If upload1.UploadedFiles.Count <= 0 Then ShowMessage(...DocUploadNoFileSelectedMsg...) : Exit Sub—UploadProcessControl.ascx.vb:391-402.
BR-BLK-027 — Update Persone: flag di collocazione/rilascio asset
- Regola: in
UPD_PERSONE,evaluateLocationvale0se è spuntato "aggiorna solo attributi" (chkUpdateOnlyPeopleAttributes),1altrimenti;evaluateReleaseAssetvale1se spuntato "sgancia asset collegati" (chkDropLinkedAsset). Con cambio vano (idRoom ≠ SourceRoomID) gli asset collegati alla persona sono trasferiti nel nuovo vano (UpdatePeopleChangeROOM), ed eventualmente marcatiToReleaseseevaluateReleaseAsset=1. - Tipo: state-transition · Enforcement: mixed · Confidence: VERIFIED
- Evidenza (UI):
..., strPeopleKey, False, If(chkUpdateOnlyPeopleAttributes.Checked, 0, 1), If(chkDropLinkedAsset.Checked, 1, 0)—UploadProcessControl.ascx.vb:468. - Evidenza (BL): dispatch collocazione
InsertObject(_evaluateLocation) —PeopleBulkLoader.vb:36-66; trasferimento asset eUpdatePeopleChangeROOM(data)—:515-543. - Flag: flag nascosti mappati da checkbox; stringhe magiche di
ReturnCode("OK","KO","-99","The source and destination room are the same."):529-539.
BR-BLK-028 — Update dedup (codici 1/0/-1)
- Regola: in update la persona è aggiornata solo se
existEntityByKeyAndTenantritorna code1(individuata univocamente per la commessa). Code0⇒ "non esiste in archivio per questa commessa",-1⇒ "non identificabile univocamente", altro ⇒ "non identificabile univocamente per la commessa corrente"; in tutti questi casi l'update è saltato (viene comunque scritto un alert). - Tipo: validation · Enforcement: BL · Confidence: VERIFIED
- Evidenza:
Selectsui valoriCInt(peopleValueArray(0))= 0 / = -1 / = 1 / Else—PeopleBulkLoader.vb:471-548; l'aggiornamento effettivoSavePeople(Username, CInt(peopleValueArray(1)), entityFields)avviene solo nel ramo= 1:544. - Flag: magic codes
1/0/-1.
BR-BLK-029 — Lettura Excel via OleDb e selezione del foglio
- Regola: il file è letto con il provider OleDb (connection string di configurazione
xls, conExtended PropertiesExcel 8.0per.xls/Excel 12.0per.xlsx). Viene selezionato automaticamente il primo foglio il cui nome tabella contiene$ed è diverso daFoglio1$. - Tipo: config-flag · Enforcement: BL · Confidence: SUPPORTED (dipende dall'ambiente/provider installato)
- Evidenza:
LoadUploadedFileOleDbcon euristica sul foglio... .Contains("$") AndAlso Not ....Contains("Foglio1$") ...—BulkLoaderBase.vb:610-654;GetExcelConnString(provider per estensione):1318-1339;LoadUploadedFile⇒LoadUploadedFileOleDb(filename, False):568-570. - Flag: dipendenza d'ambiente (provider ACE/JET OleDb sul server) e valore hard-coded italiano
"Foglio1$"; esiste anche un percorso alternativo OpenXml non usato nel path pilota (LoadUploadedFileOpenXml).
Sintesi dei rischi e flag
Regole enforced SOLO nell'UI (rischio: bypassabili da altri path)
- BR-BLK-025 — il grant di upload (
ADD_DELETE/EDITsu entità Asset) è verificato solo lato UI; il servizio remotingBulkLoadernon ricontrolla alcun permesso. Un chiamante diretto del servizio bypassa il controllo. - BR-BLK-026 — il vincolo "file obbligatorio" è solo UI.
Difetti / gotcha
- BR-BLK-022 —
CreatedObjects/CREATEDOBJSsovrastima:InsertObjectritornaTrueanche su riga scartata (dedup, errore DB, chiave non risolta). - BR-BLK-006 — il retry dipende dalla copia su disco del file, che a fine import viene cancellata (BR-BLK-023), e da un
FILENAMEmemorizzato come solo nome-base (BR-BLK-001): il retry di un processo già completato rischia di ritornare0senza operare. - BR-BLK-011 — la validazione di congruenza colonne-file↔colonne-DB è disattivata (codice commentato): colonne inattese nel file vengono silenziosamente ignorate.
Magic number / valori e stringhe hard-coded
- Limite messaggio alert
4000/3999(BR-BLK-005); troncamentiLOG_DET250eORA-9(BR-BLK-023). - Enum
ActionResults0-4scritti comeSTATUSinGLOBAL_UPLOAD_ALERT(BR-BLK-004); codici ritorno dedup1/0/-1(BR-BLK-014, BR-BLK-028). - Stringa
"senza errori"come discriminante di successo (BR-BLK-022);ReturnCode"OK"/"KO"/"-99"/"The source and destination room are the same."(BR-BLK-027). - Refuso
"ENTITY UNKNOW"(BR-BLK-007); foglio"Foglio1$"escluso (BR-BLK-029).
Logica date-sensitive / cultura
- BR-BLK-018 — riformattazione
dd/MM/yyyycon culturait-IThard-coded; euristica di conversione date in lettura Excel dipendente dallaCurrentUICulture(GetCellValue).
Flag nascosti
- BR-BLK-027 —
evaluateLocation(solo-attributi) edevaluateReleaseAsset(sgancio asset) pilotati da checkbox UI e propagati fino al server come interi.
Dipendenze d'ambiente / cliente-specifiche
- BR-BLK-029 — provider OleDb (ACE/JET) installato sul server InfocadServer; BR-BLK-020 eredita le varianti cliente-specifiche di
PRP_MANAGEENTITY(generazione codice, trigger custom) documentate in BR-PROP.
Open questions
- Rappresentazione effettivamente scritta in
GLOBAL_UPLOAD_PROCESS.STATUSdal parametroPCOMPLETION(enumCompletionResultsbindato comeVarchar2): nome ("Done") o ordinale? (BR-BLK-003). - Impatto reale del retry (BR-BLK-006):
RPS_RETRYUPLOADPROCESSrestituisce il path completo o il solo nome-base? Il file su disco è ancora presente dopo il completamento? Da verificare con Descor. - Conferma della sovrastima di
CREATEDOBJS(BR-BLK-022) su dati reali e sua eventuale rilevanza per la reportistica dei caricamenti. - SQL interno di
GetAssetLocationByParamAndTntePRP_EXISTENTITYBYKEYANDTENANT(BR-BLK-013, BR-BLK-014) — non ispezionati riga per riga. - Motivazione dell'accoppiamento del permesso di import Persone all'entità Asset (BR-BLK-025).
- Se il processo BulkLoader giri in modo sincrono nel thread della richiesta remoting o su thread dedicato del servizio (non determinabile dal solo codice).