'codice_etico', 'label' => 'Codice Etico'], ['key' => 'mission', 'label' => 'Mission'], ['key' => 'vision', 'label' => 'Vision'], ['key' => 'statuto', 'label' => 'Statuto'], ['key' => 'piano_sanzionatorio', 'label' => 'Piano Sanzionatorio'], ]; public function list(): void { $this->requireAuth(); // BUGFIX (#499): usare requireAuth+getCurrentOrgId dava sempre NO_ORG (currentOrgId // e' popolato solo da requireOrgAccess) → le 5 voci standard non comparivano MAI. // Ora risolviamo l'org dall'header e restituiamo SEMPRE le 5 voci standard; // i documenti salvati si aggiungono solo se un'org e' selezionata. $orgId = $this->resolveOrgId(); $rows = $orgId ? Database::fetchAll( "SELECT id, doc_key, title, description, file_url, is_standard, sort_order, updated_at FROM institutional_documents WHERE organization_id = ? ORDER BY is_standard DESC, sort_order ASC, id ASC", [$orgId] ) : []; $this->jsonSuccess(['docs' => $rows, 'standards' => self::STANDARDS]); } public function save(): void { $this->requireOrgRole(['org_admin', 'compliance_manager']); $this->validateRequired(['title', 'description']); $orgId = $this->getCurrentOrgId(); $userId = $this->getCurrentUserId(); $title = trim((string) $this->getParam('title')); $desc = trim((string) $this->getParam('description')); if ($title === '' || $desc === '') { $this->jsonError('Titolo e descrizione sono obbligatori', 422, 'MISSING_FIELDS'); } $fileUrl = $this->getParam('file_url'); $fileUrl = ($fileUrl !== null && trim((string) $fileUrl) !== '') ? trim((string) $fileUrl) : null; $id = (int) ($this->getParam('id') ?? 0); $docKey = $this->getParam('doc_key'); $stdKeys = array_column(self::STANDARDS, 'key'); $isStandard = ($docKey !== null && in_array($docKey, $stdKeys, true)) ? 1 : 0; if (!$isStandard) { $docKey = null; } // le voci custom non hanno doc_key // Trova riga esistente: per id, oppure per (org, doc_key) se voce standard. $existing = null; if ($id > 0) { $existing = Database::fetchOne( 'SELECT id FROM institutional_documents WHERE id=? AND organization_id=?', [$id, $orgId]); if (!$existing) { $this->jsonError('Documento non trovato', 404, 'NOT_FOUND'); } } elseif ($isStandard) { $existing = Database::fetchOne( 'SELECT id FROM institutional_documents WHERE organization_id=? AND doc_key=?', [$orgId, $docKey]); } if ($existing) { Database::update('institutional_documents', [ 'title' => $title, 'description' => $desc, 'file_url' => $fileUrl, ], 'id=? AND organization_id=?', [(int) $existing['id'], $orgId]); $savedId = (int) $existing['id']; } else { $savedId = Database::insert('institutional_documents', [ 'organization_id' => $orgId, 'doc_key' => $docKey, 'title' => $title, 'description' => $desc, 'file_url' => $fileUrl, 'is_standard' => $isStandard, 'created_by' => $userId, ]); } $this->jsonSuccess(['id' => $savedId], 'Documento salvato'); } public function delete(int $id): void { $this->requireOrgRole(['org_admin', 'compliance_manager']); $orgId = $this->getCurrentOrgId(); $row = Database::fetchOne( 'SELECT id FROM institutional_documents WHERE id=? AND organization_id=?', [$id, $orgId]); if (!$row) { $this->jsonError('Documento non trovato', 404, 'NOT_FOUND'); } Database::delete('institutional_documents', 'id=? AND organization_id=?', [$id, $orgId]); $this->jsonSuccess(null, 'Documento eliminato'); } }