Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion app/Http/Controllers/GraduacaoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ public function relatorioTurma(Request $request)

public function relatorioCargaExtensao(Request $request)
{
$this->authorize('disciplinas');
$this->authorize('ver-relatorio');
\UspTheme::activeUrl('graduacao/relatorio/carga-extensao');

$cursos = Evasao::retornarCodcurNomcur();
Expand Down Expand Up @@ -632,4 +632,84 @@ public function relatorioCargaExtensao(Request $request)
'params' => $request->all()
]);
}

public function relatorioCargaHorariaCumpridaAluno(Request $request)
{
if (!$request->old()) {
session()->flashInput($request->input());
}

$this->authorize('ver-relatorio');
\UspTheme::activeUrl('graduacao/relatorio/carga-alunos');

$entradas = Tools::limparNomes($request->nusps);

$codpesParaProcessar = [];
$naoEncontrados = [];
$resultados = [];

foreach ($entradas as $entrada) {
if (is_numeric($entrada)) {
$codpesParaProcessar[] = $entrada;
} else {
$pessoas = Pessoa::procurarPorNome($entrada);

if (!empty($pessoas)) {
foreach ($pessoas as $pessoa) {
$codpesParaProcessar[] = $pessoa['codpes'];
}
} else {
$naoEncontrados[] = $entrada;
}
}
}

$codpesParaProcessar = array_unique($codpesParaProcessar);

$nomesEncontrados = [];

if (!empty($codpesParaProcessar)) {
$nomesEncontrados = Pessoa::obterNome($codpesParaProcessar);
}

foreach ($codpesParaProcessar as $codpes) {
$nome = $nomesEncontrados[$codpes] ?? null;

if (!$nome) {
$naoEncontrados[] = $codpes . " (Número USP não encontrado na base)";
continue;
}

$dadosAluno = Graduacao::obterCargaHorariaCumpridaAluno($codpes);

if (!$dadosAluno) {
$naoEncontrados[] = $codpes . " - " . ($nome ?: 'Nº USP inválido') . " (Sem histórico de aprovações)";
continue;
}

$cursoInfo = Graduacao::obterCurso($dadosAluno['codcur'], $dadosAluno['codhab']);

$cargaExigida = ($cursoInfo['cgahortot'] ?? 0) + ($cursoInfo['cgahorobgaac'] ?? 0);
$cumprida = $dadosAluno['carga_horaria_total_cumprida'];

$porcentagem = ($cargaExigida > 0) ? ($cumprida / $cargaExigida) * 100 : 0;

$resultados[] = [
'codpes' => $dadosAluno['codpes'],
'nompes' => $dadosAluno['nompes'],
'email' => $dadosAluno['email'],
'curso' => $dadosAluno['codcur'] . " - " . ($cursoInfo['nomcur'] ?? 'Não encontrado'),
'habilitacao' => $dadosAluno['codhab'] . " - " . ($cursoInfo['nomhab'] ?? 'Não encontrada'),
'ano' => $dadosAluno['ano_ingresso'],
'exigida' => $cargaExigida,
'cumprida' => round($cumprida),
'porcentagem' => number_format($porcentagem, 2, ',', '.')
];
}

$resultados = collect($resultados)->sortBy('nompes')->toArray();

session()->flashInput($request->input());
return view('grad.relatorio-carga-alunos', compact('resultados', 'naoEncontrados'));
}
}
4 changes: 4 additions & 0 deletions app/Providers/AuthServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,9 @@ public function boot()
|| Gate::check('senhaunica.estagiario')
|| Gate::check('senhaunica.docente');
});

Gate::define('ver-relatorio', function (User $user) {
return Gate::allows('disciplina-cc') || Gate::allows('datagrad');
});
}
}
51 changes: 51 additions & 0 deletions app/Replicado/Graduacao.php
Original file line number Diff line number Diff line change
Expand Up @@ -1022,4 +1022,55 @@ public static function listarCargaHorariaExtensionista($codcur, $anoIngresso)
$ret = DB::fetchAll($query, $params);
return $ret;
}

