=250 dip o >50M EUR fatt o >43M EUR bilancio; media >=50 o >10M). */ class Nis2ClassificationService { /** Allegato I (alta criticita') -> essenziale se grande, importante se media */ private const ESSENTIAL_SECTORS = [ 'energy','energy_electricity','energy_district_heating','energy_oil','energy_gas','energy_hydrogen', 'transport','transport_air','transport_rail','transport_water','transport_road', 'banking','financial_markets','health','water','drinking_water','waste_water', 'digital_infra','digital_infrastructure','ict_service_management', 'public_admin','public_administration','space', ]; /** Allegato II (altri settori critici) -> importante se media o grande */ private const IMPORTANT_SECTORS = [ 'manufacturing','manufacturing_medical','manufacturing_computers','manufacturing_electrical', 'manufacturing_machinery','manufacturing_vehicles','manufacturing_transport', 'postal','postal_courier','chemical','chemicals','food', 'waste','waste_management','ict_services','digital_providers','research', ]; /** Categorie in ambito a prescindere dalla dimensione (art. 3 c. 5) -> classe fissa */ private const SIZE_INDEPENDENT = [ 'dns' => 'essential', 'tld' => 'essential', 'ixp' => 'essential', 'trust_qualified' => 'essential', 'trust_unqualified' => 'important', 'ecomm_public_network' => 'essential', 'ecomm_public_service' => 'essential', 'domain_registrar' => 'important', 'pa_central' => 'essential', 'pa_regional_local' => 'important', ]; /** * Classifica (autovalutazione). Input opzionali oltre a sector/employees/turnover: * balance, size_independent_category, is_autonomous, crit_sole_supplier, crit_public_impact, crit_systemic_risk. * @return array {entity_type, designation_basis, self_assessment_status, sub_threshold_candidate, * label, size, description, obligations[], warnings[], disclaimer} */ public static function classify(array $in): array { $sector = (string) ($in['sector'] ?? ''); $employees = (int) ($in['employees'] ?? 0); $turnover = (float) ($in['turnover'] ?? 0); $balance = (float) ($in['balance'] ?? 0); $sizeIndep = (string) ($in['size_independent_category'] ?? 'none'); $autonomous = array_key_exists('is_autonomous', $in) ? (int) $in['is_autonomous'] : 1; $critSole = !empty($in['crit_sole_supplier']); $critImpact = !empty($in['crit_public_impact']); $critSystemic = !empty($in['crit_systemic_risk']); $warnings = []; if (!$autonomous) { $warnings[] = "Impresa non autonoma (gruppo/collegate): il calcolo dimensionale va consolidato ai sensi dell'art. 6 della Raccomandazione 2003/361/CE. L'esito automatico potrebbe sottostimare la classe."; } // 1) Soggetti a prescindere dalla dimensione (art. 3 c. 5) if ($sizeIndep !== '' && $sizeIndep !== 'none' && isset(self::SIZE_INDEPENDENT[$sizeIndep])) { return self::result(self::SIZE_INDEPENDENT[$sizeIndep], 'size_independent', $employees, $turnover, $balance, $warnings, "Soggetto incluso a prescindere dalla dimensione (art. 3, comma 5, D.Lgs. 138/2024)."); } // 2) Matrice settore x dimensione (art. 3 c. 2) $size = self::sizeClass($employees, $turnover, $balance); // large|medium|small $isLarge = $size === 'large'; $isMedium = $size === 'medium'; if (in_array($sector, self::ESSENTIAL_SECTORS, true)) { if ($isLarge) return self::result('essential', 'dimensional', $employees, $turnover, $balance, $warnings); if ($isMedium) return self::result('important', 'dimensional', $employees, $turnover, $balance, $warnings); } if (in_array($sector, self::IMPORTANT_SECTORS, true)) { if ($isLarge || $isMedium) return self::result('important', 'dimensional', $employees, $turnover, $balance, $warnings); } // 3) Sotto-soglia con criteri qualitativi (art. 3 c. 9 lett. b/c/d) -> CANDIDATO (no auto-classe) if ($critSole || $critImpact || $critSystemic) { $r = self::result('not_applicable', 'sub_threshold_candidate', $employees, $turnover, $balance, $warnings, "Soggetto sotto la soglia dimensionale che soddisfa uno o piu' criteri qualitativi dell'art. 3, comma 9, lett. b/c/d del D.Lgs. 138/2024. NON e' una classificazione automatica: l'individuazione come soggetto essenziale o importante spetta all'Autorita' (ACN) ex art. 3, comma 13. Verificare/segnalarsi presso ACN."); $r['sub_threshold_candidate'] = true; $r['label'] = 'Potenziale soggetto individuabile (rinvio ACN)'; return $r; } // 4) Fuori ambito return self::result('not_applicable', 'out_of_scope', $employees, $turnover, $balance, $warnings); } /** Solo il tipo (compat con i vecchi chiamanti). */ public static function entityType(string $sector, int $employees, float $turnover, float $balance = 0): string { return self::classify(['sector' => $sector, 'employees' => $employees, 'turnover' => $turnover, 'balance' => $balance])['entity_type']; } /** large | medium | small (micro inclusa) — Racc. 2003/361/CE (criteri alternativi su fatturato/bilancio). */ private static function sizeClass(int $employees, float $turnover, float $balance): string { if ($employees >= 250 || $turnover > 50000000 || $balance > 43000000) return 'large'; if ($employees >= 50 || $turnover > 10000000 || $balance > 10000000) return 'medium'; return 'small'; } private static function result(string $type, string $basis, int $employees, float $turnover, float $balance, array $warnings, ?string $note = null): array { $sizeLabel = ($employees >= 250 || $turnover > 50000000 || $balance > 43000000) ? 'Grande impresa' : (($employees >= 50 || $turnover > 10000000 || $balance > 10000000) ? 'Media impresa' : 'Piccola/micro impresa'); $obligations = match ($type) { 'essential', 'important' => [ 'Misure di gestione del rischio di cybersicurezza (art. 24 D.Lgs. 138/2024)', 'Notifica degli incidenti significativi: preallarme 24h, notifica 72h, relazione finale 1 mese (art. 25 D.Lgs. 138/2024)', 'Responsabilita\' e formazione degli organi di amministrazione e direttivi (art. 23 D.Lgs. 138/2024)', $type === 'essential' ? 'Vigilanza proattiva (ex ante) da parte dell\'Autorita\'' : 'Vigilanza reattiva (ex post) da parte dell\'Autorita\'', $type === 'essential' ? 'Sanzioni fino a 10M EUR o 2% del fatturato mondiale annuo' : 'Sanzioni fino a 7M EUR o 1,4% del fatturato mondiale annuo', ], default => [ 'Nessun obbligo NIS2 automatico in base ai dati forniti', 'Buone pratiche di cybersicurezza comunque raccomandate', ], }; $labels = ['essential' => 'Soggetto Essenziale', 'important' => 'Soggetto Importante', 'not_applicable' => 'Non in ambito (in base ai dati)']; $descr = match ($type) { 'essential' => "Autovalutazione: la vostra organizzazione rientrerebbe tra i soggetti ESSENZIALI (settore ad alta criticita', Allegato I, dimensione di grande impresa).", 'important' => "Autovalutazione: la vostra organizzazione rientrerebbe tra i soggetti IMPORTANTI ai sensi del D.Lgs. 138/2024.", default => "Autovalutazione: in base ai dati forniti la vostra organizzazione non rientrerebbe automaticamente nell'ambito del D.Lgs. 138/2024.", }; if ($note) $descr .= ' ' . $note; return [ 'entity_type' => $type, 'designation_basis' => $basis, 'self_assessment_status' => 'preliminary', 'sub_threshold_candidate' => false, 'label' => $labels[$type] ?? $type, 'size' => $sizeLabel, 'description' => $descr, 'obligations' => $obligations, 'warnings' => $warnings, 'disclaimer' => "Autovalutazione PRELIMINARE non vincolante. La qualifica formale di soggetto essenziale/importante e la registrazione spettano esclusivamente all'ACN tramite la piattaforma (Determinazione ACN 333017/2025): dichiarazione ex DPR 445/2000 confermata dal punto di contatto, finestra di registrazione 1 gennaio - 28 febbraio, verifiche di coerenza ex art. 14. La classificazione formale e i pareri legali competono a Direzione/Legale.", ]; } }