Subdominio activo

SoluManager

Este espacio ya quedo reservado y publicado para el modulo SoluManager.

La aplicacion principal aun no ha sido cargada en esta carpeta.

function ecosystem_apps_seed(): array { return [ [ 'code' => 'soluactivos', 'name' => 'SOLUACTIVOS', 'folder_path' => 'D:\\FACILWEB\\SOLUACTIVOS', 'public_path' => '/SOLUACTIVOS/', 'description' => 'Activos, control operativo y catalogos internos.', 'deployment_status' => 'planeada', 'default_company_admin_manage' => 0, 'display_order' => 10, ], [ 'code' => 'solucrm', 'name' => 'SOLUCRM', 'folder_path' => 'D:\\FACILWEB\\SOLUCRM', 'public_path' => '/SOLUCRM/', 'description' => 'Relacion comercial, clientes y seguimiento de ventas.', 'deployment_status' => 'planeada', 'default_company_admin_manage' => 0, 'display_order' => 20, ], [ 'code' => 'solufiles', 'name' => 'SOLUFILES', 'folder_path' => 'D:\\FACILWEB\\SOLUFILES', 'public_path' => '/SOLUFILES/', 'description' => 'Archivos, bibliotecas y control documental.', 'deployment_status' => 'planeada', 'default_company_admin_manage' => 0, 'display_order' => 30, ], [ 'code' => 'solumail', 'name' => 'SOLUMAIL', 'folder_path' => 'D:\\FACILWEB\\SOLUMAL', 'public_path' => '/SOLUMAL/', 'description' => 'Correo, cuentas, reglas y bandejas compartidas.', 'deployment_status' => 'planeada', 'default_company_admin_manage' => 0, 'display_order' => 40, ], [ 'code' => 'solumanager', 'name' => 'SOLUMANAGER', 'folder_path' => 'D:\\FACILWEB\\SOLUMANAGER', 'public_path' => '/SOLUMANAGER/', 'description' => 'Orquestacion administrativa del ecosistema.', 'deployment_status' => 'operativa-local', 'default_company_admin_manage' => 0, 'display_order' => 50, ], [ 'code' => 'solutask', 'name' => 'SOLUTASK', 'folder_path' => 'D:\\FACILWEB\\SOLUTASK', 'public_path' => '/SOLUTASK/', 'description' => 'Tareas, proyectos y trabajo colaborativo.', 'deployment_status' => 'planeada', 'default_company_admin_manage' => 0, 'display_order' => 60, ], [ 'code' => 'solutranscribe', 'name' => 'SOLUTRANSCRIBE', 'folder_path' => 'D:\\FACILWEB\\SOLUTRANSCRIBE', 'public_path' => '/SOLUTRANSCRIBE/', 'description' => 'Transcripcion, lectura asistida y salidas estructuradas.', 'deployment_status' => 'operativa-local', 'default_company_admin_manage' => 1, 'display_order' => 70, ], ]; } function ensure_ecosystem_admin_schema(): void { mysql()->exec( 'CREATE TABLE IF NOT EXISTS ecosystem_apps ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, code VARCHAR(120) NOT NULL, name VARCHAR(190) NOT NULL, folder_path VARCHAR(255) NOT NULL, public_path VARCHAR(190) DEFAULT NULL, description TEXT DEFAULT NULL, deployment_status VARCHAR(80) NOT NULL DEFAULT "planeada", default_company_admin_manage TINYINT(1) NOT NULL DEFAULT 0, is_active TINYINT(1) NOT NULL DEFAULT 1, display_order INT UNSIGNED NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uq_ecosystem_apps_code (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' ); mysql()->exec( 'CREATE TABLE IF NOT EXISTS ecosystem_company_apps ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, company_id BIGINT UNSIGNED NOT NULL, app_id BIGINT UNSIGNED NOT NULL, access_status VARCHAR(40) NOT NULL DEFAULT "disabled", allow_company_admin_manage TINYINT(1) NOT NULL DEFAULT 0, notes TEXT DEFAULT NULL, assigned_by BIGINT UNSIGNED DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uq_ecosystem_company_apps (company_id, app_id), KEY idx_ecosystem_company_apps_app (app_id), CONSTRAINT fk_ecosystem_company_apps_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE, CONSTRAINT fk_ecosystem_company_apps_app FOREIGN KEY (app_id) REFERENCES ecosystem_apps (id) ON DELETE CASCADE, CONSTRAINT fk_ecosystem_company_apps_actor FOREIGN KEY (assigned_by) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' ); mysql()->exec( 'CREATE TABLE IF NOT EXISTS ecosystem_user_apps ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, company_id BIGINT UNSIGNED NOT NULL, app_id BIGINT UNSIGNED NOT NULL, access_status VARCHAR(40) NOT NULL DEFAULT "inherit", role_label VARCHAR(120) DEFAULT NULL, allow_manage_users TINYINT(1) NOT NULL DEFAULT 0, notes TEXT DEFAULT NULL, assigned_by BIGINT UNSIGNED DEFAULT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uq_ecosystem_user_apps (user_id, company_id, app_id), KEY idx_ecosystem_user_apps_company (company_id), KEY idx_ecosystem_user_apps_app (app_id), CONSTRAINT fk_ecosystem_user_apps_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE, CONSTRAINT fk_ecosystem_user_apps_company FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE, CONSTRAINT fk_ecosystem_user_apps_app FOREIGN KEY (app_id) REFERENCES ecosystem_apps (id) ON DELETE CASCADE, CONSTRAINT fk_ecosystem_user_apps_actor FOREIGN KEY (assigned_by) REFERENCES users (id) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' ); $stmt = mysql()->prepare( 'INSERT INTO ecosystem_apps ( code, name, folder_path, public_path, description, deployment_status, default_company_admin_manage, is_active, display_order ) VALUES ( :code, :name, :folder_path, :public_path, :description, :deployment_status, :default_company_admin_manage, 1, :display_order ) ON DUPLICATE KEY UPDATE name = VALUES(name), folder_path = VALUES(folder_path), public_path = VALUES(public_path), description = VALUES(description), deployment_status = VALUES(deployment_status), default_company_admin_manage = VALUES(default_company_admin_manage), display_order = VALUES(display_order), is_active = 1' ); foreach (ecosystem_apps_seed() as $app) { $stmt->execute([ ':code' => $app['code'], ':name' => $app['name'], ':folder_path' => $app['folder_path'], ':public_path' => $app['public_path'], ':description' => $app['description'], ':deployment_status' => $app['deployment_status'], ':default_company_admin_manage' => $app['default_company_admin_manage'], ':display_order' => $app['display_order'], ]); } } function ecosystem_admin_token(): string { start_app_session(); if (!isset($_SESSION['ecosystem_admin_token']) || !is_string($_SESSION['ecosystem_admin_token'])) { $_SESSION['ecosystem_admin_token'] = bin2hex(random_bytes(24)); } return $_SESSION['ecosystem_admin_token']; } function verify_ecosystem_admin_token(): void { $token = (string) ($_POST['token'] ?? ''); if ($token === '' || !hash_equals(ecosystem_admin_token(), $token)) { http_response_code(419); exit('Sesion de formulario vencida. Recarga la pagina e intenta de nuevo.'); } } function ecosystem_status_label(string $status): string { return match ($status) { 'enabled' => 'Habilitada', 'pending' => 'Reservada', 'disabled' => 'Sin acceso', 'inherit' => 'Hereda empresa', 'blocked' => 'Bloqueado', 'planeada' => 'Planeada', 'operativa-local' => 'Operativa local', default => ucfirst(str_replace(['-', '_'], ' ', $status)), }; } function ecosystem_flash_set(string $message): void { start_app_session(); $_SESSION['ecosystem_admin_flash'] = $message; } function ecosystem_flash_take(): ?string { start_app_session(); if (!isset($_SESSION['ecosystem_admin_flash'])) { return null; } $message = (string) $_SESSION['ecosystem_admin_flash']; unset($_SESSION['ecosystem_admin_flash']); return $message; } function ecosystem_apps(): array { return mysql()->query('SELECT * FROM ecosystem_apps WHERE is_active = 1 ORDER BY display_order ASC, name ASC')->fetchAll(); } function ecosystem_companies(): array { return mysql()->query('SELECT id, name, code, status FROM companies ORDER BY name ASC')->fetchAll(); } function ecosystem_users_by_company(int $companyId): array { $stmt = mysql()->prepare( 'SELECT id, company_id, first_name, last_name, email, is_active, status FROM users WHERE company_id = :company_id ORDER BY first_name ASC, last_name ASC, email ASC' ); $stmt->execute([':company_id' => $companyId]); return $stmt->fetchAll(); } function ecosystem_company_access_map(): array { $rows = mysql()->query('SELECT * FROM ecosystem_company_apps')->fetchAll(); $map = []; foreach ($rows as $row) { $map[(int) $row['company_id']][(int) $row['app_id']] = $row; } return $map; } function ecosystem_user_access_map(int $companyId): array { $stmt = mysql()->prepare('SELECT * FROM ecosystem_user_apps WHERE company_id = :company_id'); $stmt->execute([':company_id' => $companyId]); $rows = $stmt->fetchAll(); $map = []; foreach ($rows as $row) { $map[(int) $row['user_id']][(int) $row['app_id']] = $row; } return $map; } function ecosystem_summary_counts(): array { return [ 'companies' => (int) mysql()->query('SELECT COUNT(*) FROM companies')->fetchColumn(), 'users' => (int) mysql()->query('SELECT COUNT(*) FROM users WHERE is_active = 1')->fetchColumn(), 'apps' => (int) mysql()->query('SELECT COUNT(*) FROM ecosystem_apps WHERE is_active = 1')->fetchColumn(), 'company_assignments' => (int) mysql()->query("SELECT COUNT(*) FROM ecosystem_company_apps WHERE access_status IN ('enabled','pending')")->fetchColumn(), 'user_assignments' => (int) mysql()->query("SELECT COUNT(*) FROM ecosystem_user_apps WHERE access_status IN ('enabled','blocked')")->fetchColumn(), ]; } function ecosystem_redirect_url(int $companyId): string { $params = []; if ($companyId > 0) { $params['company_id'] = $companyId; } $query = $params !== [] ? ('?' . http_build_query($params)) : ''; return '/SOLUMANAGER/' . $query; } function save_company_accesses(int $companyId, array $accessRows, int $actorId): void { $stmt = mysql()->prepare( 'INSERT INTO ecosystem_company_apps ( company_id, app_id, access_status, allow_company_admin_manage, notes, assigned_by ) VALUES ( :company_id, :app_id, :access_status, :allow_company_admin_manage, :notes, :assigned_by ) ON DUPLICATE KEY UPDATE access_status = VALUES(access_status), allow_company_admin_manage = VALUES(allow_company_admin_manage), notes = VALUES(notes), assigned_by = VALUES(assigned_by)' ); foreach ($accessRows as $appId => $row) { $appId = (int) $appId; if ($appId <= 0) { continue; } $status = (string) ($row['status'] ?? 'disabled'); if (!in_array($status, ['disabled', 'pending', 'enabled'], true)) { $status = 'disabled'; } $stmt->execute([ ':company_id' => $companyId, ':app_id' => $appId, ':access_status' => $status, ':allow_company_admin_manage' => !empty($row['allow_company_admin_manage']) ? 1 : 0, ':notes' => trim((string) ($row['notes'] ?? '')), ':assigned_by' => $actorId, ]); } } function save_user_accesses(int $userId, int $companyId, array $accessRows, int $actorId): void { $stmt = mysql()->prepare( 'INSERT INTO ecosystem_user_apps ( user_id, company_id, app_id, access_status, role_label, allow_manage_users, notes, assigned_by ) VALUES ( :user_id, :company_id, :app_id, :access_status, :role_label, :allow_manage_users, :notes, :assigned_by ) ON DUPLICATE KEY UPDATE access_status = VALUES(access_status), role_label = VALUES(role_label), allow_manage_users = VALUES(allow_manage_users), notes = VALUES(notes), assigned_by = VALUES(assigned_by)' ); foreach ($accessRows as $appId => $row) { $appId = (int) $appId; if ($appId <= 0) { continue; } $status = (string) ($row['status'] ?? 'inherit'); if (!in_array($status, ['inherit', 'enabled', 'blocked'], true)) { $status = 'inherit'; } $stmt->execute([ ':user_id' => $userId, ':company_id' => $companyId, ':app_id' => $appId, ':access_status' => $status, ':role_label' => trim((string) ($row['role_label'] ?? '')), ':allow_manage_users' => !empty($row['allow_manage_users']) ? 1 : 0, ':notes' => trim((string) ($row['notes'] ?? '')), ':assigned_by' => $actorId, ]); } } ensure_ecosystem_admin_schema(); $companies = ecosystem_companies(); $selectedCompanyId = (int) ($_GET['company_id'] ?? 0); if ($selectedCompanyId <= 0 && $companies !== []) { $selectedCompanyId = (int) ($companies[0]['id'] ?? 0); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_ecosystem_admin_token(); $action = (string) ($_POST['action'] ?? ''); if ($action === 'save_company_accesses') { $companyId = (int) ($_POST['company_id'] ?? 0); save_company_accesses($companyId, (array) ($_POST['company_access'] ?? []), (int) ($actor['id'] ?? 0)); ecosystem_flash_set('Permisos por empresa guardados.'); header('Location: ' . ecosystem_redirect_url($companyId)); exit; } if ($action === 'save_user_accesses') { $userId = (int) ($_POST['user_id'] ?? 0); $companyId = (int) ($_POST['company_id'] ?? 0); save_user_accesses($userId, $companyId, (array) ($_POST['user_access'] ?? []), (int) ($actor['id'] ?? 0)); ecosystem_flash_set('Permisos por usuario guardados.'); header('Location: ' . ecosystem_redirect_url($companyId)); exit; } } $apps = ecosystem_apps(); $companyAccessMap = ecosystem_company_access_map(); $users = $selectedCompanyId > 0 ? ecosystem_users_by_company($selectedCompanyId) : []; $userAccessMap = $selectedCompanyId > 0 ? ecosystem_user_access_map($selectedCompanyId) : []; $summary = ecosystem_summary_counts(); $flash = ecosystem_flash_take(); $token = ecosystem_admin_token(); $actorName = trim((string) ($actor['first_name'] ?? '') . ' ' . (string) ($actor['last_name'] ?? '')); ?> Control de ecosistema | SOLUMANAGER

SoluManager ยท superadmin central

Control de ecosistema

Gestiona empresas, usuarios y acceso a las aplicaciones del ecosistema desde una sola base compartida.

Actor actual: