[FEAT] A2 backend: Nis2ClassificationService v2 (matrice+bilancio, size-independent art.3 c.5, criteri sotto-soglia c.9 b/c/d, obblighi D.Lgs. art.23/24/25, esito 'preliminare non vincolante'); logica centralizzata (no duplicazione) + complete() salva i nuovi campi

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-15 17:06:17 +02:00
co-authored by Claude Opus 4.8
parent b2f47c0a47
commit c5fce7bdf7
3 changed files with 208 additions and 76 deletions
@@ -6,6 +6,7 @@
*/
require_once __DIR__ . '/BaseController.php';
require_once __DIR__ . '/../services/Nis2ClassificationService.php';
class OrganizationController extends BaseController
{
@@ -309,19 +310,31 @@ class OrganizationController extends BaseController
{
$this->validateRequired(['sector', 'employee_count', 'annual_turnover_eur']);
$sector = $this->getParam('sector');
$employees = (int) $this->getParam('employee_count');
$turnover = (float) $this->getParam('annual_turnover_eur');
$entityType = $this->classifyNis2Entity($sector, $employees, $turnover);
$r = Nis2ClassificationService::classify([
'sector' => $this->getParam('sector'),
'employees' => (int) $this->getParam('employee_count'),
'turnover' => (float) $this->getParam('annual_turnover_eur'),
'balance' => (float) $this->getParam('total_balance_eur', 0),
'size_independent_category' => $this->getParam('size_independent_category', 'none'),
'is_autonomous' => (int) $this->getParam('is_autonomous', 1),
'crit_sole_supplier' => (int) $this->getParam('crit_sole_supplier', 0),
'crit_public_impact' => (int) $this->getParam('crit_public_impact', 0),
'crit_systemic_risk' => (int) $this->getParam('crit_systemic_risk', 0),
]);
$this->jsonSuccess([
'entity_type' => $entityType,
'sector' => $sector,
'employee_count' => $employees,
'annual_turnover_eur' => $turnover,
'allows_voluntary' => $entityType === 'not_applicable',
'explanation' => $this->getClassificationExplanation($entityType, $sector, $employees, $turnover),
'entity_type' => $r['entity_type'],
'sector' => $this->getParam('sector'),
'allows_voluntary' => $r['entity_type'] === 'not_applicable',
'designation_basis' => $r['designation_basis'],
'self_assessment_status' => $r['self_assessment_status'],
'sub_threshold_candidate' => $r['sub_threshold_candidate'],
'label' => $r['label'],
'size' => $r['size'],
'explanation' => $r['description'],
'obligations' => $r['obligations'],
'warnings' => $r['warnings'],
'disclaimer' => $r['disclaimer'],
]);
}
@@ -334,32 +347,8 @@ class OrganizationController extends BaseController
*/
private function classifyNis2Entity(string $sector, int $employees, float $turnover): string
{
// Settori Essenziali (Allegato I)
$essentialSectors = [
'energy', 'transport', 'banking', 'health', 'water',
'digital_infra', 'public_admin', 'space',
];
// Settori Importanti (Allegato II)
$importantSectors = [
'manufacturing', 'postal', 'chemical', 'food', 'waste',
'ict_services', 'digital_providers', 'research',
];
// Soglie dimensionali
$isLarge = $employees >= 250 || $turnover >= 50000000;
$isMedium = ($employees >= 50 || $turnover >= 10000000) && !$isLarge;
if (in_array($sector, $essentialSectors)) {
if ($isLarge) return 'essential';
if ($isMedium) return 'important';
}
if (in_array($sector, $importantSectors)) {
if ($isLarge || $isMedium) return 'important';
}
return 'not_applicable';
// Logica centralizzata in Nis2ClassificationService (A2). Delego per evitare duplicazione.
return Nis2ClassificationService::entityType($sector, $employees, $turnover);
}
/**