/**
* Método para obter os dados acadêmicos e a carga horária total
* cumprida em disciplinas por um aluno.
*
* @param Int $codpes
* @return Array Lista com codpes, nome, email, cod_curso, cod_habilitação, ano_ingresso, carga_horaria_total_cumprida ou false se não encontrado.
* @author Vinicius Rafael do Vale, em 15/05/2026
*/
public static function obterCargaHorariaCumpridaAluno($codpes)
{
$query = "
SELECT
v.codpes,
v.nompes,
e.codema AS email,
v.codcurgrd AS codcur,
v.codhab AS codhab,
YEAR(v.dtainivin) AS ano_ingresso,
SUM(
(ISNULL(d.creaul, 0) * 15) +
(ISNULL(d.cretrb, 0) * 30)
) AS carga_horaria_total_cumprida
FROM VINCULOPESSOAUSP v
INNER JOIN HISTESCOLARGR h ON h.codpes = v.codpes
INNER JOIN DISCIPLINAGR d ON d.coddis = h.coddis
LEFT JOIN EMAILPESSOA e ON e.codpes = v.codpes AND e.stamtr = 'S'
WHERE v.codpes = :codpes
AND v.tipvin = 'ALUNOGR'
AND v.sitatl = 'A'
AND h.rstfim IS NOT NULL
AND h.rstfim = 'A'
AND h.stamtr NOT IN ('E', 'R')
AND h.discrl IN ('O', 'L')
AND d.dtaatvdis <= ISNULL(h.dtavalfim, h.dtacrihst)
AND (
d.dtadtvdis IS NULL
OR ISNULL(h.dtavalfim, h.dtacrihst) <= d.dtadtvdis
)
GROUP BY
YEAR(v.dtainivin),
v.codpes,
v.codcurgrd,
v.codhab,
v.nompes,
e.codema
";

$param = ['codpes' => $codpes];
return DB::fetch($query, $param);
}
}
7 changes: 6 additions & 1 deletion config/laravel-usp-theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
[
'text' => 'Relatório carga extensionista',
'url' => 'graduacao/relatorio/carga-extensao',
'can' => 'disciplinas',
'can' => 'ver-relatorio',
],
[
'text' => 'Relatório carga horária cumprida por aluno',
'url' => 'graduacao/relatorio/carga-alunos',
'can' => 'ver-relatorio',
],
[
'text' => 'Relatório de evasão',
Expand Down
76 changes: 76 additions & 0 deletions resources/views/grad/relatorio-carga-alunos.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@extends('layouts.app')

@section('content')
<h4>Relatório carga horária cumprida por aluno</h4>
<div>
Lista a carga horária cumprida pelo aluno, juntamente com a porcentagem.
</div>

<form method="POST" action="">
@csrf
<div class="form-group">
<label for="nuspsTextarea">Forneça uma lista que contenha nomes ou números USP (1 por linha)</label>
<textarea name="nusps" class="form-control" id="nuspsTextarea" rows="4">{{ old('nusps') }}</textarea>
</div>
<button type="submit" class="btn btn-sm btn-primary spinner mt-3">Enviar</button>
</form>

@if($naoEncontrados)
<div class="alert alert-warning mt-3">
<b>Não encontrados:</b>
<ul>
@foreach($naoEncontrados as $item)
<li>{{ $item }}</li>
@endforeach
</ul>
</div>
@endif

@if($resultados)
<hr>
<div class="h4 mt-3">Resultados</div>
<table class="table table-bordered mt-3 table-hover datatable-simples dt-buttons dt-fixed-header">
<thead class="thead-light">
<tr>
<th>Nº USP</th>
<th>Nome</th>
<th>E-mail</th>
<th>Curso</th>
<th>Complemento</th>
<th>Ingresso</th>
<th>Carga Exigida</th>
<th>Carga Cumprida</th>
<th>% Progresso</th>
</tr>
</thead>
<tbody>
@foreach($resultados as $r)
<tr>
<td>{{ $r['codpes'] }}</td>
<td>{{ $r['nompes'] }}</td>
<td>{{ $r['email'] }}</td>
<td>{{ $r['curso'] }}</td>
<td>{{ $r['habilitacao'] }}</td>
<td>{{ $r['ano'] }}</td>
<td>{{ $r['exigida'] }} h</td>
<td>{{ $r['cumprida'] }} h</td>
<td>
<div class="progress" style="height: 25px; background-color: #e9ecef; position: relative;">
<div class="progress-bar" role="progressbar"
style="width: {{ str_replace(',', '.', $r['porcentagem']) }}%; background-color: #56a5ccc1;"
aria-valuenow="{{ str_replace(',', '.', $r['porcentagem']) }}"
aria-valuemin="0"
aria-valuemax="100">
</div>

<div style="position: absolute; width: 100%; text-align: center; line-height: 25px; color: black; font-weight: bold; font-size: 1rem;">
{{ $r['porcentagem'] }}%
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
@endsection
1 change: 1 addition & 0 deletions resources/views/welcome.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
- <b>Relatório de carga didática</b>: mostra a carga didática de docentes em determinado período;<br>
- <b>Relatório grade horária</b>: mostra a grade horária corrente para a lista de alunos informada;<br>
- <b>Relatório carga de extensão</b>: mostra por curso e por ano de ingresso a relação de alunos e o total de carga extensionista cumprida por cada um;<br>
- <b>Relatório carga horária cumprida por aluno</b>: mostra a carga horária cumprida pelo aluno e a porcentagem com base na carga exigida pelo curso;<br>
- <b>Relatório de evasão</b>: mostra gráfico e tabela de evasão por curso e por ano de ingresso;<br>
- <b>Alteração de ementas de disicplinas</b>: Ferramenta que facilita a atualização das ementas das disciplinas.<br>
</div>
Expand Down
5 changes: 4 additions & 1 deletion routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,7 @@
Route::resource('/cursos', CursoController::class);

Route::get('graduacao/relatorio/carga-extensao', [GraduacaoController::class, 'relatorioCargaExtensao'])->name('graduacao.relatorio.carga-extensao');
Route::post('graduacao/relatorio/carga-extensao', [GraduacaoController::class, 'relatorioCargaExtensao'])->name('graduacao.relatorio.carga-extensao.post');
Route::post('graduacao/relatorio/carga-extensao', [GraduacaoController::class, 'relatorioCargaExtensao'])->name('graduacao.relatorio.carga-extensao.post');

Route::get('graduacao/relatorio/carga-alunos', [GraduacaoController::class, 'relatorioCargaHorariaCumpridaAluno'])->name('graduacao.relatorio.carga-alunos');
Route::post('graduacao/relatorio/carga-alunos', [GraduacaoController::class, 'relatorioCargaHorariaCumpridaAluno'])->name('graduacao.relatorio.carga-alunos.post');