Passa al contenuto principale

Componenti UI — dominio job

🎯 Cosa fa

Sotto TrainingHub.BackOffice/Components/CRUD/job/ vivono i componenti Blazor CRUD per le 19 entità del dominio. Pattern generazione identico a inv, reg, edu: vedi componenti UI inv per dettagli generali.

🗺️ Entità e viste

CRUD standard

EntitàNote
WorkerForm ricco con cascade FK molteplici (company, companyLocation, role, department, riskLevel, academicQualification)
WorkerJobHistoryTipicamente in sola lettura, alimentato da logica di cambio mansione
WorkersJobAssociazione lavoratore-mansione
Job, JobGroup, JobSubcategoryAnagrafiche mansioni
Role, DepartmentAnagrafiche ruoli/reparti (reparti con tree view)
Risk, RiskLevelAnagrafiche rischi e livelli
AtecoCodeTree view gerarchica
AtecoCodeLegacyCRUD su atecoCodesLegacy. Esposto come admin tool per popolare/aggiornare il mapping versioni precedenti → codice corrente; non parte del flusso operativo utente. Alimenta la conversione automatica nell'import aziende (TrainingHub.Import/Engines/Company.cs ClearCompanyData).
CompaniesRisk, JobsRisk, WorkersRiskAssociazioni rischio per livello

Viste aggregate / analitiche

ComponenteRuolo
WorkersData.razorVista dati lavoratori con aggregazioni
JobsData.razorVista mansioni con statistiche
WorkerEffectiveRisk.razorVista calcolata dei rischi finali del lavoratore (cascade applicato)
WorkerComplianceSummary.razorCRUD auto-generato sulla view vw_workerComplianceSummary (read-only). Mostra rollup compliance per lavoratore: badge worstStatus + conteggi + giorni residui. Embed nello step "Conformità formativa" del wizard CompanyFormPopup con filtro companyId. Vedi pattern in Architettura — view → CRUD

Tutti e quattro sono CRUD generati su vista, non componenti custom: WorkersData.razor:3-6 (/job/vw_workersData), JobsData.razor:3-6 (/job/vw_jobsData) e WorkerEffectiveRisk.razor:3-6 (/job/vw_workerEffectiveRisks, policy page-job-vw_workerEffectiveRisks_R) ereditano da Tabiot.Blazor.DxGridBase e hanno il proprio .razor.tt.cs più il conf _conf/vw_*.dxgrid.conf.json. Un generator_run li riscrive: le personalizzazioni vanno nel conf o nel .razor.cs, non nel .razor.

🧩 Pattern chiave job-specifici

Form Worker con molteplici FK

WorkerForm.razor contiene ~6 combobox cascade-oriented:

<EditComboBox Data="fk_companyId" ... />
<EditComboBox Data="fk_companyLocationId" ... /> <!-- filtrato per companyId -->
<EditComboBox Data="fk_departmentId" ... /> <!-- filtrato per companyId -->
<EditComboBox Data="fk_roleId" ... />
<EditComboBox Data="fk_riskLevelId" ... />
<EditComboBox Data="fk_academicQualificationId" ... />

Il filtro dinamico dei combobox "dipendenti" (companyLocation, department filtrati per company) è logica custom nel .razor.cs. Al cambio companyId, i combobox correlati vengono ricaricati con il nuovo filtro.

Vista WorkerEffectiveRisk

Il cascade non è nel componente: è nella vista SQL job.vw_workerEffectiveRisks. Il code-behind si limita a SELECT * FROM job.fn_getWorkerRisks(@workerId) (WorkerEffectiveRisk.razor.cs:40), con un filtro su origin <> 'none' quando non si chiede «mostra tutti».

