diff --git a/.env.example b/.env.example index 00044c6..10958ce 100644 --- a/.env.example +++ b/.env.example @@ -167,3 +167,13 @@ WSFOTO_PASS= # Caminho para o arquivo de imagem desejada para ser utilizada # como a foto fake WS_FOTO_FAKE_PATH= + + + +# Configurações específicas da aplicação ################################ + +# Define quais códigos de habilitação serão considerados pela aplicação. +# Na EESC somente as com codhab = 0, default +CODHABS=0 +# Na ECA são consideradas as com codhab terminando em 0, 2 e 4 +# CODHABS=0,2,4 \ No newline at end of file diff --git a/app/Http/Controllers/EquivalenciaController.php b/app/Http/Controllers/EquivalenciaController.php index fc5a872..ec3a391 100644 --- a/app/Http/Controllers/EquivalenciaController.php +++ b/app/Http/Controllers/EquivalenciaController.php @@ -5,19 +5,55 @@ use App\Http\Requests\StoreEquivalenciaRequest; use App\Http\Requests\UpdateEquivalenciaRequest; use App\Models\Equivalencia; -use Symfony\Component\HttpFoundation\Request; +use App\Replicado\Graduacao; +use Illuminate\Http\Request; use Uspdev\Forms\Form; -use Uspdev\Replicado\Graduacao; class EquivalenciaController extends Controller { + public function __construct() + { + // Adiciona o middleware para marcar a URL ativa no menu da aplicação, utilizando o pacote Uspdev/Theme. + $this->middleware(function ($request, $next) { + \UspTheme::activeUrl('equivalencias'); + + return $next($request); + }); + } + /** - * Display a listing of the resource. + * Lista os cursos e habilitações disponíveis para cadastro de equivalências. + * Cada curso/habilitação é um link que leva para a página de disciplinas + * USP equivalentes cadastradas para aquele curso/habilitação. */ - public function index() + public function cursos() { + $cursos = Graduacao::listarCursosHabilitacoes(); + + return view('equivalencias.cursos', [ + 'cursos' => $cursos, + ]); + } + + /** + * Exibe a lista de disciplinas USP equivalentes para um curso/habilitação específico. + * Pega o codcur e codhab da rota, + * busca as disciplinas USP equivalentes cadastradas para esse curso/habilitação, + * e retorna para a view. A view é responsável por exibir as disciplinas USP + * e os formulários para criar/editar as disciplinas USP e adicionar/remover equivalências. + */ + public function index(int $codcur, int $codhab) + { + + $curso = collect(Graduacao::listarCursosHabilitacoes()) + ->first(fn ($item) => (int) $item['codcur'] === $codcur && (int) $item['codhab'] === $codhab); + + abort_unless($curso, 404); + $disciplinas = Equivalencia::query() ->usp() + ->where('codcur', $codcur) + ->where('codhab', $codhab) ->with(['equivalentes' => function ($query) { $query->orderBy('coddis'); }]) @@ -26,9 +62,12 @@ public function index() return view('equivalencias.index', [ 'disciplinas' => $disciplinas, + 'codcur' => $codcur, + 'codhab' => $codhab, + 'nomeCurso' => $curso['nomcur'], 'formHtmlCreate' => $this->buildFormHtml( 'eq_usp_create', - route('equivalencias.store'), + route('equivalencias.store', ['codcur' => $codcur, 'codhab' => $codhab]), 'POST', $this->oldInputForFields(['coddis']) ), @@ -36,28 +75,38 @@ public function index() } /** - * Store a newly created resource in storage. + * Armazena uma nova disciplina USP equivalente para um curso/habilitação específico. + * Pega o codcur e codhab da rota, valida os dados do formulário utilizando a StoreEquivalenciaRequest, + * preenche os dados da disciplina USP com as informações do Replicado */ - public function store(StoreEquivalenciaRequest $request) + public function store(StoreEquivalenciaRequest $request, int $codcur, int $codhab) { $dados = $request->validated(); $dados['equivalencias_id'] = null; $dados['tipo'] = Equivalencia::TIPO_AUTOMATICA; + $dados['codcur'] = $codcur; + $dados['codhab'] = $codhab; $dados = $this->preencherDadosDisciplinaUsp($dados); $equivalencia = Equivalencia::create($dados); return redirect() - ->route('equivalencias.show', $equivalencia) + ->route('equivalencias.show', [$codcur, $codhab, $equivalencia]) ->with('alert-success', 'Disciplina USP criada com sucesso.'); } /** * Display the specified resource. */ - public function show(Equivalencia $equivalencia) + public function show(int $codcur, int $codhab, Equivalencia $equivalencia) { abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); + + $curso = collect(Graduacao::listarCursosHabilitacoes()) + ->first(fn ($item) => (int) $item['codcur'] === $codcur && (int) $item['codhab'] === $codhab); + + abort_unless($curso, 404); $equivalencia->load(['equivalentes' => function ($query) { $query->orderBy('coddis'); @@ -66,93 +115,149 @@ public function show(Equivalencia $equivalencia) return view('equivalencias.show', [ 'disciplina' => $equivalencia, 'equivalencias' => $equivalencia->equivalentes, - 'formHtmlEdit' => $this->addHiddenModalField( - $this->buildFormHtml( - 'eq_usp_edit', - route('equivalencias.update', $equivalencia), - 'PUT', - $this->oldInputForFields( - ['coddis'], - ['coddis' => $equivalencia->coddis] - ) - ), - 'equivalencia-edit' + 'nomeCurso' => $curso['nomcur'], + 'formHtmlEdit' => $this->buildFormHtml( + 'eq_usp_edit', + route('equivalencias.update', [$codcur, $codhab, $equivalencia]), + 'PUT', + $this->oldInputForFields( + ['coddis'], + ['coddis' => $equivalencia->coddis] + ) ), 'formHtmlEquivalencia' => $this->buildFormHtml( 'eq_child_add', - route('equivalencias.add-equivalencia', $equivalencia), + route('equivalencias.add-equivalencia', [$codcur, $codhab, $equivalencia]), 'POST', $this->oldInputForFields([ 'coddis', 'nome_disciplina', 'ies', - 'creditos', - 'carga_horaria', ]) ), + 'formHtmlEquivalenciaEdit' => $equivalencia->equivalentes + ->mapWithKeys(function (Equivalencia $equivalenciaFilha) use ($codcur, $codhab, $equivalencia) { + return [ + $equivalenciaFilha->id => $this->buildFormHtml( + 'eq_child_add', + route('equivalencias.update-equivalencia', [$codcur, $codhab, $equivalencia, $equivalenciaFilha]), + 'PUT', + [ + 'coddis' => $equivalenciaFilha->coddis, + 'nome_disciplina' => $equivalenciaFilha->nome_disciplina, + 'ies' => $equivalenciaFilha->ies, + ] + ), + ]; + }) + ->all(), + 'codcur' => $codcur, + 'codhab' => $codhab, ]); } /** * Update the specified resource in storage. */ - public function update(UpdateEquivalenciaRequest $request, Equivalencia $equivalencia) + public function update(UpdateEquivalenciaRequest $request, int $codcur, int $codhab, Equivalencia $equivalencia) { abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); $dados = $request->validated(); $dados['tipo'] = Equivalencia::TIPO_AUTOMATICA; + $dados['codcur'] = $codcur; + $dados['codhab'] = $codhab; $dados = $this->preencherDadosDisciplinaUsp($dados, $equivalencia->coddis); $equivalencia->update($dados); return redirect() - ->route('equivalencias.show', $equivalencia) + ->route('equivalencias.show', [$codcur, $codhab, $equivalencia]) ->with('alert-success', 'Disciplina USP atualizada com sucesso.'); } /** - * Remove the specified resource from storage. + * Deleta a disciplina USP, o que também deleta as equivalências + filhas devido à relação de chave estrangeira com cascade on delete */ - public function destroy(Equivalencia $equivalencia) + public function destroy(int $codcur, int $codhab, Equivalencia $equivalencia) { abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); $equivalencia->delete(); return redirect() - ->route('equivalencias.index') + ->route('equivalencias.curso', [$codcur, $codhab]) ->with('alert-success', 'Disciplina USP removida com sucesso.'); } - public function addEquivalencia(Request $request, Equivalencia $equivalencia) + /** + * Adiciona uma nova disciplina equivalente (filha) para uma disciplina USP (pai). + * Pega o codcur, codhab e a disciplina USP (pai) da rota + */ + public function addEquivalencia(Request $request, int $codcur, int $codhab, Equivalencia $equivalencia) { abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); $request['equivalencias_id'] = $equivalencia->id; $request['tipo'] = Equivalencia::TIPO_CURSADA; + $request['codcur'] = $codcur; + $request['codhab'] = $codhab; Equivalencia::create($request->all()); return redirect() - ->route('equivalencias.show', $equivalencia) + ->route('equivalencias.show', [$codcur, $codhab, $equivalencia]) ->with('alert-success', 'Equivalência adicionada com sucesso.'); } - public function destroyEquivalencia(Equivalencia $equivalencia, Equivalencia $equivalenciaFilha) + /** + * Atualiza uma disciplina equivalente (filha) de uma disciplina USP (pai). + */ + public function updateEquivalencia(Request $request, int $codcur, int $codhab, Equivalencia $equivalencia, Equivalencia $equivalenciaFilha) { abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); + abort_unless($equivalenciaFilha->isEquivalencia(), 404); + abort_unless($equivalenciaFilha->equivalencias_id === $equivalencia->id, 404); + + $dados = $request->all(); + + $dados['equivalencias_id'] = $equivalencia->id; + $dados['tipo'] = Equivalencia::TIPO_CURSADA; + $dados['codcur'] = $codcur; + $dados['codhab'] = $codhab; + + $equivalenciaFilha->update($dados); + + return redirect() + ->route('equivalencias.show', [$codcur, $codhab, $equivalencia]) + ->with('alert-success', 'Equivalência atualizada com sucesso.'); + } + + /** + * Remove uma disciplina equivalente (filha) de uma disciplina USP (pai). + */ + public function destroyEquivalencia(int $codcur, int $codhab, Equivalencia $equivalencia, Equivalencia $equivalenciaFilha) + { + abort_unless($equivalencia->isUsp(), 404); + abort_unless($this->equivalenciaPertenceAoCurso($equivalencia, $codcur, $codhab), 404); abort_unless($equivalenciaFilha->equivalencias_id === $equivalencia->id, 404); $equivalenciaFilha->delete(); return redirect() - ->route('equivalencias.show', $equivalencia) + ->route('equivalencias.show', [$codcur, $codhab, $equivalencia]) ->with('alert-success', 'Equivalência removida com sucesso.'); } - // Cria um formulário HTML para as views, utilizando a classe Form do pacote Uspdev/Forms. + /** + * Cria o HTML do formulário utilizando o pacote Uspdev/Forms + */ private function buildFormHtml(string $name, string $action, string $method, array $values): string { $form = new Form([ @@ -198,17 +303,20 @@ private function preencherDadosDisciplinaUsp(array $dados, ?string $coddisAtual $dados['creditos'] = $disciplina['creaul'] ?? $dados['creditos'] ?? null; $dados['carga_horaria'] = $disciplina['numhor'] ?? $dados['carga_horaria'] ?? null; $dados['nomcur'] = $disciplina['nomcur'] ?? $dados['nomcur'] ?? null; - $dados['codcur'] = $disciplina['codcur'] ?? $dados['codcur'] ?? null; - $dados['codhab'] = $disciplina['codhab'] ?? $dados['codhab'] ?? null; + $dados['codcur'] = $dados['codcur'] ?? $disciplina['codcur'] ?? null; + $dados['codhab'] = $dados['codhab'] ?? $disciplina['codhab'] ?? null; return $dados; } - private function addHiddenModalField(string $formHtml, string $value): string + // Verifica se a disciplina USP (equivalencia) pertence ao curso e habilitação especificados pelos códigos codcur e codhab. + private function equivalenciaPertenceAoCurso(Equivalencia $equivalencia, int $codcur, int $codhab): bool { - return str_replace('', '', $formHtml); + return (int) $equivalencia->codcur === $codcur + && (int) $equivalencia->codhab === $codhab; } + // Busca os dados da disciplina no Replicado a partir do código da disciplina (coddis). private function buscarDisciplinaNoReplicado(?string $coddis): ?array { if (! $coddis) { diff --git a/app/Http/Requests/StoreEquivalenciaRequest.php b/app/Http/Requests/StoreEquivalenciaRequest.php index ef7fb43..d1a7923 100644 --- a/app/Http/Requests/StoreEquivalenciaRequest.php +++ b/app/Http/Requests/StoreEquivalenciaRequest.php @@ -22,9 +22,16 @@ public function authorize(): bool */ public function rules(): array { + // Obter os parâmetros da rota + $codcur = (int) $this->route('codcur'); + $codhab = (int) $this->route('codhab'); + return [ 'coddis' => [ - Rule::unique('equivalencias')->whereNull('equivalencias_id'), + Rule::unique('equivalencias') + ->whereNull('equivalencias_id') + ->where('codcur', $codcur) + ->where('codhab', $codhab), ], ]; diff --git a/app/Http/Requests/UpdateEquivalenciaRequest.php b/app/Http/Requests/UpdateEquivalenciaRequest.php index ecaa3e6..d479faa 100644 --- a/app/Http/Requests/UpdateEquivalenciaRequest.php +++ b/app/Http/Requests/UpdateEquivalenciaRequest.php @@ -27,12 +27,16 @@ public function rules(): array $equivalenciaId = $equivalencia instanceof Equivalencia ? $equivalencia->id : $equivalencia; + // Obter os parâmetros da rota + $codcur = (int) $this->route('codcur'); + $codhab = (int) $this->route('codhab'); return [ 'coddis' => [ - 'sometimes', Rule::unique('equivalencias') ->whereNull('equivalencias_id') + ->where('codcur', $codcur) + ->where('codhab', $codhab) ->ignore($equivalenciaId), ], ]; diff --git a/app/Replicado/Graduacao.php b/app/Replicado/Graduacao.php new file mode 100644 index 0000000..9dfb705 --- /dev/null +++ b/app/Replicado/Graduacao.php @@ -0,0 +1,45 @@ + explode(',', env('CODHABS', 0)), +]; diff --git a/database/seeders/FormDefinitionsTableSeeder.php b/database/seeders/FormDefinitionsTableSeeder.php index 835efdd..2a82b74 100644 --- a/database/seeders/FormDefinitionsTableSeeder.php +++ b/database/seeders/FormDefinitionsTableSeeder.php @@ -33,7 +33,7 @@ public function run() [21, 'tr_finalizar_enviar', 'equivalencia', null, '[{"name":"obs","type":"texttextarea","label":"Observações sobre finalização","required":false},{"name":"definition_name","type":"hidden","value":"workflowDefinitionName"},{"name":"place","type":"hidden","value":"place_name"},{"name":"transition","type":"hidden","value":"transition_name"}]', '2025-03-17 19:33:49', '2025-03-17 19:33:49'], [22, 'eq_usp_create', 'equivalencia-crud', 'Cadastro de disciplina USP', '[[{"name":"coddis","type":"disciplina-usp","label":"Código da disciplina","required":true}]]', '2025-03-17 19:33:49', '2025-03-17 19:33:49'], [23, 'eq_usp_edit', 'equivalencia-crud', 'Edição de disciplina USP', '[[{"name":"coddis","type":"disciplina-usp","label":"Código da disciplina","required":true}]]', '2025-03-17 19:33:49', '2025-03-17 19:33:49'], - [24, 'eq_child_add', 'equivalencia-crud', 'Cadastro de equivalência', '[[{"name":"coddis","type":"text","label":"Código","maxlength":"7","width":3,"required":true},{"name":"nome_disciplina","type":"text","label":"Nome da equivalência","maxlength":"240","required":true}],[{"name":"ies","type":"text","label":"IES","maxlength":"255","required":true}],[{"name":"creditos","type":"number","label":"Créditos","min":0,"max":20,"width":3,"required":true},{"name":"carga_horaria","type":"number","label":"Carga horária","min":0,"max":1000,"width":3,"required":true}]]', '2025-03-17 19:33:49', '2025-03-17 19:33:49'], + [24, 'eq_child_add', 'equivalencia-crud', 'Cadastro de equivalência', '[[{"name":"coddis","type":"text","label":"Código","maxlength":"7","width":3,"required":true},{"name":"nome_disciplina","type":"text","label":"Nome da equivalência","maxlength":"240","required":true}],[{"name":"ies","type":"text","label":"IES","maxlength":"255","required":true}]]', '2025-03-17 19:33:49', '2025-03-17 19:33:49'], ]; foreach ($formDefinitions as $formDefinition) { diff --git a/resources/views/equivalencias/cursos.blade.php b/resources/views/equivalencias/cursos.blade.php new file mode 100644 index 0000000..8405118 --- /dev/null +++ b/resources/views/equivalencias/cursos.blade.php @@ -0,0 +1,40 @@ +@extends('layouts.app') + +@section('content') +
+
+

