find($this->argument('tenant')); if ($tenant === null || ! Schema::hasColumn('tenants', 'work_context_policy')) { $this->error('Empresa inexistente ou instalação do contexto pendente.'); return self::FAILURE; } $users = User::query()->where('tenant_id', $tenant->id)->get(); $actor = $users->first(); if ($actor === null || $contexts->policy($actor) === null || $contexts->purchased($actor) === [] || ! app(OrganizationAccess::class)->active($tenant->id)) { $this->error('Defina produto contratado, opções e administração da empresa antes da entrega.'); return self::FAILURE; } $administrators = 0; foreach ($users as $user) { $profiles = DB::table('organization_memberships as m')->join('organization_profiles as p', 'p.id', '=', 'm.profile_id') ->where('m.tenant_id', $tenant->id)->where('p.tenant_id', $tenant->id)->where('m.user_id', $user->id) ->where('m.maintenance', false)->whereNull('m.expires_at')->pluck('p.permissions'); if ($profiles->contains(fn ($json) => in_array('admin', json_decode($json, true, 32, JSON_THROW_ON_ERROR), true))) { $administrators++; } } $clean = true; foreach (Schema::getTables() as $table) { $name = $table['name']; if (in_array($name, ['users', 'departments', 'cost_centers', 'organization_profiles', 'organization_memberships', 'organization_access', 'audit_logs'], true)) { continue; } if (Schema::hasColumn($name, 'tenant_id') && DB::table($name)->where('tenant_id', $tenant->id)->exists()) { $this->error('Existem registos a reconciliar antes da entrega: '.$name); $clean = false; } } $enabled = $contexts->policy($actor)['enabled'] ?? []; if ($administrators < 2 || $enabled === [] || array_diff($enabled, $contexts->purchased($actor)) !== []) { $this->error('Confira dois administradores permanentes e opções activadas dentro do produto contratado.'); $clean = false; } foreach ($enabled as $key) { if (! (WorkContext::OPTIONS[$key]['operational'] ?? false)) { $this->error('Percurso operacional ainda pendente: '.$key); $clean = false; } if (! $users->contains(fn ($user) => in_array($key, $contexts->available($user), true))) { $this->error('Opção sem utilizador com perfil/contexto autorizado: '.$key); $clean = false; } } if ($clean) { $this->info('Conferência técnica aprovada. Não substitui aceitação funcional, revisão dos cadastros de configuração ou instalação de RH.'); } return $clean ? self::SUCCESS : self::FAILURE; } }