In sintesi, quel che fa la vista:

  1. Tre rami — mansione, azienda, personale — tutti su lavoratori attivi. jobsRisks.onlyIfCompanyHasRisk governa il ramo mansione; jobs.inheritsCompanyRisks e companiesRisks.onlyForExposedJobs governano il ramo azienda (lo filtrano, non sommano nulla): il primo dal lato mansione, il secondo dal lato rischio — un rischio marcato non si propaga a chi eredita, pur restando condizione per il ramo mansione.
  2. Spareggio per origine: worker > job > company.
  3. Livello: COALESCE(riskLevelId, companies.riskLevelId).
  4. Gli esclusi non spariscono: tornano con origin = 'excluded'.
  5. fn_getWorkerRisks aggiunge i rischi di catalogo non assegnati con origin = 'none'.

Le origini sono quindi cinque: job, company, worker, excluded, none. Dettaglio in logica applicativa.

Utile per:

  • Verifica manuale da parte del RSPP.
  • Generazione bozza DVR individuale.
  • Determinazione formazione richiesta (consumato da ITrainingExpirationService).

Reparti e ATECO — nessuna tree view

Department.razor e AtecoCode.razor portano entrambi una gerarchia nei dati (parentId e parentCode), ma in UI sono griglie piatte: DxGridBase + <DxGrid>, con i code-behind vuoti. Nessun DxTreeView, nessun TreeList, nessun drag-and-drop.

Derivazione del sesso dal codice fiscale

Forms/WorkerForm.razor.cs:8-12OnFiscalCodeChanged() fa una cosa sola: se fiscalCode ha almeno 16 caratteri, legge i caratteri 9-10 e imposta gender (> 40 → F, altrimenti M).

Non calcola data di nascita né luogo di nascita, non usa helper condivisi e non valida il checksum. Non c'è nessun pulsante: il metodo è invocato da Validate() (:36-43) insieme a OnCompanyChanged(), quindi scatta al salvataggio.

📁 File chiave

  • Components/CRUD/job/Worker.razor.cs — code-behind principale
  • Components/CRUD/job/Forms/WorkerForm.razor{,.cs} — form con cascade FK e auto-calcolo CF
  • Components/CRUD/job/WorkerEffectiveRisk.razor — vista cascade rischi
  • Components/CRUD/job/Department.razor + tree view helper
  • Components/CRUD/job/AtecoCode.razor + tree view
  • Components/CRUD/job/_conf/*.dxgrid.conf.json — configurazione

🔌 Estensione tipica

Pattern generale come nei domini precedenti. Specificità job:

  • Aggiungere un campo worker. Molti campi esistenti richiedono logica custom nel .razor.cs (cascade FK); valutare se il nuovo campo necessita di logica o è "semplice" form field.
  • Aggiungere un livello di rischio. Inserire riga in riskLevel (PK int) con label. Gli override lato UI non servono se i combobox sono già dinamici.
  • Modificare cascade rischi. Logica centrale in IRiskInheritanceService: modifiche lì invece che nel UI.
  • Nuova vista analitica. Segui il pattern di WorkersData / WorkerEffectiveRisk: componente Razor custom non-CRUD con @page directive, inject dei service necessari.

⚠️ Debito tecnico

  • Cascade filtri combobox in WorkerForm. La logica di filtro dinamico (companyLocation per company, department per company) è duplicata tra form. Valutare helper condiviso.
  • WorkerEffectiveRisk senza test. Componente centrale per compliance, ma senza copertura automatica. Regressioni difficili da detect.
  • Vista JobsData / WorkersData. Non è chiaro se sono "live" o cachate. Performance su dataset grandi.
  • Gerarchie senza rappresentazione ad albero. Reparti e ATECO hanno un parentId/parentCode che la griglia piatta non mostra: l'utente non vede la struttura. Valutare un TreeList condiviso.
  • Nessuna validazione del checksum CF. WorkerForm.razor.cs:10 si ferma a Length >= 16. L'algoritmo esiste già nel pacchetto Mascher (repo sorella dev3sd/Mascher, Anonymization/Italian/FiscalCode.cs).

🔗 Vedi anche