Cursos

+
+ +
+
+ @if (empty($cursos)) +

Nenhum curso/habilitação ativo encontrado.

+ @else +
+ + + + + + + + + @foreach ($cursos as $curso) + + + + + + @endforeach + +
CursoHabilitação
+ + {{ $curso['nomcur'] ?? '-' }} ({{ $curso['codcur'] ?? '-' }}) + {{ $curso['nomhab'] ?? '-' }} ({{ $curso['codhab'] ?? '-' }})
+
+ @endif +
+
+
+@endsection diff --git a/resources/views/equivalencias/index.blade.php b/resources/views/equivalencias/index.blade.php index 5a898c9..5b2ba64 100644 --- a/resources/views/equivalencias/index.blade.php +++ b/resources/views/equivalencias/index.blade.php @@ -3,8 +3,10 @@ @section('content')
-

Equivalências Automáticas

- @include('equivalencias.partials.modal-create') + Cursos +
+

{{ $nomeCurso ?? $disciplinas->first()->nomcur ?? 'Curso' }} ({{ $codcur }}/{{ $codhab }})

+
@include('equivalencias.partials.modal-create')
@@ -18,19 +20,15 @@ Código Nome Verdis - Codcur - Codhab Equivalências @foreach ($disciplinas as $disciplina) - {{ $disciplina->coddis }} + {{ $disciplina->coddis }} {{ $disciplina->nome_disciplina ?: '-' }} {{ $disciplina->verdis ?: '-' }} - {{ $disciplina->codcur ?: '-' }} - {{ $disciplina->codhab ?: '-' }} @forelse ($disciplina->equivalentes as $equivalencia)
{{ $equivalencia->coddis ?: '-' }} - {{ $equivalencia->nome_disciplina ?: '-' }}
diff --git a/resources/views/equivalencias/partials/modal-edit-equivalencia.blade.php b/resources/views/equivalencias/partials/modal-edit-equivalencia.blade.php new file mode 100644 index 0000000..33939f9 --- /dev/null +++ b/resources/views/equivalencias/partials/modal-edit-equivalencia.blade.php @@ -0,0 +1,29 @@ + + + diff --git a/resources/views/equivalencias/partials/modal-edit.blade.php b/resources/views/equivalencias/partials/modal-edit.blade.php index 1d851b5..b9dc860 100644 --- a/resources/views/equivalencias/partials/modal-edit.blade.php +++ b/resources/views/equivalencias/partials/modal-edit.blade.php @@ -28,13 +28,3 @@
-@section('javascripts_bottom') - @parent - -@endsection diff --git a/resources/views/equivalencias/show.blade.php b/resources/views/equivalencias/show.blade.php index ef8dd25..ebe6a4d 100644 --- a/resources/views/equivalencias/show.blade.php +++ b/resources/views/equivalencias/show.blade.php @@ -3,7 +3,9 @@ @section('content')
@@ -15,25 +17,19 @@ - - + - - - - + - -
CódigoNomeDisciplina requerida VerdisCodcurCodhab Ações
{{ $disciplina->coddis ?: '-' }}{{ $disciplina->nome_disciplina ?: '-' }}({{ $disciplina->coddis ?: '-' }}) {{ $disciplina->nome_disciplina ?: '-' }} {{ $disciplina->verdis ?: '-' }}{{ $disciplina->codcur ?: '-' }}{{ $disciplina->codhab ?: '-' }}
@include('equivalencias.partials.modal-edit') -
+ @csrf @method('DELETE') @@ -62,11 +58,8 @@ - - + - - @@ -74,14 +67,12 @@ @foreach ($equivalencias as $equivalencia) - - + - -
CódigoNomeDisciplina equivalente IESCréditosCarga horária
{{ $equivalencia->coddis }}{{ $equivalencia->nome_disciplina ?: '-' }}({{ $equivalencia->coddis ?: '-' }}) {{ $equivalencia->nome_disciplina ?: '-' }} {{ $equivalencia->ies ?: '-' }}{{ $equivalencia->creditos ?: '-' }}{{ $equivalencia->carga_horaria ?: '-' }}
- + @include('equivalencias.partials.modal-edit-equivalencia') + @csrf @method('DELETE') diff --git a/routes/web.php b/routes/web.php index 7506b3a..3f9f6fc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,8 +1,8 @@ name('workflows.index'); Route::middleware(['auth'])->group(function () { - Route::resource('equivalencias', EquivalenciaController::class)->except(['create', 'edit']); - Route::post('/equivalencias/{equivalencia}/equivalencias', [EquivalenciaController::class, 'addEquivalencia']) + Route::get('/equivalencias', [EquivalenciaController::class, 'cursos']) + ->name('equivalencias.index'); + Route::get('/equivalencias/{codcur}/{codhab}', [EquivalenciaController::class, 'index']) + ->name('equivalencias.curso'); + Route::post('/equivalencias/{codcur}/{codhab}', [EquivalenciaController::class, 'store']) + ->name('equivalencias.store'); + Route::get('/equivalencias/{codcur}/{codhab}/{equivalencia}', [EquivalenciaController::class, 'show']) + ->name('equivalencias.show'); + Route::put('/equivalencias/{codcur}/{codhab}/{equivalencia}', [EquivalenciaController::class, 'update']) + ->name('equivalencias.update'); + Route::delete('/equivalencias/{codcur}/{codhab}/{equivalencia}', [EquivalenciaController::class, 'destroy']) + ->name('equivalencias.destroy'); + Route::post('/equivalencias/{codcur}/{codhab}/{equivalencia}/equivalencias', [EquivalenciaController::class, 'addEquivalencia']) ->name('equivalencias.add-equivalencia'); - Route::delete('/equivalencias/{equivalencia}/equivalencias/{equivalenciaFilha}', [EquivalenciaController::class, 'destroyEquivalencia']) + Route::put('/equivalencias/{codcur}/{codhab}/{equivalencia}/equivalencias/{equivalenciaFilha}', [EquivalenciaController::class, 'updateEquivalencia']) + ->name('equivalencias.update-equivalencia'); + Route::delete('/equivalencias/{codcur}/{codhab}/{equivalencia}/equivalencias/{equivalenciaFilha}', [EquivalenciaController::class, 'destroyEquivalencia']) ->name('equivalencias.destroy-equivalencia'); Route::get('/createdefinition', [WorkflowController::class, 'createDefinition'])->name('workflows.create-definition');