diff --git a/app/Http/Controllers/GroupController.php b/app/Http/Controllers/GroupController.php index 8257712..25beb62 100644 --- a/app/Http/Controllers/GroupController.php +++ b/app/Http/Controllers/GroupController.php @@ -11,34 +11,34 @@ class GroupController extends Controller { private array $modules = [ - 'vinc_orc' => 'Vinculação Orçamentária', - 'termo_jur' => 'Termo Jurídico', - 'extrato_jur' => 'Extrato do Termo Jurídico', + 'budget_allocation' => 'Vinculação Orçamentária', + 'legal_term' => 'Termo Jurídico', + 'term_summary' => 'Extrato do Termo Jurídico', 'ci' => 'CI', - 'despacho' => 'Despacho', - 'parecer_jur' => 'Parecer Jurídico', - 'parecer_orc' => 'Parecer Orçamentário', - 'abertura' => 'Abertura', - 'analise_jur' => 'Análise Jurídica', - 'formalizacao' => 'Formalização', - 'orcamento' => 'Orçamento e Parcelas', - 'pagamento' => 'Pagamento Financeiro', - 'usuarios' => 'Gerenciamento de Usuários', - 'grupos' => 'Gerenciamento de Grupos', + 'dispatch' => 'Despacho', + 'legal_opinion' => 'Parecer Jurídico', + 'budget_opinion' => 'Parecer Orçamentário', + 'opening' => 'Abertura', + 'legal' => 'Análise Jurídica', + 'formalization' => 'Formalização', + 'budget' => 'Orçamento e Parcelas', + 'payment' => 'Pagamento Financeiro', + 'users' => 'Gerenciamento de Usuários', + 'groups' => 'Gerenciamento de Grupos', ]; private array $roleLabels = [ - 'fomento' => 'Fomento', - 'coord_fomento' => 'Coord. Fomento', - 'financeiro' => 'Financeiro', - 'coord_financeiro' => 'Coord. Financeiro', - 'juridico' => 'Jurídico', - 'coord_juridico' => 'Coord. Jurídico', - 'orcamentario' => 'Orçamentário', - 'coord_orcamentario' => 'Coord. Orçamentário', - 'monitoramento' => 'Monitoramento', - 'coord_monitoramento' => 'Coord. Monitoramento', - 'acompanhamento' => 'Acompanhamento', + 'fomentation' => 'Fomento', + 'coord_fomentation' => 'Coord. Fomento', + 'financial' => 'Financeiro', + 'coord_financial' => 'Coord. Financeiro', + 'legal' => 'Jurídico', + 'coord_legal' => 'Coord. Jurídico', + 'budgetary' => 'Orçamentário', + 'coord_budgetary' => 'Coord. Orçamentário', + 'monitoring' => 'Monitoramento', + 'coord_monitoring' => 'Coord. Monitoramento', + 'tracking' => 'Acompanhamento', 'super_admin' => 'Super Admin', ]; @@ -50,6 +50,7 @@ class GroupController extends Controller ['key' => 'edit_any', 'label' => 'Editar outros'], ['key' => 'delete_own', 'label' => 'Excluir o próprio'], ['key' => 'delete_any', 'label' => 'Excluir outros'], + ['key'=> 'assign_supervisor', 'label' => 'Atribuir Supervisor'], ]; public function index() diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index e8b799b..0157358 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -7,15 +7,20 @@ use Inertia\Inertia; use Inertia\Response; use App\Models\Notice; +use App\Models\User; +use App\Models\Project; +use App\Models\OpeningSupervisor; use App\Enums\ProjectPhase; use App\Enums\InstrumentType; +use Illuminate\Support\Facades\DB; +use App\Services\ProjectSupervisorService; class ProjectController extends Controller { public function index(Request $request, Notice $notice) { $query = $notice->projects() - ->with(['agent', 'category', 'opening']) + ->with(['agent', 'category', 'opening', 'opening.supervisors']) ->withCount('openings') ->filterPhase($request->phase) ->search($request->search); @@ -30,7 +35,36 @@ public function index(Request $request, Notice $notice) 'title' => $phase->label(), 'total' => $phase->count($query), ]), + 'supervisors_available' => User::role(['monitoring', 'coord_monitoring']) + ->select('id', 'name') + ->get(), + ]); + } + + public function assignProjectSupervisor(Request $request, ProjectSupervisorService $service) + { + $data = $request->validate([ + 'selected_projects' => 'required|array', + 'selected_projects.*' => 'exists:projects,id', + + 'selected_supervisors' => 'required|array', + 'selected_supervisors.*' => 'exists:users,id', ]); + + try { + $service->assign( + $data['selected_projects'], + $data['selected_supervisors'] + ); + + return back()->with('success', 'Fiscais atribuídos com sucesso!'); + } catch (\Throwable $e) { + report($e); + + return back()->withErrors([ + 'message' => 'Erro ao atribuir fiscais. Tente novamente.', + ]); + } } } \ No newline at end of file diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index d942b69..a572f87 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Inertia\Middleware; +use Illuminate\Support\Facades\Route; class HandleInertiaRequests extends Middleware { @@ -35,6 +36,7 @@ public function share(Request $request): array 'user' => $request->user(), 'roles' => $request->user()?->getRoleNames() ?? [], 'permissions' => $request->user()?->getAllPermissions()->pluck('name') ?? [], + 'currentRoute' => Route::currentRouteName(), ], ]; } diff --git a/app/Models/Opening.php b/app/Models/Opening.php index b2d1714..3d8d043 100644 --- a/app/Models/Opening.php +++ b/app/Models/Opening.php @@ -13,6 +13,7 @@ use App\Enums\OpeningStatus; use OwenIt\Auditing\Auditable as AuditableTrait; use OwenIt\Auditing\Contracts\Auditable; +use Illuminate\Support\Facades\Auth; class Opening extends Model implements Auditable { use HasFactory, SoftDeletes, AuditableTrait, HasFiles; @@ -70,4 +71,25 @@ public function activeSupervisor(): HasOne ->where('is_active', true) ->latestOfMany('assigned_at'); } + + public function assignSupervisors(array|Collection $supervisorIds): void + { + OpeningSupervisor::where('opening_id', $this->id) + ->where('is_active', true) + ->update([ + 'is_active' => false, + 'removed_at' => now(), + ]); + + + foreach ($supervisorIds as $supervisorId) { + OpeningSupervisor::create([ + 'opening_id' => $this->id, + 'user_id' => $supervisorId, + 'assigned_by' => Auth::id(), + 'assigned_at' => now(), + 'is_active' => true, + ]); + } + } } diff --git a/app/Services/ProjectSupervisorService.php b/app/Services/ProjectSupervisorService.php new file mode 100644 index 0000000..6b4bfab --- /dev/null +++ b/app/Services/ProjectSupervisorService.php @@ -0,0 +1,25 @@ +whereIn('id', $projectIds) + ->get(); + + DB::transaction(function () use ($projects, $supervisorIds) { + foreach ($projects as $project) { + if (!$project->opening) { + throw new \Exception("Projeto {$project->id} não possui abertura."); + } + + $project->opening->assignSupervisors($supervisorIds); + } + }); + } +} \ No newline at end of file diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index afcca01..c30a1b5 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -13,366 +13,71 @@ class PermissionSeeder extends Seeder public function run(): void { - // 1. LIMPAR CACHE app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions(); - // 2. PERMISSIONS - $permissions = [ - // Vinculação Orçamentária - 'vinc_orc.view_own', - 'vinc_orc.view_any', - 'vinc_orc.create', - 'vinc_orc.edit_own', - 'vinc_orc.edit_any', - 'vinc_orc.delete_own', - 'vinc_orc.delete_any', - - // Termo Jurídico - 'termo_jur.view_own', - 'termo_jur.view_any', - 'termo_jur.create', - 'termo_jur.edit_own', - 'termo_jur.edit_any', - 'termo_jur.delete_own', - 'termo_jur.delete_any', - - // Extrato do Termo Jurídico - 'extrato_jur.view_own', - 'extrato_jur.view_any', - 'extrato_jur.create', - 'extrato_jur.edit_own', - 'extrato_jur.edit_any', - 'extrato_jur.delete_own', - 'extrato_jur.delete_any', - - // CI - 'ci.view_own', - 'ci.view_any', - 'ci.create', - 'ci.edit_own', - 'ci.edit_any', - 'ci.delete_own', - 'ci.delete_any', - - // Despacho - 'despacho.view_own', - 'despacho.view_any', - 'despacho.create', - 'despacho.edit_own', - 'despacho.edit_any', - 'despacho.delete_own', - 'despacho.delete_any', - - // Parecer Jurídico - 'parecer_jur.view_own', - 'parecer_jur.view_any', - 'parecer_jur.create', - 'parecer_jur.edit_own', - 'parecer_jur.edit_any', - 'parecer_jur.delete_own', - 'parecer_jur.delete_any', - - // Parecer Orçamentário - 'parecer_orc.view_own', - 'parecer_orc.view_any', - 'parecer_orc.create', - 'parecer_orc.edit_own', - 'parecer_orc.edit_any', - 'parecer_orc.delete_own', - 'parecer_orc.delete_any', - - // Abertura - 'abertura.view_own', - 'abertura.view_any', - 'abertura.create', - 'abertura.edit_own', - 'abertura.edit_any', - 'abertura.delete_own', - 'abertura.delete_any', - - // Análise Jurídica - 'analise_jur.view_own', - 'analise_jur.view_any', - 'analise_jur.create', - 'analise_jur.edit_own', - 'analise_jur.edit_any', - 'analise_jur.delete_own', - 'analise_jur.delete_any', - - // Formalização - 'formalizacao.view_own', - 'formalizacao.view_any', - 'formalizacao.create', - 'formalizacao.edit_own', - 'formalizacao.edit_any', - 'formalizacao.delete_own', - 'formalizacao.delete_any', - - // Orçamento e Parcelas - 'orcamento.view_own', - 'orcamento.view_any', - 'orcamento.create', - 'orcamento.edit_own', - 'orcamento.edit_any', - 'orcamento.delete_own', - 'orcamento.delete_any', - - // Pagamento Financeiro - 'pagamento.view_own', - 'pagamento.view_any', - 'pagamento.create', - 'pagamento.edit_own', - 'pagamento.edit_any', - 'pagamento.delete_own', - 'pagamento.delete_any', - - // Gerenciamento de Usuários - 'usuarios.create', - 'usuarios.edit_own', - 'usuarios.edit_any', - 'usuarios.delete_own', - 'usuarios.delete_any', + $modules = [ + 'budget_allocation', + 'legal_term', + 'term_summary', + 'ci', + 'dispatch', + 'legal_opinion', + 'budget_opinion', + 'opening', + 'legal', + 'formalization', + 'budget', + 'payment', + 'users', + 'groups', + ]; - // Gerenciamento de Grupos - 'grupos.create', - 'grupos.edit_own', - 'grupos.edit_any', - 'grupos.delete_own', - 'grupos.delete_any', + $actions = [ + 'create', + 'view_own', + 'view_any', + 'edit_own', + 'edit_any', + 'delete_own', + 'delete_any', + 'assign_supervisor', ]; - foreach ($permissions as $permission) { - Permission::firstOrCreate(['name' => $permission]); + // Criar permissions + foreach ($modules as $module) { + foreach ($actions as $action) { + Permission::firstOrCreate([ + 'name' => "{$module}.{$action}", + 'guard_name' => 'web', + ]); + } } - // 3. ROLES - $fomento = Role::firstOrCreate(['name' => 'fomento']); - $coordFomento = Role::firstOrCreate(['name' => 'coord_fomento']); - $financeiro = Role::firstOrCreate(['name' => 'financeiro']); - $coordFinanceiro = Role::firstOrCreate(['name' => 'coord_financeiro']); - $juridico = Role::firstOrCreate(['name' => 'juridico']); - $coordJuridico = Role::firstOrCreate(['name' => 'coord_juridico']); - $orcamentario = Role::firstOrCreate(['name' => 'orcamentario']); - $coordOrcamentario = Role::firstOrCreate(['name' => 'coord_orcamentario']); - $monitoramento = Role::firstOrCreate(['name' => 'monitoramento']); - $coordMonitoramento = Role::firstOrCreate(['name' => 'coord_monitoramento']); - $acompanhamento = Role::firstOrCreate(['name' => 'acompanhamento']); - $superAdmin = Role::firstOrCreate(['name' => 'super_admin']); - - // 4. ASSOCIAÇÕES - - // fomento — Abertura (próprios) - $fomento->givePermissionTo([ - 'abertura.view_own', - 'abertura.create', - 'abertura.edit_own', - 'abertura.delete_own', - ]); - - // coord_fomento — Abertura (todos) - $coordFomento->givePermissionTo([ - 'abertura.view_own', - 'abertura.view_any', - 'abertura.create', - 'abertura.edit_own', - 'abertura.edit_any', - 'abertura.delete_own', - 'abertura.delete_any', - ]); - - // financeiro — Pagamento (próprios) - $financeiro->givePermissionTo([ - 'pagamento.view_own', - 'pagamento.create', - 'pagamento.edit_own', - 'pagamento.delete_own', - ]); - - // coord_financeiro — Pagamento (todos) - $coordFinanceiro->givePermissionTo([ - 'pagamento.view_own', - 'pagamento.view_any', - 'pagamento.create', - 'pagamento.edit_own', - 'pagamento.edit_any', - 'pagamento.delete_own', - 'pagamento.delete_any', - ]); - - // juridico — módulos jurídicos (próprios) - $juridico->givePermissionTo([ - 'termo_jur.view_own', - 'termo_jur.create', - 'termo_jur.edit_own', - 'termo_jur.delete_own', - - 'extrato_jur.view_own', - 'extrato_jur.create', - 'extrato_jur.edit_own', - 'extrato_jur.delete_own', - - 'ci.view_own', - 'ci.create', - 'ci.edit_own', - 'ci.delete_own', - - 'despacho.view_own', - 'despacho.create', - 'despacho.edit_own', - 'despacho.delete_own', - - 'parecer_jur.view_own', - 'parecer_jur.create', - 'parecer_jur.edit_own', - 'parecer_jur.delete_own', - - 'analise_jur.view_own', - 'analise_jur.create', - 'analise_jur.edit_own', - 'analise_jur.delete_own', - - 'formalizacao.view_own', - 'formalizacao.create', - 'formalizacao.edit_own', - 'formalizacao.delete_own', - ]); - - // coord_juridico — módulos jurídicos (todos) - $coordJuridico->givePermissionTo([ - 'termo_jur.view_own', - 'termo_jur.view_any', - 'termo_jur.create', - 'termo_jur.edit_own', - 'termo_jur.edit_any', - 'termo_jur.delete_own', - 'termo_jur.delete_any', - - 'extrato_jur.view_own', - 'extrato_jur.view_any', - 'extrato_jur.create', - 'extrato_jur.edit_own', - 'extrato_jur.edit_any', - 'extrato_jur.delete_own', - 'extrato_jur.delete_any', - - 'ci.view_own', - 'ci.view_any', - 'ci.create', - 'ci.edit_own', - 'ci.edit_any', - 'ci.delete_own', - 'ci.delete_any', - - 'despacho.view_own', - 'despacho.view_any', - 'despacho.create', - 'despacho.edit_own', - 'despacho.edit_any', - 'despacho.delete_own', - 'despacho.delete_any', - - 'parecer_jur.view_own', - 'parecer_jur.view_any', - 'parecer_jur.create', - 'parecer_jur.edit_own', - 'parecer_jur.edit_any', - 'parecer_jur.delete_own', - 'parecer_jur.delete_any', - - 'analise_jur.view_own', - 'analise_jur.view_any', - 'analise_jur.create', - 'analise_jur.edit_own', - 'analise_jur.edit_any', - 'analise_jur.delete_own', - 'analise_jur.delete_any', - - 'formalizacao.view_own', - 'formalizacao.view_any', - 'formalizacao.create', - 'formalizacao.edit_own', - 'formalizacao.edit_any', - 'formalizacao.delete_own', - 'formalizacao.delete_any', - ]); - - // orcamentario — módulos orçamentários (próprios) - $orcamentario->givePermissionTo([ - 'vinc_orc.view_own', - 'vinc_orc.create', - 'vinc_orc.edit_own', - 'vinc_orc.delete_own', - - 'despacho.view_own', - 'despacho.create', - 'despacho.edit_own', - 'despacho.delete_own', - - 'parecer_orc.view_own', - 'parecer_orc.create', - 'parecer_orc.edit_own', - 'parecer_orc.delete_own', - - 'orcamento.view_own', - 'orcamento.create', - 'orcamento.edit_own', - 'orcamento.delete_own', - ]); - - // coord_orcamentario — módulos orçamentários (todos) - $coordOrcamentario->givePermissionTo([ - 'vinc_orc.view_own', - 'vinc_orc.view_any', - 'vinc_orc.create', - 'vinc_orc.edit_own', - 'vinc_orc.edit_any', - 'vinc_orc.delete_own', - 'vinc_orc.delete_any', - - 'despacho.view_own', - 'despacho.view_any', - 'despacho.create', - 'despacho.edit_own', - 'despacho.edit_any', - 'despacho.delete_own', - 'despacho.delete_any', - - 'parecer_orc.view_own', - 'parecer_orc.view_any', - 'parecer_orc.create', - 'parecer_orc.edit_own', - 'parecer_orc.edit_any', - 'parecer_orc.delete_own', - 'parecer_orc.delete_any', - - 'orcamento.view_own', - 'orcamento.view_any', - 'orcamento.create', - 'orcamento.edit_own', - 'orcamento.edit_any', - 'orcamento.delete_own', - 'orcamento.delete_any', - ]); - - // monitoramento — sem permissões definidas - // coord_monitoramento — sem permissões definidas + // Criar roles + $roles = [ + 'fomentation', + 'coord_fomentation', + 'financial', + 'coord_financial', + 'legal', + 'coord_legal', + 'budgetary', + 'coord_budgetary', + 'monitoring', + 'coord_monitoring', + 'tracking', + 'super_admin', + ]; - // acompanhamento — view_any em todos os módulos (exceto usuários e grupos) - $acompanhamento->givePermissionTo([ - 'termo_jur.view_any', - 'extrato_jur.view_any', - 'ci.view_any', - 'despacho.view_any', - 'parecer_jur.view_any', - 'parecer_orc.view_any', - 'abertura.view_any', - 'analise_jur.view_any', - 'formalizacao.view_any', - 'orcamento.view_any', - 'pagamento.view_any', - ]); + foreach ($roles as $roleName) { + Role::firstOrCreate([ + 'name' => $roleName, + 'guard_name' => 'web', + ]); + } - // super_admin — todas as permissões - $superAdmin->givePermissionTo(Permission::all()); + // Super Admin = tudo + Role::findByName('super_admin') + ->syncPermissions(Permission::all()); } } diff --git a/resources/js/Components/ListDataTable.vue b/resources/js/Components/ListDataTable.vue index 3ff873b..8bfa337 100644 --- a/resources/js/Components/ListDataTable.vue +++ b/resources/js/Components/ListDataTable.vue @@ -34,6 +34,11 @@ const props = defineProps({ selectable: { type: Boolean, default: false }, + isSelectable: { + type: Function, + default: () => true, + }, + modelValue: { type: Array, default: () => [], @@ -48,6 +53,8 @@ const selected = computed({ }) function toggle(item) { + if (!props.isSelectable(item)) return + const exists = selected.value.includes(item.id) if (exists) { @@ -72,7 +79,7 @@ function runAction(action, item) { rounded="lg" variant="outlined">
Criar comunicação interna (CI)
+Atribuir fiscal aos selecionados
+Um ou mais projetos selecionados já possuem um fiscal. Ao atribuir um novo fiscal, o anterior será desativado.
+Conferir histórico de alterações nos processos
+