[FEAT] Ruolo consulente: visibilità firm-scoped (org-switcher + Cruscotto Studio)

Un utente con role='consultant' e consulting_firm_id vede solo i CLIENTI del
proprio studio (organizations.consulting_firm_id = suo firm) UNION le proprie
membership dirette — non tutte le org (quello resta super_admin), non solo le
membership. Applicato in OrganizationController::list (selettore azienda) e
ConsultantController::portfolio (cruscotto). Additivo: super_admin e altri ruoli
invariati. Verificato: utente-test consultant/firm1 vede 2 aziende (cliente studio
996003 + membership 996001), non tutte. version 1.25.11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-07-29 15:53:54 +02:00
co-authored by Claude Opus 4.8
parent a8516efafc
commit faadb62da6
3 changed files with 26 additions and 2 deletions
@@ -124,8 +124,20 @@ class OrganizationController extends BaseController
{
$this->requireAuth();
$firmId = (int) ($this->currentUser['consulting_firm_id'] ?? 0);
if ($this->currentUser['role'] === 'super_admin') {
$orgs = Database::fetchAll('SELECT * FROM organizations WHERE is_active = 1 ORDER BY name');
} elseif ($this->currentUser['role'] === 'consultant' && $firmId > 0) {
// Consulente: vede TUTTI i clienti del proprio studio (organizations.consulting_firm_id
// = il suo firm) UNION le org di cui è membro diretto. Non l'intero DB (quello è super_admin).
$orgs = Database::fetchAll(
'SELECT DISTINCT o.*, uo.role AS user_role, uo.is_primary
FROM organizations o
LEFT JOIN user_organizations uo ON uo.organization_id = o.id AND uo.user_id = ?
WHERE o.is_active = 1 AND (o.consulting_firm_id = ? OR uo.user_id IS NOT NULL)
ORDER BY uo.is_primary DESC, o.name',
[$this->getCurrentUserId(), $firmId]
);
} else {
$orgs = Database::fetchAll(
'SELECT o.*, uo.role as user_role, uo.is_primary