feat: initialize autocensup application
This commit is contained in:
commit
1e72e0239a
20
.env.example
Normal file
20
.env.example
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
DJANGO_DEBUG=True
|
||||||
|
DJANGO_SECRET_KEY=django-insecure-dev-only-change-me
|
||||||
|
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
|
||||||
|
|
||||||
|
POSTGRES_DB=autocensup
|
||||||
|
POSTGRES_USER=autocensup
|
||||||
|
POSTGRES_PASSWORD=autocensup
|
||||||
|
POSTGRES_HOST=localhost
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
GENNERA_API_BASE_URL=http://gennera.solucaoti.net.br
|
||||||
|
API_TOKEN=
|
||||||
|
GENNERA_LOCAL_AUTH_TOKEN=
|
||||||
|
CENSUP_IES_CODIGO=
|
||||||
|
|
||||||
|
CELERY_BROKER_URL=redis://localhost:6379/0
|
||||||
|
CELERY_RESULT_BACKEND=redis://localhost:6379/0
|
||||||
|
|
||||||
|
# Alternativa:
|
||||||
|
# DATABASE_URL=postgresql://autocensup:autocensup@localhost:5432/autocensup
|
||||||
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
|
|
||||||
|
# Local config
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Django
|
||||||
|
staticfiles/
|
||||||
|
media/
|
||||||
|
*.sqlite3
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
273
ESPECIFICACOES.md
Normal file
273
ESPECIFICACOES.md
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
# Especificacoes do Projeto Autocensup
|
||||||
|
|
||||||
|
## Visao geral
|
||||||
|
|
||||||
|
O Autocensup e uma aplicacao web Django para apoiar a preparacao, conferencia e processamento de dados do Censo da Educacao Superior. O sistema centraliza cadastros de pessoas, cursos, vinculos, instituicoes, polos e tabelas auxiliares, permitindo importar dados locais e da API Gennera, revisar pendencias e operar os registros por ano de censo.
|
||||||
|
|
||||||
|
## Objetivos
|
||||||
|
|
||||||
|
- Manter uma base local de dados necessarios ao Censo Superior.
|
||||||
|
- Importar pessoas e vinculos a partir da API Gennera.
|
||||||
|
- Importar o Arquivo Aluno exportado do sistema Censup.
|
||||||
|
- Conferir vinculos por curso, situacao e pendencias cadastrais.
|
||||||
|
- Permitir ajustes cadastrais via telas CRUD autenticadas.
|
||||||
|
- Processar situacoes de vinculos em lote por matricula.
|
||||||
|
|
||||||
|
## Stack tecnica
|
||||||
|
|
||||||
|
- Linguagem: Python 3.12+.
|
||||||
|
- Framework web: Django 5.2.
|
||||||
|
- Banco de dados: PostgreSQL 16.
|
||||||
|
- Driver PostgreSQL: psycopg 3.
|
||||||
|
- Gerenciador de dependencias: uv.
|
||||||
|
- Infra local: Docker Compose para o servico `db`.
|
||||||
|
- Templates: Django Templates com Bootstrap/Tabler.
|
||||||
|
- Autenticacao: autenticacao padrao do Django, com views protegidas por login.
|
||||||
|
|
||||||
|
## Configuracao de ambiente
|
||||||
|
|
||||||
|
Variaveis principais:
|
||||||
|
|
||||||
|
- `DJANGO_DEBUG`: habilita ou desabilita modo debug.
|
||||||
|
- `DJANGO_SECRET_KEY`: chave secreta da aplicacao.
|
||||||
|
- `DJANGO_ALLOWED_HOSTS`: hosts permitidos.
|
||||||
|
- `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_HOST`, `POSTGRES_PORT`: conexao PostgreSQL.
|
||||||
|
- `DATABASE_URL`: alternativa para configurar o banco por URL.
|
||||||
|
- `GENNERA_API_BASE_URL`: URL base da API Gennera.
|
||||||
|
- `API_TOKEN`: token Bearer usado nas chamadas a API Gennera.
|
||||||
|
|
||||||
|
Comandos basicos:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv sync
|
||||||
|
docker compose up -d db
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py migrate
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py loaddata ufs municipios
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
## Modulos principais
|
||||||
|
|
||||||
|
- `config/settings.py`: configuracao Django e leitura de variaveis de ambiente.
|
||||||
|
- `core/models.py`: modelos de dominio.
|
||||||
|
- `core/views.py`: dashboard, selecao de ano, importacoes, processamento em lote e CRUD generico.
|
||||||
|
- `core/importers.py`: importacao de arquivos, CSVs e API Gennera.
|
||||||
|
- `core/validation.py`: validacoes de curso, pessoa e vinculo.
|
||||||
|
- `core/year.py`: ano de censo selecionado na sessao.
|
||||||
|
- `templates/`: layout e telas da aplicacao.
|
||||||
|
- `docs/`: insumos e regras de leiaute do Censo Superior.
|
||||||
|
|
||||||
|
## Modelo de dados
|
||||||
|
|
||||||
|
### AnoCenso
|
||||||
|
|
||||||
|
Representa o ano de referencia do censo. O campo `ano` e chave primaria. A propriedade `ano_execucao` retorna `ano + 1`.
|
||||||
|
|
||||||
|
### UF, Pais e Municipio
|
||||||
|
|
||||||
|
Tabelas auxiliares usadas nos cadastros de pessoa. Municipio pertence a uma UF.
|
||||||
|
|
||||||
|
### Curso
|
||||||
|
|
||||||
|
Cadastro de cursos identificados por `codigo_mec`. Campos relevantes:
|
||||||
|
|
||||||
|
- descricao.
|
||||||
|
- situacao de funcionamento.
|
||||||
|
- indicador de licenciatura.
|
||||||
|
- indicador de EaD.
|
||||||
|
- carga horaria total.
|
||||||
|
- polo vinculado, quando aplicavel.
|
||||||
|
|
||||||
|
### FallbackCurso
|
||||||
|
|
||||||
|
Mapeia textos divergentes entre dados externos e cursos locais para uso cadastral/manual. A importacao de vinculos da API Gennera nao usa fallback por nome: o curso deve ser identificado exclusivamente por `course_code`.
|
||||||
|
|
||||||
|
### Instituicao e Polo
|
||||||
|
|
||||||
|
Representam instituicoes INEP e locais de oferta. Polos podem ser vinculados a cursos EaD.
|
||||||
|
|
||||||
|
### Pessoa
|
||||||
|
|
||||||
|
Cadastro do aluno/pessoa com CPF unico, dados de nascimento, nacionalidade, cor/raca, pais de origem, deficiencias, tipo de escola do ensino medio e anos de censo associados.
|
||||||
|
|
||||||
|
### Vinculo
|
||||||
|
|
||||||
|
Relaciona pessoa, curso e ano de censo. Regras estruturais:
|
||||||
|
|
||||||
|
- `ano_censo` referencia `AnoCenso`.
|
||||||
|
- `curso` referencia `Curso.codigo_mec`.
|
||||||
|
- uma pessoa pode ter apenas um vinculo para o mesmo curso no mesmo ano de censo.
|
||||||
|
- uma pessoa pode ter mais de um vinculo no mesmo ano de censo quando os cursos forem diferentes.
|
||||||
|
- a regra acima e garantida por restricao unica em pessoa, curso e ano de censo.
|
||||||
|
- vinculos sao filtrados pelo ano de trabalho selecionado em telas de consulta.
|
||||||
|
|
||||||
|
Situacoes suportadas:
|
||||||
|
|
||||||
|
- Nao informada.
|
||||||
|
- Cursando.
|
||||||
|
- Matricula trancada.
|
||||||
|
- Desvinculado do curso.
|
||||||
|
- Transferencia interna.
|
||||||
|
- Formado.
|
||||||
|
- Falecido.
|
||||||
|
|
||||||
|
## Funcionalidades web
|
||||||
|
|
||||||
|
### Dashboard
|
||||||
|
|
||||||
|
Rota: `/`
|
||||||
|
|
||||||
|
Exibe vinculos agregados por curso para o ano selecionado, com contadores por situacao e quantidade de registros pendentes.
|
||||||
|
|
||||||
|
### Selecao de ano de censo
|
||||||
|
|
||||||
|
Rota: `/ano-censo/`
|
||||||
|
|
||||||
|
Atualiza na sessao o ano de trabalho. Esse ano e usado para filtrar vinculos em dashboard, listagens e processamento de situacao.
|
||||||
|
|
||||||
|
### Importacao do Arquivo Aluno
|
||||||
|
|
||||||
|
Rota: `/importar/alunos/`
|
||||||
|
|
||||||
|
Recebe arquivo `.txt` do Censup e processa registros:
|
||||||
|
|
||||||
|
- `40`: cabecalho.
|
||||||
|
- `41`: dados cadastrais de pessoa.
|
||||||
|
- `42`: vinculo do aluno com curso.
|
||||||
|
|
||||||
|
O resultado informa pessoas criadas/atualizadas, vinculos criados/atualizados, registros ignorados e erros.
|
||||||
|
|
||||||
|
### Importacao de pessoas Gennera
|
||||||
|
|
||||||
|
Rota: `/importar/pessoas-gennera/`
|
||||||
|
|
||||||
|
Consulta a API Gennera por ano de referencia e cria pessoas ainda nao existentes na base local.
|
||||||
|
|
||||||
|
### Importacao de vinculos Gennera
|
||||||
|
|
||||||
|
Rota: `/importar/vinculos-gennera/`
|
||||||
|
|
||||||
|
Consulta a API Gennera por CPF e ano selecionado, criando ou atualizando vinculos locais conforme regras de situacao.
|
||||||
|
|
||||||
|
Endpoint esperado:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /vinculo/?ano=<ano>&cpf=<cpf>
|
||||||
|
```
|
||||||
|
|
||||||
|
O curso do vinculo deve ser resolvido exclusivamente pelo campo `course_code`, correspondente a `Curso.codigo_mec`. Se `course_code` nao vier na resposta ou nao existir em cursos locais, o registro deve ser rejeitado com erro.
|
||||||
|
|
||||||
|
### Processamento de situacao em lote
|
||||||
|
|
||||||
|
Rota: `/processar/situacao/`
|
||||||
|
|
||||||
|
Recebe uma lista de matriculas e uma situacao alvo. Atualiza vinculos do ano selecionado e informa matriculas nao encontradas.
|
||||||
|
|
||||||
|
### Pendencias
|
||||||
|
|
||||||
|
Rota: `/pendencias/`
|
||||||
|
|
||||||
|
Lista registros com campos obrigatorios ou regras de consistencia pendentes, usando as validacoes de `core/validation.py`.
|
||||||
|
|
||||||
|
### CRUD generico
|
||||||
|
|
||||||
|
Rotas:
|
||||||
|
|
||||||
|
- `/cadastros/<slug>/`
|
||||||
|
- `/cadastros/<slug>/novo/`
|
||||||
|
- `/cadastros/<slug>/<pk>/`
|
||||||
|
- `/cadastros/<slug>/<pk>/editar/`
|
||||||
|
- `/cadastros/<slug>/<pk>/excluir/`
|
||||||
|
|
||||||
|
Cadastros disponiveis:
|
||||||
|
|
||||||
|
- anos do censo.
|
||||||
|
- UFs.
|
||||||
|
- paises.
|
||||||
|
- municipios.
|
||||||
|
- cursos.
|
||||||
|
- fallbacks de curso.
|
||||||
|
- instituicoes.
|
||||||
|
- polos.
|
||||||
|
- pessoas.
|
||||||
|
- vinculos.
|
||||||
|
|
||||||
|
## Regras de validacao
|
||||||
|
|
||||||
|
### Curso
|
||||||
|
|
||||||
|
- Codigo MEC e descricao sao obrigatorios.
|
||||||
|
- Situacao de funcionamento e obrigatoria.
|
||||||
|
- Carga horaria total deve ser maior que zero.
|
||||||
|
- Curso EaD deve ter polo vinculado.
|
||||||
|
|
||||||
|
### Pessoa
|
||||||
|
|
||||||
|
- Nome, CPF, data de nascimento, cor/raca, nacionalidade, pais de origem, indicador de deficiencia e tipo de escola do ensino medio sao obrigatorios.
|
||||||
|
- CPF deve conter 11 digitos numericos.
|
||||||
|
- Brasileira nata deve ter pais `BRA` e UF de nascimento.
|
||||||
|
- Brasileira naturalizada ou estrangeira nao pode ter pais `BRA` nem UF/municipio de nascimento.
|
||||||
|
- Municipio de nascimento exige UF e deve pertencer a UF informada.
|
||||||
|
- Quando o indicador de deficiencia for Sim, todos os tipos de deficiencia devem estar preenchidos e ao menos um deve estar marcado.
|
||||||
|
|
||||||
|
### Vinculo
|
||||||
|
|
||||||
|
- Ano do censo e situacao sao obrigatorios.
|
||||||
|
- Semestre de ingresso deve seguir o formato `01AAAA` ou `02AAAA`.
|
||||||
|
- Curso presencial exige turno do aluno.
|
||||||
|
- Curso EaD exige polo no vinculo ou no curso.
|
||||||
|
- Curso de licenciatura exige informacoes de Aluno PARFOR e segunda licenciatura/formacao pedagogica.
|
||||||
|
- Carga horaria total do aluno deve vir do curso.
|
||||||
|
- Vinculo formado exige carga horaria integralizada maior ou igual a carga horaria total.
|
||||||
|
- Indicadores de financiamento, apoio social, atividade extracurricular e acao afirmativa devem ter os tipos correspondentes preenchidos conforme a opcao principal.
|
||||||
|
|
||||||
|
## Regras de importacao de vinculos
|
||||||
|
|
||||||
|
- A decisao de situacao e feita por pessoa, curso e ano de censo.
|
||||||
|
- Registros retornados pela API para outro ano sao ignorados na decisao do ano selecionado.
|
||||||
|
- Se a carga horaria acumulada for maior ou igual a carga horaria total do curso, a situacao deve ser Formado.
|
||||||
|
- Vinculo ja Formado nao deve ser rebaixado por outra regra de importacao.
|
||||||
|
- Se houver registro no segundo semestre do ano selecionado, a situacao deve ser Cursando.
|
||||||
|
- Se houver registro apenas no primeiro semestre do ano selecionado, a situacao deve ser Desvinculado.
|
||||||
|
- Se nao houver vinculo retornado para pessoa que ja possui vinculo local no ano, a situacao local deve ser Desvinculado, exceto quando ja estiver Formado.
|
||||||
|
- A carga horaria acumulada retornada pela API deve atualizar a carga horaria integralizada mesmo quando a situacao Formado for preservada.
|
||||||
|
- O campo `semestre_ingresso` deve ser atualizado a partir do registro mais antigo do grupo de vinculos, considerando ano e semestre. O formato gravado e `AAYYYY`, por exemplo `012026` para primeiro semestre de 2026.
|
||||||
|
|
||||||
|
## Dados de apoio
|
||||||
|
|
||||||
|
Arquivos relevantes em `docs/`:
|
||||||
|
|
||||||
|
- `REGRAS_ARQUIVO_ALUNO.md`: regras do leiaute do Arquivo Aluno.
|
||||||
|
- `aluno_exportacao.txt`: exemplo ou insumo de arquivo aluno.
|
||||||
|
- `cursos.csv` e `cursos_locais.csv`: insumos de cursos.
|
||||||
|
- `leiaute_aluno_2025.xlsx`: leiaute oficial usado como referencia.
|
||||||
|
- `tabela_municipio_2025.xlsx`, `tabela_paises_2025.xlsx`, `tabela_uf_2025.xlsx`: tabelas auxiliares.
|
||||||
|
|
||||||
|
## Fluxo operacional sugerido
|
||||||
|
|
||||||
|
1. Conferir e atualizar cadastros de cursos.
|
||||||
|
2. Exportar `aluno_exportacao.txt` no sistema Censup.
|
||||||
|
3. Importar o Arquivo Aluno no Autocensup.
|
||||||
|
4. Importar pessoas e vinculos da API Gennera quando necessario.
|
||||||
|
5. Revisar dashboard e pendencias.
|
||||||
|
6. Processar ajustes de situacao por matricula, se aplicavel.
|
||||||
|
7. Corrigir cadastros pendentes via CRUD.
|
||||||
|
|
||||||
|
## Testes
|
||||||
|
|
||||||
|
Executar a suite:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py test
|
||||||
|
```
|
||||||
|
|
||||||
|
Verificar migracoes pendentes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py makemigrations --check --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Observacoes de schema
|
||||||
|
|
||||||
|
O campo `Vinculo.ano_censo` e uma `ForeignKey` para `AnoCenso`, mas usa explicitamente a coluna fisica `ano_censo` no banco por compatibilidade com dados existentes. Essa decisao evita perda de dados e mantem o ORM alinhado ao schema atual.
|
||||||
5
ETAPAS.md
Normal file
5
ETAPAS.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Etapas de geração de arquivo do censup:
|
||||||
|
|
||||||
|
1 - Conferir o cadastro de curso, usando as views do sistema;
|
||||||
|
2 - Exportar arquivo aluno_exportacao.txt do site censup (https://censosuperior.inep.gov.br/censosuperior/), evento externo;
|
||||||
|
3 - Importar o arquivo aluno_exportacao.txt;
|
||||||
13
Makefile
Normal file
13
Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.PHONY: up down logs worker
|
||||||
|
|
||||||
|
up:
|
||||||
|
docker compose up -d db valkey
|
||||||
|
|
||||||
|
down:
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
logs:
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
worker:
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run celery -A config worker -l info
|
||||||
56
README.md
Normal file
56
README.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
## Autocensup
|
||||||
|
|
||||||
|
Aplicacao Django configurada para usar PostgreSQL.
|
||||||
|
|
||||||
|
### Requisitos
|
||||||
|
|
||||||
|
- Python 3.12+
|
||||||
|
- uv
|
||||||
|
- Docker e Docker Compose
|
||||||
|
|
||||||
|
### Como rodar
|
||||||
|
|
||||||
|
Crie o arquivo de ambiente:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Instale as dependencias:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv sync
|
||||||
|
```
|
||||||
|
|
||||||
|
Suba o PostgreSQL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d db
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute as migracoes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
Carregue as UFs e municipios:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py loaddata ufs municipios
|
||||||
|
```
|
||||||
|
|
||||||
|
Inicie o servidor:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
A aplicacao ficara disponivel em <http://127.0.0.1:8000/>.
|
||||||
|
|
||||||
|
### Comandos uteis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py createsuperuser
|
||||||
|
UV_CACHE_DIR=/tmp/uv-cache uv run python manage.py test
|
||||||
|
```
|
||||||
49
REGRAS_VINCULO.md
Normal file
49
REGRAS_VINCULO.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Regras de importacao de vinculos
|
||||||
|
|
||||||
|
## Origem
|
||||||
|
|
||||||
|
A importacao de vinculos consulta a API Gennera pessoa por pessoa, usando o CPF da
|
||||||
|
pessoa cadastrada localmente e o ano de referencia selecionado.
|
||||||
|
|
||||||
|
Endpoint consultado:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /vinculo/?ano=<ano>&cpf=<cpf>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Curso
|
||||||
|
|
||||||
|
O campo `course_code` retornado pela API Gennera representa o codigo MEC do curso.
|
||||||
|
Esse valor deve ser usado para localizar `Curso.codigo_mec`.
|
||||||
|
|
||||||
|
## Situacao do vinculo
|
||||||
|
|
||||||
|
As regras de situacao devem ser aplicadas por pessoa, curso e ano do censo.
|
||||||
|
Registros retornados pela API para outro ano devem ser ignorados na decisao do
|
||||||
|
ano selecionado.
|
||||||
|
|
||||||
|
1. Se `carga_horaria_acumulada` for maior ou igual a `carga_horaria_total` do curso,
|
||||||
|
a situacao do vinculo deve ser `FORMADO`.
|
||||||
|
2. Uma vez que um vinculo esteja `FORMADO`, ele nao pode ser alterado por outra
|
||||||
|
regra de importacao.
|
||||||
|
3. Se houver vinculo no ano do censo e no semestre 2, a situacao deve ser
|
||||||
|
`CURSANDO`.
|
||||||
|
4. Se houver vinculo no ano do censo e no semestre 1, mas nao houver no semestre 2,
|
||||||
|
a situacao deve ser `DESVINCULADO`.
|
||||||
|
5. Se nao houver vinculo no ano do censo para uma pessoa que ja possui vinculo local
|
||||||
|
no ano, a situacao local deve ser `DESVINCULADO`, exceto quando o vinculo local ja
|
||||||
|
estiver `FORMADO`.
|
||||||
|
|
||||||
|
## Prioridade
|
||||||
|
|
||||||
|
A regra de `FORMADO` tem prioridade sobre todas as demais.
|
||||||
|
Mesmo quando a situacao `FORMADO` for preservada, a carga horaria acumulada
|
||||||
|
retornada pela API deve sempre atualizar a carga horaria integralizada do vinculo.
|
||||||
|
|
||||||
|
Ordem pratica de decisao:
|
||||||
|
|
||||||
|
1. Manter `FORMADO` se o vinculo local ja estiver formado.
|
||||||
|
2. Definir `FORMADO` se a carga horaria acumulada atingir a carga horaria total do curso.
|
||||||
|
3. Ignorar registros fora do ano do censo selecionado.
|
||||||
|
4. Definir `CURSANDO` se existir registro no semestre 2 do ano do censo.
|
||||||
|
5. Definir `DESVINCULADO` nos demais casos do ano do censo.
|
||||||
3
config/__init__.py
Normal file
3
config/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .celery import app as celery_app
|
||||||
|
|
||||||
|
__all__ = ("celery_app",)
|
||||||
9
config/asgi.py
Normal file
9
config/asgi.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""ASGI config for autocensup."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
||||||
9
config/celery.py
Normal file
9
config/celery.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||||
|
|
||||||
|
app = Celery("autocensup")
|
||||||
|
app.config_from_object("django.conf:settings", namespace="CELERY")
|
||||||
|
app.autodiscover_tasks()
|
||||||
153
config/settings.py
Normal file
153
config/settings.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
"""Django settings for autocensup."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def load_env_file(path: Path) -> None:
|
||||||
|
if not path.exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
for line in path.read_text().splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("#") or "=" not in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
key, value = line.split("=", 1)
|
||||||
|
key = key.strip()
|
||||||
|
value = value.strip().strip("'\"")
|
||||||
|
if key:
|
||||||
|
os.environ.setdefault(key, value)
|
||||||
|
|
||||||
|
|
||||||
|
load_env_file(BASE_DIR / ".env")
|
||||||
|
|
||||||
|
SECRET_KEY = os.getenv(
|
||||||
|
"DJANGO_SECRET_KEY",
|
||||||
|
"django-insecure-dev-only-change-me",
|
||||||
|
)
|
||||||
|
|
||||||
|
DEBUG = os.getenv("DJANGO_DEBUG", "True").lower() in {"1", "true", "yes", "on"}
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = [
|
||||||
|
host.strip()
|
||||||
|
for host in os.getenv("DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1,0.0.0.0").split(",")
|
||||||
|
if host.strip()
|
||||||
|
]
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
"django.contrib.admin",
|
||||||
|
"django.contrib.auth",
|
||||||
|
"django.contrib.contenttypes",
|
||||||
|
"django.contrib.sessions",
|
||||||
|
"django.contrib.messages",
|
||||||
|
"django.contrib.staticfiles",
|
||||||
|
"core",
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = "config.urls"
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
|
"DIRS": [BASE_DIR / "templates"],
|
||||||
|
"APP_DIRS": True,
|
||||||
|
"OPTIONS": {
|
||||||
|
"context_processors": [
|
||||||
|
"django.template.context_processors.request",
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"core.context_processors.ano_censo",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = "config.wsgi.application"
|
||||||
|
|
||||||
|
|
||||||
|
def database_config() -> dict[str, str | int]:
|
||||||
|
database_url = os.getenv("DATABASE_URL")
|
||||||
|
|
||||||
|
if database_url:
|
||||||
|
parsed = urlparse(database_url)
|
||||||
|
return {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": parsed.path.removeprefix("/"),
|
||||||
|
"USER": parsed.username or "",
|
||||||
|
"PASSWORD": parsed.password or "",
|
||||||
|
"HOST": parsed.hostname or "",
|
||||||
|
"PORT": parsed.port or 5432,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
"NAME": os.getenv("POSTGRES_DB", "autocensup"),
|
||||||
|
"USER": os.getenv("POSTGRES_USER", "autocensup"),
|
||||||
|
"PASSWORD": os.getenv("POSTGRES_PASSWORD", "autocensup"),
|
||||||
|
"HOST": os.getenv("POSTGRES_HOST", "localhost"),
|
||||||
|
"PORT": int(os.getenv("POSTGRES_PORT", "5432")),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": database_config(),
|
||||||
|
}
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
LANGUAGE_CODE = "pt-br"
|
||||||
|
TIME_ZONE = "America/Fortaleza"
|
||||||
|
USE_I18N = True
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
STATIC_URL = "static/"
|
||||||
|
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
|
LOGIN_URL = "login"
|
||||||
|
LOGIN_REDIRECT_URL = "home"
|
||||||
|
LOGOUT_REDIRECT_URL = "login"
|
||||||
|
|
||||||
|
GENNERA_API_BASE_URL = os.getenv("GENNERA_API_BASE_URL", "http://gennera.solucaoti.net.br")
|
||||||
|
GENNERA_API_TOKEN = os.getenv("API_TOKEN", "")
|
||||||
|
GENNERA_LOCAL_AUTH_TOKEN = os.getenv("GENNERA_LOCAL_AUTH_TOKEN", "")
|
||||||
|
|
||||||
|
CENSUP_IES_CODIGO = os.getenv("CENSUP_IES_CODIGO", "")
|
||||||
|
|
||||||
|
CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL", "redis://localhost:6379/0")
|
||||||
|
CELERY_RESULT_BACKEND = os.getenv("CELERY_RESULT_BACKEND", "redis://localhost:6379/0")
|
||||||
|
CELERY_TASK_SERIALIZER = "json"
|
||||||
|
CELERY_RESULT_SERIALIZER = "json"
|
||||||
|
CELERY_ACCEPT_CONTENT = ["json"]
|
||||||
|
CELERY_TASK_TRACK_STARTED = True
|
||||||
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
|
CELERY_RESULT_EXTENDED = True
|
||||||
10
config/urls.py
Normal file
10
config/urls.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"""URL configuration for autocensup."""
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import include, path
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("accounts/", include("django.contrib.auth.urls")),
|
||||||
|
path("", include("core.urls")),
|
||||||
|
path("admin/", admin.site.urls),
|
||||||
|
]
|
||||||
9
config/wsgi.py
Normal file
9
config/wsgi.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""WSGI config for autocensup."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
1
core/__init__.py
Normal file
1
core/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
138
core/admin.py
Normal file
138
core/admin.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import (
|
||||||
|
AnoCenso,
|
||||||
|
Curso,
|
||||||
|
FallbackCurso,
|
||||||
|
Instituicao,
|
||||||
|
Municipio,
|
||||||
|
Pais,
|
||||||
|
Pessoa,
|
||||||
|
Polo,
|
||||||
|
UF,
|
||||||
|
Vinculo,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(AnoCenso)
|
||||||
|
class AnoCensoAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("ano", "ano_execucao")
|
||||||
|
search_fields = ("ano",)
|
||||||
|
ordering = ("-ano",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(UF)
|
||||||
|
class UFAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("codigo", "nome")
|
||||||
|
search_fields = ("codigo", "nome")
|
||||||
|
ordering = ("nome",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Pais)
|
||||||
|
class PaisAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("codigo", "nome")
|
||||||
|
search_fields = ("codigo", "nome")
|
||||||
|
ordering = ("nome",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Municipio)
|
||||||
|
class MunicipioAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("codigo", "nome", "uf")
|
||||||
|
list_filter = ("uf",)
|
||||||
|
search_fields = ("codigo", "nome", "uf__nome")
|
||||||
|
autocomplete_fields = ("uf",)
|
||||||
|
ordering = ("nome",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Curso)
|
||||||
|
class CursoAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"codigo_mec",
|
||||||
|
"descricao",
|
||||||
|
"situacao_funcionamento_curso",
|
||||||
|
"licenciatura",
|
||||||
|
"ead",
|
||||||
|
"polo",
|
||||||
|
"carga_horaria_total",
|
||||||
|
)
|
||||||
|
list_filter = ("situacao_funcionamento_curso", "licenciatura", "ead")
|
||||||
|
search_fields = ("codigo_mec", "descricao", "situacao_funcionamento_curso", "polo__descricao")
|
||||||
|
autocomplete_fields = ("polo",)
|
||||||
|
ordering = ("descricao",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(FallbackCurso)
|
||||||
|
class FallbackCursoAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("id", "texto_api", "texto_local")
|
||||||
|
search_fields = ("texto_api", "texto_local")
|
||||||
|
ordering = ("texto_api",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Instituicao)
|
||||||
|
class InstituicaoAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("codigo_inep", "nome")
|
||||||
|
search_fields = ("codigo_inep", "nome")
|
||||||
|
ordering = ("nome", "codigo_inep")
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Polo)
|
||||||
|
class PoloAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ("id", "codigo", "descricao")
|
||||||
|
search_fields = ("codigo", "descricao")
|
||||||
|
ordering = ("descricao", "codigo")
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Pessoa)
|
||||||
|
class PessoaAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"nome",
|
||||||
|
"cpf",
|
||||||
|
"data_nascimento",
|
||||||
|
"nacionalidade",
|
||||||
|
"pais_origem",
|
||||||
|
)
|
||||||
|
list_filter = ("cor_raca", "nacionalidade", "aluno_com_deficiencia")
|
||||||
|
search_fields = ("nome", "cpf", "id_aluno_inep")
|
||||||
|
autocomplete_fields = ("uf_nascimento", "municipio_nascimento", "pais_origem")
|
||||||
|
ordering = ("nome",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Vinculo)
|
||||||
|
class VinculoAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"pessoa",
|
||||||
|
"curso",
|
||||||
|
"ano_censo",
|
||||||
|
"periodo_referencia",
|
||||||
|
"situacao",
|
||||||
|
"semestre_ingresso",
|
||||||
|
)
|
||||||
|
list_filter = (
|
||||||
|
"ano_censo",
|
||||||
|
"periodo_referencia",
|
||||||
|
"situacao",
|
||||||
|
"turno",
|
||||||
|
"apoio_social",
|
||||||
|
"atividade_extracurricular",
|
||||||
|
"ingressou_acao_afirmativa",
|
||||||
|
)
|
||||||
|
search_fields = (
|
||||||
|
"pessoa__nome",
|
||||||
|
"pessoa__cpf",
|
||||||
|
"matricula",
|
||||||
|
"ano_censo",
|
||||||
|
"curso__codigo_mec",
|
||||||
|
"curso__descricao",
|
||||||
|
)
|
||||||
|
autocomplete_fields = (
|
||||||
|
"pessoa",
|
||||||
|
"curso",
|
||||||
|
"polo",
|
||||||
|
"curso_origem",
|
||||||
|
"mobilidade_ies_destino",
|
||||||
|
"mobilidade_pais_destino",
|
||||||
|
)
|
||||||
|
ordering = ("pessoa__nome", "curso__descricao")
|
||||||
6
core/apps.py
Normal file
6
core/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class CoreConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "core"
|
||||||
12
core/context_processors.py
Normal file
12
core/context_processors.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from django.http import HttpRequest
|
||||||
|
|
||||||
|
from .year import available_anos_censo, get_selected_ano_censo
|
||||||
|
|
||||||
|
|
||||||
|
def ano_censo(request: HttpRequest) -> dict[str, object]:
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"selected_ano_censo": selected_year,
|
||||||
|
"available_anos_censo": available_anos_censo(),
|
||||||
|
}
|
||||||
44578
core/fixtures/municipios.json
Normal file
44578
core/fixtures/municipios.json
Normal file
File diff suppressed because it is too large
Load Diff
1752
core/fixtures/paises.json
Normal file
1752
core/fixtures/paises.json
Normal file
File diff suppressed because it is too large
Load Diff
198
core/fixtures/ufs.json
Normal file
198
core/fixtures/ufs.json
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 11,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Rondônia"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 12,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Acre"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 13,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Amazonas"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 14,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Roraima"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 15,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Pará"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 16,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Amapá"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 17,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Tocantins"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 21,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Maranhão"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 22,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Piauí"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 23,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Ceará"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 24,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Rio Grande do Norte"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 25,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Paraíba"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 26,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Pernambuco"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 27,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Alagoas"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 28,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Sergipe"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 29,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Bahia"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 31,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Minas Gerais"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 32,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Espírito Santo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 33,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Rio de Janeiro"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 35,
|
||||||
|
"fields": {
|
||||||
|
"nome": "São Paulo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 41,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Paraná"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 42,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Santa Catarina"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 43,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Rio Grande do Sul"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 50,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Mato Grosso do Sul"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 51,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Mato Grosso"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 52,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Goiás"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 53,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Distrito Federal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "core.uf",
|
||||||
|
"pk": 99,
|
||||||
|
"fields": {
|
||||||
|
"nome": "Exterior (embaixada)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
1381
core/importers.py
Normal file
1381
core/importers.py
Normal file
File diff suppressed because it is too large
Load Diff
1
core/management/__init__.py
Normal file
1
core/management/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
core/management/commands/__init__.py
Normal file
1
core/management/commands/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
59
core/management/commands/import_carga_horaria_censup.py
Normal file
59
core/management/commands/import_carga_horaria_censup.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
|
from core.importers import import_carga_horaria_from_gennera
|
||||||
|
from core.models import Vinculo
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = (
|
||||||
|
"Atualiza a carga horaria integralizada de cada vinculo consultando "
|
||||||
|
"a API Gennera (censup_carga_horaria), por matricula."
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_arguments(self, parser) -> None:
|
||||||
|
parser.add_argument("--page-size", type=int, default=100)
|
||||||
|
parser.add_argument("--threads", type=int, default=4)
|
||||||
|
|
||||||
|
def handle(self, *args, **options) -> None:
|
||||||
|
token = settings.GENNERA_LOCAL_AUTH_TOKEN
|
||||||
|
if not token:
|
||||||
|
raise CommandError("GENNERA_LOCAL_AUTH_TOKEN nao configurado no .env.")
|
||||||
|
|
||||||
|
page_size = options["page_size"]
|
||||||
|
threads = options["threads"]
|
||||||
|
|
||||||
|
def report_progress(
|
||||||
|
index: int, total: int, matricula: str, vinculos: list[Vinculo]
|
||||||
|
) -> None:
|
||||||
|
if not vinculos:
|
||||||
|
self.stdout.write(
|
||||||
|
f"Matricula {index}/{total} - {matricula} - sem atualizacao"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
for vinculo in vinculos:
|
||||||
|
self.stdout.write(
|
||||||
|
f"Matricula {index}/{total} - {matricula} - "
|
||||||
|
f"{vinculo.curso.descricao} - "
|
||||||
|
f"{vinculo.carga_horaria_integralizada}/{vinculo.carga_horaria_total_aluno}h"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_carga_horaria_from_gennera(
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=token,
|
||||||
|
page_size=page_size,
|
||||||
|
max_workers=threads,
|
||||||
|
progress_callback=report_progress,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
"Importacao concluida: "
|
||||||
|
f"{result.matriculas_processadas} matriculas processadas, "
|
||||||
|
f"{result.vinculos_atualizados} vinculos atualizados, "
|
||||||
|
f"{result.sem_dados} sem dados na API, "
|
||||||
|
f"{len(result.errors)} com erro."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for error in result.errors:
|
||||||
|
self.stdout.write(self.style.WARNING(f" {error.identifier}: {error.message}"))
|
||||||
29
core/management/commands/import_cursos.py
Normal file
29
core/management/commands/import_cursos.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from core.importers import import_cursos
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Importa cursos de um CSV usando carga horaria maxima do TXT de alunos."
|
||||||
|
|
||||||
|
def add_arguments(self, parser) -> None:
|
||||||
|
parser.add_argument("--csv", default="docs/cursos.csv")
|
||||||
|
parser.add_argument("--alunos", default="docs/aluno_exportacao.txt")
|
||||||
|
|
||||||
|
def handle(self, *args, **options) -> None:
|
||||||
|
result = import_cursos(
|
||||||
|
csv_path=Path(options["csv"]),
|
||||||
|
alunos_path=Path(options["alunos"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
"Cursos importados: "
|
||||||
|
f"{result.total} processados, "
|
||||||
|
f"{result.created} criados, "
|
||||||
|
f"{result.updated} atualizados, "
|
||||||
|
f"{result.without_carga_horaria} sem carga horaria no TXT."
|
||||||
|
)
|
||||||
|
)
|
||||||
46
core/management/commands/import_pessoas_ingressantes.py
Normal file
46
core/management/commands/import_pessoas_ingressantes.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
|
from core.importers import import_pessoas_ingressantes_from_gennera
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Importa pessoas ingressantes da API Gennera (censup_person_ingressantes)."
|
||||||
|
|
||||||
|
def add_arguments(self, parser) -> None:
|
||||||
|
parser.add_argument("--primeiro-ano", type=int, default=2025)
|
||||||
|
parser.add_argument("--page-size", type=int, default=100)
|
||||||
|
|
||||||
|
def handle(self, *args, **options) -> None:
|
||||||
|
token = settings.GENNERA_LOCAL_AUTH_TOKEN
|
||||||
|
if not token:
|
||||||
|
raise CommandError("GENNERA_LOCAL_AUTH_TOKEN nao configurado no .env.")
|
||||||
|
|
||||||
|
primeiro_ano = options["primeiro_ano"]
|
||||||
|
page_size = options["page_size"]
|
||||||
|
|
||||||
|
def report_progress(page: int, total_pages: int, processed: int, total_count: int) -> None:
|
||||||
|
self.stdout.write(
|
||||||
|
f"Pagina {page}/{total_pages} - {processed}/{total_count} pessoas processadas"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_pessoas_ingressantes_from_gennera(
|
||||||
|
primeiro_ano=primeiro_ano,
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=token,
|
||||||
|
page_size=page_size,
|
||||||
|
progress_callback=report_progress,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
"Importacao concluida: "
|
||||||
|
f"{result.total} processadas, "
|
||||||
|
f"{result.created} criadas, "
|
||||||
|
f"{result.skipped} ignoradas, "
|
||||||
|
f"{result.ignorados_sem_cpf} sem CPF, "
|
||||||
|
f"{len(result.errors)} com erro."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for error in result.errors:
|
||||||
|
self.stdout.write(self.style.WARNING(f" {error.identifier}: {error.message}"))
|
||||||
26
core/management/commands/import_polos.py
Normal file
26
core/management/commands/import_polos.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from core.importers import import_polos
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Importa polos de cursos_locais.csv e vincula cursos EaD ao primeiro polo encontrado."
|
||||||
|
|
||||||
|
def add_arguments(self, parser) -> None:
|
||||||
|
parser.add_argument("--csv", default="docs/cursos_locais.csv")
|
||||||
|
|
||||||
|
def handle(self, *args, **options) -> None:
|
||||||
|
result = import_polos(csv_path=Path(options["csv"]))
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
"Polos importados: "
|
||||||
|
f"{result.total} linhas processadas, "
|
||||||
|
f"{result.created} criados, "
|
||||||
|
f"{result.updated} atualizados, "
|
||||||
|
f"{result.cursos_vinculados} cursos EaD vinculados, "
|
||||||
|
f"{result.cursos_nao_encontrados} cursos nao encontrados."
|
||||||
|
)
|
||||||
|
)
|
||||||
62
core/management/commands/import_vinculos_censup.py
Normal file
62
core/management/commands/import_vinculos_censup.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
|
from core.importers import fetch_gennera_vinculos_censup, import_vinculos_from_gennera
|
||||||
|
from core.models import Vinculo
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = (
|
||||||
|
"Importa vinculos da API Gennera (censup_vinculos): cria os que nao "
|
||||||
|
"existem e atualiza os existentes, por pessoa cadastrada."
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_arguments(self, parser) -> None:
|
||||||
|
parser.add_argument("--ano", type=int, required=True)
|
||||||
|
parser.add_argument("--page-size", type=int, default=100)
|
||||||
|
parser.add_argument("--threads", type=int, default=4)
|
||||||
|
|
||||||
|
def handle(self, *args, **options) -> None:
|
||||||
|
token = settings.GENNERA_LOCAL_AUTH_TOKEN
|
||||||
|
if not token:
|
||||||
|
raise CommandError("GENNERA_LOCAL_AUTH_TOKEN nao configurado no .env.")
|
||||||
|
|
||||||
|
ano = options["ano"]
|
||||||
|
page_size = options["page_size"]
|
||||||
|
threads = options["threads"]
|
||||||
|
|
||||||
|
def report_progress(
|
||||||
|
index: int, total: int, cpf: str, vinculos: list[Vinculo]
|
||||||
|
) -> None:
|
||||||
|
if not vinculos:
|
||||||
|
self.stdout.write(f"Pessoa {index}/{total} - CPF {cpf} - sem vinculo")
|
||||||
|
return
|
||||||
|
for vinculo in vinculos:
|
||||||
|
self.stdout.write(
|
||||||
|
f"Pessoa {index}/{total} - CPF {cpf} - "
|
||||||
|
f"{vinculo.curso.descricao} - {vinculo.get_situacao_display()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_vinculos_from_gennera(
|
||||||
|
ano=ano,
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=token,
|
||||||
|
fetcher=partial(fetch_gennera_vinculos_censup, page_size=page_size),
|
||||||
|
progress_callback=report_progress,
|
||||||
|
max_workers=threads,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(
|
||||||
|
"Importacao concluida: "
|
||||||
|
f"{result.pessoas_processed} pessoas processadas, "
|
||||||
|
f"{result.pessoas_without_vinculo} sem vinculo no ano, "
|
||||||
|
f"{result.created} vinculos criados, "
|
||||||
|
f"{result.updated} vinculos atualizados, "
|
||||||
|
f"{len(result.errors)} com erro."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for error in result.errors:
|
||||||
|
self.stdout.write(self.style.WARNING(f" {error.identifier}: {error.message}"))
|
||||||
41
core/migrations/0001_initial.py
Normal file
41
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-14 16:35
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UF',
|
||||||
|
fields=[
|
||||||
|
('codigo', models.PositiveSmallIntegerField(primary_key=True, serialize=False)),
|
||||||
|
('nome', models.CharField(max_length=100, unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'UF',
|
||||||
|
'verbose_name_plural': 'UFs',
|
||||||
|
'ordering': ['nome'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Municipio',
|
||||||
|
fields=[
|
||||||
|
('codigo', models.PositiveIntegerField(primary_key=True, serialize=False)),
|
||||||
|
('nome', models.CharField(max_length=150)),
|
||||||
|
('uf', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='municipios', to='core.uf')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'municipio',
|
||||||
|
'verbose_name_plural': 'municipios',
|
||||||
|
'ordering': ['nome'],
|
||||||
|
'indexes': [models.Index(fields=['nome'], name='core_munici_nome_0e9814_idx'), models.Index(fields=['uf', 'nome'], name='core_munici_uf_id_ac0c6d_idx')],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
29
core/migrations/0002_curso.py
Normal file
29
core/migrations/0002_curso.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-14 17:03
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Curso',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
|
('codigo_mec', models.PositiveIntegerField()),
|
||||||
|
('descricao', models.CharField(max_length=200)),
|
||||||
|
('licenciatura', models.BooleanField(default=False)),
|
||||||
|
('ead', models.BooleanField(default=False)),
|
||||||
|
('carga_horaria_total', models.PositiveIntegerField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'curso',
|
||||||
|
'verbose_name_plural': 'cursos',
|
||||||
|
'ordering': ['descricao'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
25
core/migrations/0003_pais.py
Normal file
25
core/migrations/0003_pais.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-14 17:04
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0002_curso'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Pais',
|
||||||
|
fields=[
|
||||||
|
('codigo', models.CharField(max_length=3, primary_key=True, serialize=False)),
|
||||||
|
('nome', models.CharField(max_length=100, unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'pais',
|
||||||
|
'verbose_name_plural': 'paises',
|
||||||
|
'ordering': ['nome'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-14 17:21
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0003_pais'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Instituicao',
|
||||||
|
fields=[
|
||||||
|
('codigo_inep', models.PositiveBigIntegerField(primary_key=True, serialize=False)),
|
||||||
|
('nome', models.CharField(blank=True, max_length=200)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'instituicao',
|
||||||
|
'verbose_name_plural': 'instituicoes',
|
||||||
|
'ordering': ['nome', 'codigo_inep'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Polo',
|
||||||
|
fields=[
|
||||||
|
('codigo_inep', models.PositiveBigIntegerField(primary_key=True, serialize=False)),
|
||||||
|
('descricao', models.CharField(blank=True, max_length=200)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'polo',
|
||||||
|
'verbose_name_plural': 'polos',
|
||||||
|
'ordering': ['descricao', 'codigo_inep'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='curso',
|
||||||
|
name='codigo_mec',
|
||||||
|
field=models.PositiveIntegerField(unique=True),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Pessoa',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('id_aluno_inep', models.PositiveBigIntegerField(blank=True, null=True)),
|
||||||
|
('nome', models.CharField(max_length=120)),
|
||||||
|
('cpf', models.CharField(max_length=11, unique=True)),
|
||||||
|
('documento_estrangeiro', models.CharField(blank=True, max_length=20)),
|
||||||
|
('data_nascimento', models.DateField()),
|
||||||
|
('cor_raca', models.PositiveSmallIntegerField(choices=[(0, 'Aluno nao quis declarar cor/raca'), (1, 'Branca'), (2, 'Preta'), (3, 'Parda'), (4, 'Amarela'), (5, 'Indigena'), (6, 'Nao dispoe da informacao')])),
|
||||||
|
('nacionalidade', models.PositiveSmallIntegerField(choices=[(1, 'Brasileira nata'), (2, 'Brasileira por naturalizacao'), (3, 'Estrangeira')])),
|
||||||
|
('aluno_com_deficiencia', models.PositiveSmallIntegerField(choices=[(0, 'Nao'), (1, 'Sim'), (2, 'Nao dispoe da informacao')])),
|
||||||
|
('deficiencia_cegueira', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_baixa_visao', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_visao_monocular', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_surdez', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_auditiva', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_fisica', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_surdocegueira', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_intelectual', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_tea', models.BooleanField(blank=True, null=True)),
|
||||||
|
('deficiencia_altas_habilidades', models.BooleanField(blank=True, null=True)),
|
||||||
|
('tipo_escola_ensino_medio', models.PositiveSmallIntegerField(choices=[(0, 'Privado'), (1, 'Publico'), (2, 'Nao dispoe da informacao')])),
|
||||||
|
('municipio_nascimento', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pessoas_nascidas', to='core.municipio')),
|
||||||
|
('pais_origem', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='pessoas_originarias', to='core.pais')),
|
||||||
|
('uf_nascimento', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pessoas_nascidas', to='core.uf')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'pessoa',
|
||||||
|
'verbose_name_plural': 'pessoas',
|
||||||
|
'ordering': ['nome'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Vinculo',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('id_aluno_ies', models.CharField(blank=True, max_length=20)),
|
||||||
|
('periodo_referencia', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Primeiro semestre'), (2, 'Segundo semestre')], null=True)),
|
||||||
|
('turno', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Matutino'), (2, 'Vespertino'), (3, 'Noturno'), (4, 'Integral')], null=True)),
|
||||||
|
('situacao', models.PositiveSmallIntegerField(choices=[(2, 'Cursando'), (3, 'Matricula trancada'), (4, 'Desvinculado do curso'), (5, 'Transferencia interna'), (6, 'Formado'), (7, 'Falecido')])),
|
||||||
|
('semestre_conclusao', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Primeiro semestre'), (2, 'Segundo semestre')], null=True)),
|
||||||
|
('aluno_parfor', models.BooleanField(blank=True, null=True)),
|
||||||
|
('segunda_licenciatura_formacao_pedagogica', models.BooleanField(blank=True, null=True)),
|
||||||
|
('tipo_segunda_licenciatura_formacao_pedagogica', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Segunda licenciatura'), (2, 'Formacao pedagogica')], null=True)),
|
||||||
|
('semestre_ingresso', models.CharField(max_length=6)),
|
||||||
|
('ingresso_vestibular', models.BooleanField()),
|
||||||
|
('ingresso_enem', models.BooleanField()),
|
||||||
|
('ingresso_avaliacao_seriada', models.BooleanField()),
|
||||||
|
('ingresso_selecao_simplificada', models.BooleanField()),
|
||||||
|
('ingresso_egresso_bi_li', models.BooleanField()),
|
||||||
|
('ingresso_pec_g', models.BooleanField()),
|
||||||
|
('ingresso_transferencia_ex_officio', models.BooleanField()),
|
||||||
|
('ingresso_decisao_judicial', models.BooleanField()),
|
||||||
|
('ingresso_vagas_remanescentes', models.BooleanField()),
|
||||||
|
('ingresso_programas_especiais', models.BooleanField()),
|
||||||
|
('mobilidade_academica', models.BooleanField(blank=True, null=True)),
|
||||||
|
('tipo_mobilidade_academica', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Nacional'), (2, 'Internacional')], null=True)),
|
||||||
|
('financiamento_estudantil', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_fies', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_governo_estadual', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_governo_municipal', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_ies', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_entidades_externas', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_prouni_integral', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_prouni_parcial', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_nao_reembolsavel_entidades_externas', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_nao_reembolsavel_governo_estadual', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_nao_reembolsavel_ies', models.BooleanField(blank=True, null=True)),
|
||||||
|
('financiamento_nao_reembolsavel_governo_municipal', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_social', models.BooleanField()),
|
||||||
|
('apoio_alimentacao', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_moradia', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_transporte', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_material_didatico', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_bolsa_trabalho', models.BooleanField(blank=True, null=True)),
|
||||||
|
('apoio_bolsa_permanencia', models.BooleanField(blank=True, null=True)),
|
||||||
|
('atividade_extracurricular', models.BooleanField()),
|
||||||
|
('atividade_pesquisa', models.BooleanField(blank=True, null=True)),
|
||||||
|
('bolsa_pesquisa', models.BooleanField(blank=True, null=True)),
|
||||||
|
('atividade_extensao', models.BooleanField(blank=True, null=True)),
|
||||||
|
('bolsa_extensao', models.BooleanField(blank=True, null=True)),
|
||||||
|
('atividade_monitoria', models.BooleanField(blank=True, null=True)),
|
||||||
|
('bolsa_monitoria', models.BooleanField(blank=True, null=True)),
|
||||||
|
('atividade_estagio_nao_obrigatorio', models.BooleanField(blank=True, null=True)),
|
||||||
|
('bolsa_estagio_nao_obrigatorio', models.BooleanField(blank=True, null=True)),
|
||||||
|
('carga_horaria_total_aluno', models.PositiveIntegerField()),
|
||||||
|
('carga_horaria_integralizada', models.PositiveIntegerField()),
|
||||||
|
('ingressou_acao_afirmativa', models.BooleanField()),
|
||||||
|
('tipo_politica_acao_afirmativa', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Reserva de vaga - Lei de Cotas'), (2, 'Outras reservas de vagas ou programa diferenciado')], null=True)),
|
||||||
|
('tipo_acao_afirmativa_lei_cotas', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||||
|
('reserva_ppi', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_renda', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_pessoa_com_deficiencia', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_escola_publica', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_quilombola', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_transgenero_travesti', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_estudante_internacional', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_refugiado_apatrida_visto_humanitario', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_idoso', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_povos_comunidades_tradicionais', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_olimpiadas_conhecimento', models.BooleanField(blank=True, null=True)),
|
||||||
|
('reserva_outros', models.BooleanField(blank=True, null=True)),
|
||||||
|
('justificativa', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||||
|
('curso', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vinculos', to='core.curso', to_field='codigo_mec')),
|
||||||
|
('curso_origem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vinculos_originados', to='core.curso', to_field='codigo_mec')),
|
||||||
|
('mobilidade_ies_destino', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vinculos_mobilidade_destino', to='core.instituicao')),
|
||||||
|
('mobilidade_pais_destino', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vinculos_mobilidade_destino', to='core.pais')),
|
||||||
|
('pessoa', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vinculos', to='core.pessoa')),
|
||||||
|
('polo', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vinculos', to='core.polo')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'vinculo',
|
||||||
|
'verbose_name_plural': 'vinculos',
|
||||||
|
'ordering': ['pessoa__nome', 'curso__descricao'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='pessoa',
|
||||||
|
index=models.Index(fields=['nome'], name='core_pessoa_nome_124496_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='pessoa',
|
||||||
|
index=models.Index(fields=['cpf'], name='core_pessoa_cpf_2292ad_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='vinculo',
|
||||||
|
index=models.Index(fields=['situacao'], name='core_vincul_situaca_cd833c_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='vinculo',
|
||||||
|
index=models.Index(fields=['semestre_ingresso'], name='core_vincul_semestr_fb0751_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='vinculo',
|
||||||
|
constraint=models.UniqueConstraint(fields=('pessoa', 'curso', 'periodo_referencia'), name='unique_vinculo_pessoa_curso_periodo'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-14 17:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0004_instituicao_polo_alter_curso_codigo_mec_pessoa_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveConstraint(
|
||||||
|
model_name='vinculo',
|
||||||
|
name='unique_vinculo_pessoa_curso_periodo',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vinculo',
|
||||||
|
name='ano_censo',
|
||||||
|
field=models.PositiveSmallIntegerField(default=2025),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='vinculo',
|
||||||
|
index=models.Index(fields=['ano_censo'], name='core_vincul_ano_cen_514d37_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name='vinculo',
|
||||||
|
constraint=models.UniqueConstraint(fields=('pessoa', 'curso', 'ano_censo'), name='unique_vinculo_pessoa_curso_ano'),
|
||||||
|
),
|
||||||
|
]
|
||||||
85
core/migrations/0006_rework_polo_add_curso_situacao.py
Normal file
85
core/migrations/0006_rework_polo_add_curso_situacao.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Generated manually to rework Polo and add course import fields.
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0005_remove_vinculo_unique_vinculo_pessoa_curso_periodo_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="vinculo",
|
||||||
|
name="polo",
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name="Polo",
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Polo",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("codigo", models.PositiveBigIntegerField(unique=True)),
|
||||||
|
("descricao", models.CharField(max_length=200)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "polo",
|
||||||
|
"verbose_name_plural": "polos",
|
||||||
|
"ordering": ["descricao", "codigo"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="curso",
|
||||||
|
name="situacao_funcionamento_curso",
|
||||||
|
field=models.CharField(blank=True, default="", max_length=100),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="curso",
|
||||||
|
name="polo",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="cursos",
|
||||||
|
to="core.polo",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="vinculo",
|
||||||
|
name="polo",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="vinculos",
|
||||||
|
to="core.polo",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="vinculo",
|
||||||
|
name="situacao",
|
||||||
|
field=models.PositiveSmallIntegerField(
|
||||||
|
choices=[
|
||||||
|
(0, "Nao informada"),
|
||||||
|
(2, "Cursando"),
|
||||||
|
(3, "Matricula trancada"),
|
||||||
|
(4, "Desvinculado do curso"),
|
||||||
|
(5, "Transferencia interna"),
|
||||||
|
(6, "Formado"),
|
||||||
|
(7, "Falecido"),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-05-15 12:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0006_rework_polo_add_curso_situacao'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AnoCenso',
|
||||||
|
fields=[
|
||||||
|
('ano', models.PositiveSmallIntegerField(primary_key=True, serialize=False)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'ano do censo',
|
||||||
|
'verbose_name_plural': 'anos do censo',
|
||||||
|
'ordering': ['-ano'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.SeparateDatabaseAndState(
|
||||||
|
database_operations=[],
|
||||||
|
state_operations=[
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='vinculo',
|
||||||
|
old_name='id_aluno_ies',
|
||||||
|
new_name='matricula',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='vinculo',
|
||||||
|
name='matricula',
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
db_column='id_aluno_ies',
|
||||||
|
max_length=20,
|
||||||
|
verbose_name='matricula',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
22
core/migrations/0008_create_ano_censo_2025.py
Normal file
22
core/migrations/0008_create_ano_censo_2025.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def create_ano_censo_2025(apps, schema_editor):
|
||||||
|
AnoCenso = apps.get_model("core", "AnoCenso")
|
||||||
|
AnoCenso.objects.get_or_create(ano=2025)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_ano_censo_2025(apps, schema_editor):
|
||||||
|
AnoCenso = apps.get_model("core", "AnoCenso")
|
||||||
|
AnoCenso.objects.filter(ano=2025).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0007_anocenso_align_vinculo_matricula_state"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(create_ano_censo_2025, remove_ano_censo_2025),
|
||||||
|
]
|
||||||
57
core/migrations/0009_fallbackcurso.py
Normal file
57
core/migrations/0009_fallbackcurso.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def create_initial_course_fallbacks(apps, schema_editor):
|
||||||
|
FallbackCurso = apps.get_model("core", "FallbackCurso")
|
||||||
|
FallbackCurso.objects.get_or_create(
|
||||||
|
texto_api="Bacharelado em Administração",
|
||||||
|
defaults={"texto_local": "ADMINISTRAÇÃO"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_initial_course_fallbacks(apps, schema_editor):
|
||||||
|
FallbackCurso = apps.get_model("core", "FallbackCurso")
|
||||||
|
FallbackCurso.objects.filter(
|
||||||
|
texto_api="Bacharelado em Administração",
|
||||||
|
texto_local="ADMINISTRAÇÃO",
|
||||||
|
).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0008_create_ano_censo_2025"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="FallbackCurso",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("texto_api", models.CharField(max_length=200, unique=True)),
|
||||||
|
("texto_local", models.CharField(max_length=200)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "fallback de curso",
|
||||||
|
"verbose_name_plural": "fallbacks de curso",
|
||||||
|
"ordering": ["texto_api"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name="fallbackcurso",
|
||||||
|
index=models.Index(fields=["texto_api"], name="core_fallba_texto_a_b13933_idx"),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name="fallbackcurso",
|
||||||
|
index=models.Index(fields=["texto_local"], name="core_fallba_texto_l_644724_idx"),
|
||||||
|
),
|
||||||
|
migrations.RunPython(create_initial_course_fallbacks, remove_initial_course_fallbacks),
|
||||||
|
]
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def create_anos_and_link_pessoas(apps, schema_editor):
|
||||||
|
AnoCenso = apps.get_model("core", "AnoCenso")
|
||||||
|
Pessoa = apps.get_model("core", "Pessoa")
|
||||||
|
Vinculo = apps.get_model("core", "Vinculo")
|
||||||
|
|
||||||
|
anos = set(Vinculo.objects.values_list("ano_censo", flat=True))
|
||||||
|
for ano in anos:
|
||||||
|
if ano is not None:
|
||||||
|
AnoCenso.objects.get_or_create(ano=ano)
|
||||||
|
|
||||||
|
for pessoa in Pessoa.objects.all():
|
||||||
|
pessoa_anos = Vinculo.objects.filter(pessoa=pessoa).values_list("ano_censo", flat=True)
|
||||||
|
for ano in set(pessoa_anos):
|
||||||
|
if ano is None:
|
||||||
|
continue
|
||||||
|
ano_censo, _ = AnoCenso.objects.get_or_create(ano=ano)
|
||||||
|
pessoa.anos_censo.add(ano_censo)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0009_fallbackcurso"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="pessoa",
|
||||||
|
name="anos_censo",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name="pessoas",
|
||||||
|
to="core.anocenso",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunPython(create_anos_and_link_pessoas, migrations.RunPython.noop),
|
||||||
|
migrations.RenameIndex(
|
||||||
|
model_name="vinculo",
|
||||||
|
new_name="core_vincul_ano_cen_e1353a_idx",
|
||||||
|
old_name="core_vincul_ano_cen_514d37_idx",
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="vinculo",
|
||||||
|
name="ano_censo",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
default=2025,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="vinculos",
|
||||||
|
to="core.anocenso",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
33
core/migrations/0011_fix_vinculo_ano_censo_column.py
Normal file
33
core/migrations/0011_fix_vinculo_ano_censo_column.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0010_pessoa_anos_censo_vinculo_ano_censo_fk"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunSQL(
|
||||||
|
sql="""
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'core_vinculo'
|
||||||
|
AND column_name = 'ano_censo'
|
||||||
|
) AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_name = 'core_vinculo'
|
||||||
|
AND column_name = 'ano_censo_id'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE core_vinculo
|
||||||
|
RENAME COLUMN ano_censo TO ano_censo_id;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
""",
|
||||||
|
reverse_sql=migrations.RunSQL.noop,
|
||||||
|
),
|
||||||
|
]
|
||||||
18
core/migrations/0012_alter_pessoa_data_nascimento.py
Normal file
18
core/migrations/0012_alter_pessoa_data_nascimento.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.14 on 2026-07-05 12:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0011_fix_vinculo_ano_censo_column'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='pessoa',
|
||||||
|
name='data_nascimento',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
core/migrations/__init__.py
Normal file
0
core/migrations/__init__.py
Normal file
414
core/models.py
Normal file
414
core/models.py
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class AnoCenso(models.Model):
|
||||||
|
ano = models.PositiveSmallIntegerField(primary_key=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "ano do censo"
|
||||||
|
verbose_name_plural = "anos do censo"
|
||||||
|
ordering = ["-ano"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ano_execucao(self) -> int:
|
||||||
|
return self.ano + 1
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return str(self.ano)
|
||||||
|
|
||||||
|
|
||||||
|
class UF(models.Model):
|
||||||
|
codigo = models.PositiveSmallIntegerField(primary_key=True)
|
||||||
|
nome = models.CharField(max_length=100, unique=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "UF"
|
||||||
|
verbose_name_plural = "UFs"
|
||||||
|
ordering = ["nome"]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.nome
|
||||||
|
|
||||||
|
|
||||||
|
class Pais(models.Model):
|
||||||
|
codigo = models.CharField(max_length=3, primary_key=True)
|
||||||
|
nome = models.CharField(max_length=100, unique=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "pais"
|
||||||
|
verbose_name_plural = "paises"
|
||||||
|
ordering = ["nome"]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.nome
|
||||||
|
|
||||||
|
|
||||||
|
class Municipio(models.Model):
|
||||||
|
codigo = models.PositiveIntegerField(primary_key=True)
|
||||||
|
nome = models.CharField(max_length=150)
|
||||||
|
uf = models.ForeignKey(UF, on_delete=models.PROTECT, related_name="municipios")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "municipio"
|
||||||
|
verbose_name_plural = "municipios"
|
||||||
|
ordering = ["nome"]
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["nome"]),
|
||||||
|
models.Index(fields=["uf", "nome"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.nome} - {self.uf.nome}"
|
||||||
|
|
||||||
|
|
||||||
|
class Curso(models.Model):
|
||||||
|
id = models.BigAutoField(primary_key=True)
|
||||||
|
codigo_mec = models.PositiveIntegerField(unique=True)
|
||||||
|
descricao = models.CharField(max_length=200)
|
||||||
|
situacao_funcionamento_curso = models.CharField(max_length=100, blank=True)
|
||||||
|
licenciatura = models.BooleanField(default=False)
|
||||||
|
ead = models.BooleanField(default=False)
|
||||||
|
carga_horaria_total = models.PositiveIntegerField()
|
||||||
|
polo = models.ForeignKey(
|
||||||
|
"Polo",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="cursos",
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "curso"
|
||||||
|
verbose_name_plural = "cursos"
|
||||||
|
ordering = ["descricao"]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.descricao
|
||||||
|
|
||||||
|
|
||||||
|
class FallbackCurso(models.Model):
|
||||||
|
texto_api = models.CharField(max_length=200, unique=True)
|
||||||
|
texto_local = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "fallback de curso"
|
||||||
|
verbose_name_plural = "fallbacks de curso"
|
||||||
|
ordering = ["texto_api"]
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["texto_api"]),
|
||||||
|
models.Index(fields=["texto_local"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.texto_api} -> {self.texto_local}"
|
||||||
|
|
||||||
|
|
||||||
|
class Instituicao(models.Model):
|
||||||
|
codigo_inep = models.PositiveBigIntegerField(primary_key=True)
|
||||||
|
nome = models.CharField(max_length=200, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "instituicao"
|
||||||
|
verbose_name_plural = "instituicoes"
|
||||||
|
ordering = ["nome", "codigo_inep"]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.nome or str(self.codigo_inep)
|
||||||
|
|
||||||
|
|
||||||
|
class Polo(models.Model):
|
||||||
|
codigo = models.PositiveBigIntegerField(unique=True)
|
||||||
|
descricao = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "polo"
|
||||||
|
verbose_name_plural = "polos"
|
||||||
|
ordering = ["descricao", "codigo"]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.descricao
|
||||||
|
|
||||||
|
|
||||||
|
class Pessoa(models.Model):
|
||||||
|
class CorRaca(models.IntegerChoices):
|
||||||
|
NAO_DECLARADA = 0, "Aluno nao quis declarar cor/raca"
|
||||||
|
BRANCA = 1, "Branca"
|
||||||
|
PRETA = 2, "Preta"
|
||||||
|
PARDA = 3, "Parda"
|
||||||
|
AMARELA = 4, "Amarela"
|
||||||
|
INDIGENA = 5, "Indigena"
|
||||||
|
NAO_DISPOE = 6, "Nao dispoe da informacao"
|
||||||
|
|
||||||
|
class Nacionalidade(models.IntegerChoices):
|
||||||
|
BRASILEIRA_NATA = 1, "Brasileira nata"
|
||||||
|
BRASILEIRA_NATURALIZADA = 2, "Brasileira por naturalizacao"
|
||||||
|
ESTRANGEIRA = 3, "Estrangeira"
|
||||||
|
|
||||||
|
class SimNaoNaoDispoe(models.IntegerChoices):
|
||||||
|
NAO = 0, "Nao"
|
||||||
|
SIM = 1, "Sim"
|
||||||
|
NAO_DISPOE = 2, "Nao dispoe da informacao"
|
||||||
|
|
||||||
|
class TipoEscolaEnsinoMedio(models.IntegerChoices):
|
||||||
|
PRIVADA = 0, "Privado"
|
||||||
|
PUBLICA = 1, "Publico"
|
||||||
|
NAO_DISPOE = 2, "Nao dispoe da informacao"
|
||||||
|
|
||||||
|
id_aluno_inep = models.PositiveBigIntegerField(null=True, blank=True)
|
||||||
|
nome = models.CharField(max_length=120)
|
||||||
|
cpf = models.CharField(max_length=11, unique=True)
|
||||||
|
documento_estrangeiro = models.CharField(max_length=20, blank=True)
|
||||||
|
data_nascimento = models.DateField(null=True, blank=True)
|
||||||
|
cor_raca = models.PositiveSmallIntegerField(choices=CorRaca.choices)
|
||||||
|
nacionalidade = models.PositiveSmallIntegerField(choices=Nacionalidade.choices)
|
||||||
|
uf_nascimento = models.ForeignKey(
|
||||||
|
UF,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="pessoas_nascidas",
|
||||||
|
)
|
||||||
|
municipio_nascimento = models.ForeignKey(
|
||||||
|
Municipio,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="pessoas_nascidas",
|
||||||
|
)
|
||||||
|
pais_origem = models.ForeignKey(
|
||||||
|
Pais,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name="pessoas_originarias",
|
||||||
|
)
|
||||||
|
aluno_com_deficiencia = models.PositiveSmallIntegerField(
|
||||||
|
choices=SimNaoNaoDispoe.choices
|
||||||
|
)
|
||||||
|
deficiencia_cegueira = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_baixa_visao = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_visao_monocular = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_surdez = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_auditiva = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_fisica = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_surdocegueira = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_intelectual = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_tea = models.BooleanField(null=True, blank=True)
|
||||||
|
deficiencia_altas_habilidades = models.BooleanField(null=True, blank=True)
|
||||||
|
tipo_escola_ensino_medio = models.PositiveSmallIntegerField(
|
||||||
|
choices=TipoEscolaEnsinoMedio.choices
|
||||||
|
)
|
||||||
|
anos_censo = models.ManyToManyField(
|
||||||
|
AnoCenso,
|
||||||
|
blank=True,
|
||||||
|
related_name="pessoas",
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "pessoa"
|
||||||
|
verbose_name_plural = "pessoas"
|
||||||
|
ordering = ["nome"]
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["nome"]),
|
||||||
|
models.Index(fields=["cpf"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.nome
|
||||||
|
|
||||||
|
|
||||||
|
class Vinculo(models.Model):
|
||||||
|
class PeriodoReferencia(models.IntegerChoices):
|
||||||
|
PRIMEIRO_SEMESTRE = 1, "Primeiro semestre"
|
||||||
|
SEGUNDO_SEMESTRE = 2, "Segundo semestre"
|
||||||
|
|
||||||
|
class Turno(models.IntegerChoices):
|
||||||
|
MATUTINO = 1, "Matutino"
|
||||||
|
VESPERTINO = 2, "Vespertino"
|
||||||
|
NOTURNO = 3, "Noturno"
|
||||||
|
INTEGRAL = 4, "Integral"
|
||||||
|
|
||||||
|
class Situacao(models.IntegerChoices):
|
||||||
|
NAO_INFORMADA = 0, "Nao informada"
|
||||||
|
CURSANDO = 2, "Cursando"
|
||||||
|
MATRICULA_TRANCADA = 3, "Matricula trancada"
|
||||||
|
DESVINCULADO = 4, "Desvinculado do curso"
|
||||||
|
TRANSFERENCIA_INTERNA = 5, "Transferencia interna"
|
||||||
|
FORMADO = 6, "Formado"
|
||||||
|
FALECIDO = 7, "Falecido"
|
||||||
|
|
||||||
|
class TipoSegundaLicenciatura(models.IntegerChoices):
|
||||||
|
SEGUNDA_LICENCIATURA = 1, "Segunda licenciatura"
|
||||||
|
FORMACAO_PEDAGOGICA = 2, "Formacao pedagogica"
|
||||||
|
|
||||||
|
class TipoMobilidade(models.IntegerChoices):
|
||||||
|
NACIONAL = 1, "Nacional"
|
||||||
|
INTERNACIONAL = 2, "Internacional"
|
||||||
|
|
||||||
|
class TipoPoliticaAcaoAfirmativa(models.IntegerChoices):
|
||||||
|
LEI_COTAS = 1, "Reserva de vaga - Lei de Cotas"
|
||||||
|
OUTRAS = 2, "Outras reservas de vagas ou programa diferenciado"
|
||||||
|
|
||||||
|
pessoa = models.ForeignKey(Pessoa, on_delete=models.CASCADE, related_name="vinculos")
|
||||||
|
ano_censo = models.ForeignKey(
|
||||||
|
AnoCenso,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
default=2025,
|
||||||
|
related_name="vinculos",
|
||||||
|
)
|
||||||
|
matricula = models.CharField(
|
||||||
|
"matricula",
|
||||||
|
max_length=20,
|
||||||
|
blank=True,
|
||||||
|
db_column="id_aluno_ies",
|
||||||
|
)
|
||||||
|
periodo_referencia = models.PositiveSmallIntegerField(
|
||||||
|
choices=PeriodoReferencia.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
curso = models.ForeignKey(
|
||||||
|
Curso,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
to_field="codigo_mec",
|
||||||
|
related_name="vinculos",
|
||||||
|
)
|
||||||
|
polo = models.ForeignKey(
|
||||||
|
Polo,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="vinculos",
|
||||||
|
)
|
||||||
|
turno = models.PositiveSmallIntegerField(choices=Turno.choices, null=True, blank=True)
|
||||||
|
situacao = models.PositiveSmallIntegerField(choices=Situacao.choices)
|
||||||
|
curso_origem = models.ForeignKey(
|
||||||
|
Curso,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
to_field="codigo_mec",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="vinculos_originados",
|
||||||
|
)
|
||||||
|
semestre_conclusao = models.PositiveSmallIntegerField(
|
||||||
|
choices=PeriodoReferencia.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
aluno_parfor = models.BooleanField(null=True, blank=True)
|
||||||
|
segunda_licenciatura_formacao_pedagogica = models.BooleanField(null=True, blank=True)
|
||||||
|
tipo_segunda_licenciatura_formacao_pedagogica = models.PositiveSmallIntegerField(
|
||||||
|
choices=TipoSegundaLicenciatura.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
semestre_ingresso = models.CharField(max_length=6)
|
||||||
|
ingresso_vestibular = models.BooleanField()
|
||||||
|
ingresso_enem = models.BooleanField()
|
||||||
|
ingresso_avaliacao_seriada = models.BooleanField()
|
||||||
|
ingresso_selecao_simplificada = models.BooleanField()
|
||||||
|
ingresso_egresso_bi_li = models.BooleanField()
|
||||||
|
ingresso_pec_g = models.BooleanField()
|
||||||
|
ingresso_transferencia_ex_officio = models.BooleanField()
|
||||||
|
ingresso_decisao_judicial = models.BooleanField()
|
||||||
|
ingresso_vagas_remanescentes = models.BooleanField()
|
||||||
|
ingresso_programas_especiais = models.BooleanField()
|
||||||
|
mobilidade_academica = models.BooleanField(null=True, blank=True)
|
||||||
|
tipo_mobilidade_academica = models.PositiveSmallIntegerField(
|
||||||
|
choices=TipoMobilidade.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
mobilidade_ies_destino = models.ForeignKey(
|
||||||
|
Instituicao,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="vinculos_mobilidade_destino",
|
||||||
|
)
|
||||||
|
mobilidade_pais_destino = models.ForeignKey(
|
||||||
|
Pais,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="vinculos_mobilidade_destino",
|
||||||
|
)
|
||||||
|
financiamento_estudantil = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_fies = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_governo_estadual = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_governo_municipal = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_ies = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_entidades_externas = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_prouni_integral = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_prouni_parcial = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_nao_reembolsavel_entidades_externas = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
financiamento_nao_reembolsavel_governo_estadual = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
financiamento_nao_reembolsavel_ies = models.BooleanField(null=True, blank=True)
|
||||||
|
financiamento_nao_reembolsavel_governo_municipal = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
apoio_social = models.BooleanField()
|
||||||
|
apoio_alimentacao = models.BooleanField(null=True, blank=True)
|
||||||
|
apoio_moradia = models.BooleanField(null=True, blank=True)
|
||||||
|
apoio_transporte = models.BooleanField(null=True, blank=True)
|
||||||
|
apoio_material_didatico = models.BooleanField(null=True, blank=True)
|
||||||
|
apoio_bolsa_trabalho = models.BooleanField(null=True, blank=True)
|
||||||
|
apoio_bolsa_permanencia = models.BooleanField(null=True, blank=True)
|
||||||
|
atividade_extracurricular = models.BooleanField()
|
||||||
|
atividade_pesquisa = models.BooleanField(null=True, blank=True)
|
||||||
|
bolsa_pesquisa = models.BooleanField(null=True, blank=True)
|
||||||
|
atividade_extensao = models.BooleanField(null=True, blank=True)
|
||||||
|
bolsa_extensao = models.BooleanField(null=True, blank=True)
|
||||||
|
atividade_monitoria = models.BooleanField(null=True, blank=True)
|
||||||
|
bolsa_monitoria = models.BooleanField(null=True, blank=True)
|
||||||
|
atividade_estagio_nao_obrigatorio = models.BooleanField(null=True, blank=True)
|
||||||
|
bolsa_estagio_nao_obrigatorio = models.BooleanField(null=True, blank=True)
|
||||||
|
carga_horaria_total_aluno = models.PositiveIntegerField()
|
||||||
|
carga_horaria_integralizada = models.PositiveIntegerField()
|
||||||
|
ingressou_acao_afirmativa = models.BooleanField()
|
||||||
|
tipo_politica_acao_afirmativa = models.PositiveSmallIntegerField(
|
||||||
|
choices=TipoPoliticaAcaoAfirmativa.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
tipo_acao_afirmativa_lei_cotas = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||||
|
reserva_ppi = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_renda = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_pessoa_com_deficiencia = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_escola_publica = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_quilombola = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_transgenero_travesti = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_estudante_internacional = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_refugiado_apatrida_visto_humanitario = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
reserva_idoso = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_povos_comunidades_tradicionais = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_olimpiadas_conhecimento = models.BooleanField(null=True, blank=True)
|
||||||
|
reserva_outros = models.BooleanField(null=True, blank=True)
|
||||||
|
justificativa = models.PositiveSmallIntegerField(null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "vinculo"
|
||||||
|
verbose_name_plural = "vinculos"
|
||||||
|
ordering = ["pessoa__nome", "curso__descricao"]
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(
|
||||||
|
fields=["pessoa", "curso", "ano_censo"],
|
||||||
|
name="unique_vinculo_pessoa_curso_ano",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["ano_censo"]),
|
||||||
|
models.Index(fields=["situacao"]),
|
||||||
|
models.Index(fields=["semestre_ingresso"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.pessoa} - {self.curso}"
|
||||||
104
core/tasks.py
Normal file
104
core/tasks.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from celery import shared_task
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from .importers import (
|
||||||
|
fetch_gennera_vinculos_censup,
|
||||||
|
import_carga_horaria_from_gennera,
|
||||||
|
import_pessoas_ingressantes_from_gennera,
|
||||||
|
import_vinculos_from_gennera,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def import_pessoas_ingressantes_task(
|
||||||
|
self, primeiro_ano: int, page_size: int = 100
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
def report_progress(page: int, total_pages: int, processed: int, total_count: int) -> None:
|
||||||
|
self.update_state(
|
||||||
|
state="PROGRESS",
|
||||||
|
meta={
|
||||||
|
"processed": processed,
|
||||||
|
"total": total_count,
|
||||||
|
"message": f"Pagina {page}/{total_pages}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_pessoas_ingressantes_from_gennera(
|
||||||
|
primeiro_ano=primeiro_ano,
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
|
||||||
|
page_size=page_size,
|
||||||
|
progress_callback=report_progress,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"created": result.created,
|
||||||
|
"skipped": result.skipped,
|
||||||
|
"ignorados_sem_cpf": result.ignorados_sem_cpf,
|
||||||
|
"errors": len(result.errors),
|
||||||
|
"total": result.total,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def import_vinculos_censup_task(
|
||||||
|
self, ano: int, page_size: int = 100, threads: int = 4
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
def report_progress(index: int, total: int, cpf: str, vinculos: list) -> None:
|
||||||
|
self.update_state(
|
||||||
|
state="PROGRESS",
|
||||||
|
meta={
|
||||||
|
"processed": index,
|
||||||
|
"total": total,
|
||||||
|
"message": f"CPF {cpf}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_vinculos_from_gennera(
|
||||||
|
ano=ano,
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
|
||||||
|
fetcher=partial(fetch_gennera_vinculos_censup, page_size=page_size),
|
||||||
|
progress_callback=report_progress,
|
||||||
|
max_workers=threads,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"pessoas_processed": result.pessoas_processed,
|
||||||
|
"pessoas_without_vinculo": result.pessoas_without_vinculo,
|
||||||
|
"created": result.created,
|
||||||
|
"updated": result.updated,
|
||||||
|
"errors": len(result.errors),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def import_carga_horaria_censup_task(
|
||||||
|
self, page_size: int = 100, threads: int = 4
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
def report_progress(index: int, total: int, matricula: str, vinculos: list) -> None:
|
||||||
|
self.update_state(
|
||||||
|
state="PROGRESS",
|
||||||
|
meta={
|
||||||
|
"processed": index,
|
||||||
|
"total": total,
|
||||||
|
"message": f"Matricula {matricula}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = import_carga_horaria_from_gennera(
|
||||||
|
base_url=settings.GENNERA_API_BASE_URL,
|
||||||
|
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
|
||||||
|
page_size=page_size,
|
||||||
|
max_workers=threads,
|
||||||
|
progress_callback=report_progress,
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"matriculas_processadas": result.matriculas_processadas,
|
||||||
|
"vinculos_atualizados": result.vinculos_atualizados,
|
||||||
|
"sem_dados": result.sem_dados,
|
||||||
|
"errors": len(result.errors),
|
||||||
|
}
|
||||||
1832
core/tests.py
Normal file
1832
core/tests.py
Normal file
File diff suppressed because it is too large
Load Diff
35
core/urls.py
Normal file
35
core/urls.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import (
|
||||||
|
crud_create,
|
||||||
|
crud_delete,
|
||||||
|
crud_detail,
|
||||||
|
crud_list,
|
||||||
|
crud_update,
|
||||||
|
export_alunos_view,
|
||||||
|
home,
|
||||||
|
import_alunos_view,
|
||||||
|
pending_required_fields,
|
||||||
|
processar_situacao_view,
|
||||||
|
set_ano_censo,
|
||||||
|
start_task_view,
|
||||||
|
task_page_view,
|
||||||
|
task_status_view,
|
||||||
|
)
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("", home, name="home"),
|
||||||
|
path("ano-censo/", set_ano_censo, name="set_ano_censo"),
|
||||||
|
path("importar/alunos/", import_alunos_view, name="import_alunos"),
|
||||||
|
path("exportar/alunos/<slug:filtro>/", export_alunos_view, name="export_alunos"),
|
||||||
|
path("processar/situacao/", processar_situacao_view, name="processar_situacao"),
|
||||||
|
path("pendencias/", pending_required_fields, name="pending_required_fields"),
|
||||||
|
path("tarefas/<slug:operacao>/", task_page_view, name="task_page"),
|
||||||
|
path("tarefas/<slug:operacao>/iniciar/", start_task_view, name="start_task"),
|
||||||
|
path("tarefas/status/<str:task_id>/", task_status_view, name="task_status"),
|
||||||
|
path("cadastros/<slug:slug>/", crud_list, name="crud_list"),
|
||||||
|
path("cadastros/<slug:slug>/novo/", crud_create, name="crud_create"),
|
||||||
|
path("cadastros/<slug:slug>/<str:pk>/", crud_detail, name="crud_detail"),
|
||||||
|
path("cadastros/<slug:slug>/<str:pk>/editar/", crud_update, name="crud_update"),
|
||||||
|
path("cadastros/<slug:slug>/<str:pk>/excluir/", crud_delete, name="crud_delete"),
|
||||||
|
]
|
||||||
204
core/validation.py
Normal file
204
core/validation.py
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .models import Curso, Pessoa, Vinculo
|
||||||
|
|
||||||
|
|
||||||
|
SEMESTRE_RE = re.compile(r"^(01|02)(19|20)\d{2}$")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_curso(curso: Curso) -> list[str]:
|
||||||
|
issues = []
|
||||||
|
if not curso.codigo_mec:
|
||||||
|
issues.append("Curso: codigo MEC obrigatorio.")
|
||||||
|
if not curso.descricao:
|
||||||
|
issues.append("Curso: descricao obrigatoria.")
|
||||||
|
if not curso.situacao_funcionamento_curso:
|
||||||
|
issues.append("Curso: situacao de funcionamento obrigatoria.")
|
||||||
|
if curso.carga_horaria_total <= 0:
|
||||||
|
issues.append("Curso: carga horaria total deve ser maior que zero.")
|
||||||
|
if curso.ead and curso.polo_id is None:
|
||||||
|
issues.append("Curso: curso EaD deve ter polo vinculado.")
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def validate_pessoa(pessoa: Pessoa) -> list[str]:
|
||||||
|
issues = []
|
||||||
|
if not pessoa.nome:
|
||||||
|
issues.append("Pessoa: nome obrigatorio.")
|
||||||
|
if not pessoa.cpf or len(pessoa.cpf) != 11 or not pessoa.cpf.isdigit():
|
||||||
|
issues.append("Pessoa: CPF deve ter 11 digitos.")
|
||||||
|
if not pessoa.data_nascimento:
|
||||||
|
issues.append("Pessoa: data de nascimento obrigatoria.")
|
||||||
|
if pessoa.cor_raca is None:
|
||||||
|
issues.append("Pessoa: cor/raca obrigatoria.")
|
||||||
|
if pessoa.nacionalidade is None:
|
||||||
|
issues.append("Pessoa: nacionalidade obrigatoria.")
|
||||||
|
if pessoa.pais_origem_id is None:
|
||||||
|
issues.append("Pessoa: pais de origem obrigatorio.")
|
||||||
|
if pessoa.aluno_com_deficiencia is None:
|
||||||
|
issues.append("Pessoa: indicador de deficiencia obrigatorio.")
|
||||||
|
if pessoa.tipo_escola_ensino_medio is None:
|
||||||
|
issues.append("Pessoa: tipo de escola do ensino medio obrigatorio.")
|
||||||
|
|
||||||
|
if pessoa.nacionalidade == Pessoa.Nacionalidade.BRASILEIRA_NATA:
|
||||||
|
if pessoa.pais_origem_id != "BRA":
|
||||||
|
issues.append("Pessoa: brasileira nata deve ter pais de origem BRA.")
|
||||||
|
if pessoa.uf_nascimento_id is None:
|
||||||
|
issues.append("Pessoa: brasileira nata deve ter UF de nascimento.")
|
||||||
|
elif pessoa.nacionalidade in {
|
||||||
|
Pessoa.Nacionalidade.BRASILEIRA_NATURALIZADA,
|
||||||
|
Pessoa.Nacionalidade.ESTRANGEIRA,
|
||||||
|
}:
|
||||||
|
if pessoa.pais_origem_id == "BRA":
|
||||||
|
issues.append("Pessoa: pais BRA e exclusivo de brasileira nata.")
|
||||||
|
if pessoa.uf_nascimento_id is not None or pessoa.municipio_nascimento_id is not None:
|
||||||
|
issues.append("Pessoa: UF/municipio de nascimento sao exclusivos de brasileira nata.")
|
||||||
|
|
||||||
|
if pessoa.municipio_nascimento_id and pessoa.uf_nascimento_id is None:
|
||||||
|
issues.append("Pessoa: municipio de nascimento exige UF de nascimento.")
|
||||||
|
if (
|
||||||
|
pessoa.municipio_nascimento_id
|
||||||
|
and pessoa.uf_nascimento_id
|
||||||
|
and pessoa.municipio_nascimento.uf_id != pessoa.uf_nascimento_id
|
||||||
|
):
|
||||||
|
issues.append("Pessoa: municipio de nascimento nao pertence a UF informada.")
|
||||||
|
|
||||||
|
disability_flags = [
|
||||||
|
pessoa.deficiencia_cegueira,
|
||||||
|
pessoa.deficiencia_baixa_visao,
|
||||||
|
pessoa.deficiencia_visao_monocular,
|
||||||
|
pessoa.deficiencia_surdez,
|
||||||
|
pessoa.deficiencia_auditiva,
|
||||||
|
pessoa.deficiencia_fisica,
|
||||||
|
pessoa.deficiencia_surdocegueira,
|
||||||
|
pessoa.deficiencia_intelectual,
|
||||||
|
pessoa.deficiencia_tea,
|
||||||
|
pessoa.deficiencia_altas_habilidades,
|
||||||
|
]
|
||||||
|
has_disability_flag = any(flag is True for flag in disability_flags)
|
||||||
|
has_blank_disability_flag = any(flag is None for flag in disability_flags)
|
||||||
|
if pessoa.aluno_com_deficiencia == Pessoa.SimNaoNaoDispoe.SIM:
|
||||||
|
if has_blank_disability_flag:
|
||||||
|
issues.append("Pessoa: todos os tipos de deficiencia devem ser informados.")
|
||||||
|
if not has_disability_flag:
|
||||||
|
issues.append("Pessoa: ao menos um tipo de deficiencia deve ser marcado.")
|
||||||
|
elif has_disability_flag:
|
||||||
|
issues.append("Pessoa: tipos de deficiencia so podem ser marcados quando indicador for Sim.")
|
||||||
|
|
||||||
|
return issues
|
||||||
|
|
||||||
|
|
||||||
|
def validate_vinculo(vinculo: Vinculo) -> list[str]:
|
||||||
|
issues = []
|
||||||
|
curso = vinculo.curso
|
||||||
|
pessoa = vinculo.pessoa
|
||||||
|
|
||||||
|
issues.extend(validate_curso(curso))
|
||||||
|
issues.extend(validate_pessoa(pessoa))
|
||||||
|
|
||||||
|
if not vinculo.ano_censo:
|
||||||
|
issues.append("Vinculo: ano do censo obrigatorio.")
|
||||||
|
if vinculo.situacao == Vinculo.Situacao.NAO_INFORMADA:
|
||||||
|
issues.append("Vinculo: situacao de vinculo obrigatoria.")
|
||||||
|
if not vinculo.semestre_ingresso or not SEMESTRE_RE.match(vinculo.semestre_ingresso):
|
||||||
|
issues.append("Vinculo: semestre de ingresso deve estar no formato 01AAAA ou 02AAAA.")
|
||||||
|
|
||||||
|
if curso.ead:
|
||||||
|
if vinculo.polo_id is None and curso.polo_id is None:
|
||||||
|
issues.append("Vinculo: curso EaD exige polo.")
|
||||||
|
elif vinculo.turno is None:
|
||||||
|
issues.append("Vinculo: curso presencial exige turno do aluno.")
|
||||||
|
|
||||||
|
if curso.licenciatura:
|
||||||
|
if vinculo.aluno_parfor is None:
|
||||||
|
issues.append("Vinculo: licenciatura exige informacao de Aluno PARFOR.")
|
||||||
|
if vinculo.segunda_licenciatura_formacao_pedagogica is None:
|
||||||
|
issues.append("Vinculo: licenciatura exige segunda licenciatura/formacao pedagogica.")
|
||||||
|
if (
|
||||||
|
vinculo.segunda_licenciatura_formacao_pedagogica is True
|
||||||
|
and vinculo.tipo_segunda_licenciatura_formacao_pedagogica is None
|
||||||
|
):
|
||||||
|
issues.append("Vinculo: segunda licenciatura/formacao pedagogica exige tipo.")
|
||||||
|
|
||||||
|
if vinculo.carga_horaria_total_aluno != curso.carga_horaria_total:
|
||||||
|
issues.append("Vinculo: carga horaria total deve vir do curso.")
|
||||||
|
if vinculo.carga_horaria_total_aluno <= 0:
|
||||||
|
issues.append("Vinculo: carga horaria total obrigatoria.")
|
||||||
|
if vinculo.carga_horaria_integralizada < 0:
|
||||||
|
issues.append("Vinculo: carga horaria integralizada invalida.")
|
||||||
|
if vinculo.carga_horaria_integralizada > 15000:
|
||||||
|
issues.append("Vinculo: carga horaria integralizada deve ser menor que 15000.")
|
||||||
|
if (
|
||||||
|
vinculo.situacao == Vinculo.Situacao.FORMADO
|
||||||
|
and vinculo.carga_horaria_integralizada < vinculo.carga_horaria_total_aluno
|
||||||
|
):
|
||||||
|
issues.append("Vinculo: formado exige carga integralizada maior ou igual a total.")
|
||||||
|
|
||||||
|
if vinculo.financiamento_estudantil is True:
|
||||||
|
financing_flags = [
|
||||||
|
vinculo.financiamento_fies,
|
||||||
|
vinculo.financiamento_governo_estadual,
|
||||||
|
vinculo.financiamento_governo_municipal,
|
||||||
|
vinculo.financiamento_ies,
|
||||||
|
vinculo.financiamento_entidades_externas,
|
||||||
|
vinculo.financiamento_prouni_integral,
|
||||||
|
vinculo.financiamento_prouni_parcial,
|
||||||
|
vinculo.financiamento_nao_reembolsavel_entidades_externas,
|
||||||
|
vinculo.financiamento_nao_reembolsavel_governo_estadual,
|
||||||
|
vinculo.financiamento_nao_reembolsavel_ies,
|
||||||
|
vinculo.financiamento_nao_reembolsavel_governo_municipal,
|
||||||
|
]
|
||||||
|
if any(flag is None for flag in financing_flags):
|
||||||
|
issues.append("Vinculo: financiamento exige preenchimento dos tipos.")
|
||||||
|
if not any(flag is True for flag in financing_flags):
|
||||||
|
issues.append("Vinculo: financiamento exige ao menos um tipo marcado.")
|
||||||
|
|
||||||
|
social_flags = [
|
||||||
|
vinculo.apoio_alimentacao,
|
||||||
|
vinculo.apoio_moradia,
|
||||||
|
vinculo.apoio_transporte,
|
||||||
|
vinculo.apoio_material_didatico,
|
||||||
|
vinculo.apoio_bolsa_trabalho,
|
||||||
|
vinculo.apoio_bolsa_permanencia,
|
||||||
|
]
|
||||||
|
if vinculo.apoio_social and (any(flag is None for flag in social_flags) or not any(social_flags)):
|
||||||
|
issues.append("Vinculo: apoio social exige tipos preenchidos e ao menos um marcado.")
|
||||||
|
if not vinculo.apoio_social and any(flag is True for flag in social_flags):
|
||||||
|
issues.append("Vinculo: tipos de apoio social exigem Apoio Social igual a Sim.")
|
||||||
|
|
||||||
|
activity_flags = [
|
||||||
|
vinculo.atividade_pesquisa,
|
||||||
|
vinculo.atividade_extensao,
|
||||||
|
vinculo.atividade_monitoria,
|
||||||
|
vinculo.atividade_estagio_nao_obrigatorio,
|
||||||
|
]
|
||||||
|
if vinculo.atividade_extracurricular and (
|
||||||
|
any(flag is None for flag in activity_flags) or not any(activity_flags)
|
||||||
|
):
|
||||||
|
issues.append("Vinculo: atividade extracurricular exige tipos preenchidos e ao menos um marcado.")
|
||||||
|
if not vinculo.atividade_extracurricular and any(flag is True for flag in activity_flags):
|
||||||
|
issues.append("Vinculo: tipos de atividade exigem Atividade extracurricular igual a Sim.")
|
||||||
|
|
||||||
|
if vinculo.ingressou_acao_afirmativa:
|
||||||
|
if vinculo.tipo_politica_acao_afirmativa is None:
|
||||||
|
issues.append("Vinculo: acao afirmativa exige tipo de politica.")
|
||||||
|
reserve_flags = [
|
||||||
|
vinculo.reserva_ppi,
|
||||||
|
vinculo.reserva_renda,
|
||||||
|
vinculo.reserva_pessoa_com_deficiencia,
|
||||||
|
vinculo.reserva_escola_publica,
|
||||||
|
vinculo.reserva_quilombola,
|
||||||
|
vinculo.reserva_transgenero_travesti,
|
||||||
|
vinculo.reserva_estudante_internacional,
|
||||||
|
vinculo.reserva_refugiado_apatrida_visto_humanitario,
|
||||||
|
vinculo.reserva_idoso,
|
||||||
|
vinculo.reserva_povos_comunidades_tradicionais,
|
||||||
|
vinculo.reserva_olimpiadas_conhecimento,
|
||||||
|
vinculo.reserva_outros,
|
||||||
|
]
|
||||||
|
if not any(flag is True for flag in reserve_flags) and vinculo.tipo_acao_afirmativa_lei_cotas is None:
|
||||||
|
issues.append("Vinculo: acao afirmativa exige ao menos um tipo.")
|
||||||
|
|
||||||
|
return issues
|
||||||
784
core/views.py
Normal file
784
core/views.py
Normal file
@ -0,0 +1,784 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import re
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from celery.result import AsyncResult
|
||||||
|
from django import forms
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.db.models import Model, Q
|
||||||
|
from django.forms import modelform_factory
|
||||||
|
from django.http import (
|
||||||
|
Http404,
|
||||||
|
HttpRequest,
|
||||||
|
HttpResponse,
|
||||||
|
HttpResponseNotAllowed,
|
||||||
|
JsonResponse,
|
||||||
|
)
|
||||||
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.http import url_has_allowed_host_and_scheme
|
||||||
|
from django.core.paginator import Paginator
|
||||||
|
|
||||||
|
from .importers import build_aluno_export_file, import_alunos
|
||||||
|
from .models import (
|
||||||
|
AnoCenso,
|
||||||
|
Curso,
|
||||||
|
FallbackCurso,
|
||||||
|
Instituicao,
|
||||||
|
Municipio,
|
||||||
|
Pais,
|
||||||
|
Pessoa,
|
||||||
|
Polo,
|
||||||
|
UF,
|
||||||
|
Vinculo,
|
||||||
|
)
|
||||||
|
from .tasks import (
|
||||||
|
import_carga_horaria_censup_task,
|
||||||
|
import_pessoas_ingressantes_task,
|
||||||
|
import_vinculos_censup_task,
|
||||||
|
)
|
||||||
|
from .validation import validate_vinculo
|
||||||
|
from .year import get_selected_ano_censo, set_selected_ano_censo
|
||||||
|
|
||||||
|
|
||||||
|
TASK_OPERATIONS = {
|
||||||
|
"pessoas-ingressantes": {
|
||||||
|
"label": "Pessoas Ingressantes",
|
||||||
|
"task": import_pessoas_ingressantes_task,
|
||||||
|
},
|
||||||
|
"vinculos-censup": {
|
||||||
|
"label": "Vinculos (censup_vinculos)",
|
||||||
|
"task": import_vinculos_censup_task,
|
||||||
|
},
|
||||||
|
"carga-horaria-censup": {
|
||||||
|
"label": "Carga Horaria (censup_carga_horaria)",
|
||||||
|
"task": import_carga_horaria_censup_task,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class CrudConfig:
|
||||||
|
slug: str
|
||||||
|
model: type[Model]
|
||||||
|
title: str
|
||||||
|
list_fields: tuple[str, ...]
|
||||||
|
search_fields: tuple[tuple[str, str], ...]
|
||||||
|
|
||||||
|
|
||||||
|
CRUD_CONFIGS = {
|
||||||
|
"anos-censo": CrudConfig(
|
||||||
|
slug="anos-censo",
|
||||||
|
model=AnoCenso,
|
||||||
|
title="Anos do Censo",
|
||||||
|
list_fields=("ano", "ano_execucao"),
|
||||||
|
search_fields=(("ano", "int"),),
|
||||||
|
),
|
||||||
|
"ufs": CrudConfig(
|
||||||
|
slug="ufs",
|
||||||
|
model=UF,
|
||||||
|
title="UFs",
|
||||||
|
list_fields=("codigo", "nome"),
|
||||||
|
search_fields=(("codigo", "int"), ("nome", "icontains")),
|
||||||
|
),
|
||||||
|
"paises": CrudConfig(
|
||||||
|
slug="paises",
|
||||||
|
model=Pais,
|
||||||
|
title="Paises",
|
||||||
|
list_fields=("codigo", "nome"),
|
||||||
|
search_fields=(("codigo", "icontains"), ("nome", "icontains")),
|
||||||
|
),
|
||||||
|
"municipios": CrudConfig(
|
||||||
|
slug="municipios",
|
||||||
|
model=Municipio,
|
||||||
|
title="Municipios",
|
||||||
|
list_fields=("codigo", "nome", "uf"),
|
||||||
|
search_fields=(
|
||||||
|
("codigo", "int"),
|
||||||
|
("nome", "icontains"),
|
||||||
|
("uf__nome", "icontains"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"cursos": CrudConfig(
|
||||||
|
slug="cursos",
|
||||||
|
model=Curso,
|
||||||
|
title="Cursos",
|
||||||
|
list_fields=(
|
||||||
|
"codigo_mec",
|
||||||
|
"descricao",
|
||||||
|
"situacao_funcionamento_curso",
|
||||||
|
"licenciatura",
|
||||||
|
"ead",
|
||||||
|
"polo",
|
||||||
|
"carga_horaria_total",
|
||||||
|
),
|
||||||
|
search_fields=(
|
||||||
|
("codigo_mec", "int"),
|
||||||
|
("descricao", "icontains"),
|
||||||
|
("situacao_funcionamento_curso", "icontains"),
|
||||||
|
("polo__descricao", "icontains"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"fallbacks-cursos": CrudConfig(
|
||||||
|
slug="fallbacks-cursos",
|
||||||
|
model=FallbackCurso,
|
||||||
|
title="Fallbacks de Curso",
|
||||||
|
list_fields=("id", "texto_api", "texto_local"),
|
||||||
|
search_fields=(
|
||||||
|
("id", "int"),
|
||||||
|
("texto_api", "icontains"),
|
||||||
|
("texto_local", "icontains"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"instituicoes": CrudConfig(
|
||||||
|
slug="instituicoes",
|
||||||
|
model=Instituicao,
|
||||||
|
title="Instituicoes",
|
||||||
|
list_fields=("codigo_inep", "nome"),
|
||||||
|
search_fields=(("codigo_inep", "int"), ("nome", "icontains")),
|
||||||
|
),
|
||||||
|
"polos": CrudConfig(
|
||||||
|
slug="polos",
|
||||||
|
model=Polo,
|
||||||
|
title="Polos",
|
||||||
|
list_fields=("id", "codigo", "descricao"),
|
||||||
|
search_fields=(("id", "int"), ("codigo", "int"), ("descricao", "icontains")),
|
||||||
|
),
|
||||||
|
"pessoas": CrudConfig(
|
||||||
|
slug="pessoas",
|
||||||
|
model=Pessoa,
|
||||||
|
title="Pessoas",
|
||||||
|
list_fields=("id", "nome", "cpf", "data_nascimento", "nacionalidade"),
|
||||||
|
search_fields=(
|
||||||
|
("id", "int"),
|
||||||
|
("nome", "icontains"),
|
||||||
|
("cpf", "icontains"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"vinculos": CrudConfig(
|
||||||
|
slug="vinculos",
|
||||||
|
model=Vinculo,
|
||||||
|
title="Vinculos",
|
||||||
|
list_fields=("id", "pessoa", "curso", "ano_censo", "situacao"),
|
||||||
|
search_fields=(
|
||||||
|
("id", "int"),
|
||||||
|
("matricula", "icontains"),
|
||||||
|
("pessoa__nome", "icontains"),
|
||||||
|
("pessoa__cpf", "icontains"),
|
||||||
|
("curso__descricao", "icontains"),
|
||||||
|
("curso__codigo_mec", "int"),
|
||||||
|
("ano_censo", "int"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
CRUD_LINKS = tuple(CRUD_CONFIGS.values())
|
||||||
|
|
||||||
|
|
||||||
|
class ImportAlunosForm(forms.Form):
|
||||||
|
ano_censo = forms.TypedChoiceField(coerce=int)
|
||||||
|
arquivo = forms.FileField()
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields["ano_censo"].choices = [
|
||||||
|
(ano.ano, ano.ano)
|
||||||
|
for ano in AnoCenso.objects.order_by("-ano")
|
||||||
|
]
|
||||||
|
self.fields["ano_censo"].widget.attrs["class"] = "form-select"
|
||||||
|
self.fields["arquivo"].widget.attrs["class"] = "form-control"
|
||||||
|
self.fields["arquivo"].widget.attrs["accept"] = ".txt,text/plain"
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessarSituacaoForm(forms.Form):
|
||||||
|
matriculas = forms.CharField(
|
||||||
|
label="Matricula",
|
||||||
|
widget=forms.Textarea,
|
||||||
|
)
|
||||||
|
situacao = forms.ChoiceField(
|
||||||
|
label="Situacao",
|
||||||
|
choices=Vinculo.Situacao.choices,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields["matriculas"].widget.attrs.update(
|
||||||
|
{
|
||||||
|
"class": "form-control",
|
||||||
|
"rows": 10,
|
||||||
|
"placeholder": "Informe uma ou mais matriculas",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.fields["situacao"].widget.attrs["class"] = "form-select"
|
||||||
|
|
||||||
|
def clean_matriculas(self) -> list[str]:
|
||||||
|
raw_value = self.cleaned_data["matriculas"]
|
||||||
|
matriculas = [
|
||||||
|
item.strip()
|
||||||
|
for item in re.split(r"[\s,;]+", raw_value)
|
||||||
|
if item.strip()
|
||||||
|
]
|
||||||
|
deduplicated = list(dict.fromkeys(matriculas))
|
||||||
|
if not deduplicated:
|
||||||
|
raise forms.ValidationError("Informe ao menos uma matricula.")
|
||||||
|
return deduplicated
|
||||||
|
|
||||||
|
|
||||||
|
def ano_ingresso(semestre_ingresso: str) -> int | None:
|
||||||
|
year = (semestre_ingresso or "")[-4:]
|
||||||
|
return int(year) if year.isdigit() else None
|
||||||
|
|
||||||
|
|
||||||
|
EXPORT_FILTERS: dict[str, dict[str, Any]] = {
|
||||||
|
"todos": {"label": "Todos", "situacao": None},
|
||||||
|
"ingressantes": {"label": "Apenas Ingressantes", "situacao": None},
|
||||||
|
"desvinculado": {"label": "Apenas Desvinculado", "situacao": Vinculo.Situacao.DESVINCULADO},
|
||||||
|
"cursando": {"label": "Apenas Cursando", "situacao": Vinculo.Situacao.CURSANDO},
|
||||||
|
"transferido": {
|
||||||
|
"label": "Apenas Transferido",
|
||||||
|
"situacao": Vinculo.Situacao.TRANSFERENCIA_INTERNA,
|
||||||
|
},
|
||||||
|
"falecido": {"label": "Apenas Falecido", "situacao": Vinculo.Situacao.FALECIDO},
|
||||||
|
"formado": {"label": "Apenas Formado", "situacao": Vinculo.Situacao.FORMADO},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def export_alunos_view(request: HttpRequest, filtro: str) -> HttpResponse:
|
||||||
|
config = EXPORT_FILTERS.get(filtro)
|
||||||
|
if config is None:
|
||||||
|
raise Http404("Filtro de exportacao desconhecido.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
ies_codigo = int(settings.CENSUP_IES_CODIGO)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
messages.error(request, "CENSUP_IES_CODIGO nao configurado.")
|
||||||
|
return redirect("home")
|
||||||
|
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
vinculos = Vinculo.objects.filter(ano_censo=selected_year)
|
||||||
|
if filtro == "ingressantes":
|
||||||
|
vinculos = vinculos.filter(semestre_ingresso__endswith=str(selected_year))
|
||||||
|
elif config["situacao"] is not None:
|
||||||
|
vinculos = vinculos.filter(situacao=config["situacao"])
|
||||||
|
|
||||||
|
vinculos = vinculos.select_related(
|
||||||
|
"pessoa",
|
||||||
|
"pessoa__uf_nascimento",
|
||||||
|
"pessoa__municipio_nascimento",
|
||||||
|
"pessoa__pais_origem",
|
||||||
|
"curso",
|
||||||
|
"curso_origem",
|
||||||
|
"polo",
|
||||||
|
"mobilidade_ies_destino",
|
||||||
|
"mobilidade_pais_destino",
|
||||||
|
).order_by("pessoa__nome", "pessoa_id")
|
||||||
|
|
||||||
|
content = build_aluno_export_file(vinculos, ies_codigo)
|
||||||
|
response = HttpResponse(content, content_type="text/plain; charset=utf-8")
|
||||||
|
filename = f"aluno_exportacao_{filtro}_{selected_year}.txt"
|
||||||
|
response["Content-Disposition"] = f'attachment; filename="{filename}"'
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def home(request: HttpRequest) -> HttpResponse:
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
rows_by_course: dict[int, dict[str, Any]] = {}
|
||||||
|
status_fields = {
|
||||||
|
Vinculo.Situacao.DESVINCULADO: "desvinculado",
|
||||||
|
Vinculo.Situacao.CURSANDO: "cursando",
|
||||||
|
Vinculo.Situacao.TRANSFERENCIA_INTERNA: "transferido",
|
||||||
|
Vinculo.Situacao.FALECIDO: "falecido",
|
||||||
|
Vinculo.Situacao.FORMADO: "formado",
|
||||||
|
}
|
||||||
|
vinculos = (
|
||||||
|
Vinculo.objects.filter(ano_censo=selected_year)
|
||||||
|
.select_related(
|
||||||
|
"curso",
|
||||||
|
"pessoa",
|
||||||
|
"pessoa__pais_origem",
|
||||||
|
"pessoa__uf_nascimento",
|
||||||
|
"pessoa__municipio_nascimento",
|
||||||
|
"polo",
|
||||||
|
)
|
||||||
|
.order_by("curso__descricao", "pessoa__nome")
|
||||||
|
)
|
||||||
|
|
||||||
|
for vinculo in vinculos:
|
||||||
|
row = rows_by_course.setdefault(
|
||||||
|
vinculo.curso_id,
|
||||||
|
{
|
||||||
|
"curso": vinculo.curso,
|
||||||
|
"desvinculado": 0,
|
||||||
|
"cursando": 0,
|
||||||
|
"transferido": 0,
|
||||||
|
"falecido": 0,
|
||||||
|
"formado": 0,
|
||||||
|
"pendente": 0,
|
||||||
|
"ingressantes": 0,
|
||||||
|
"total": 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
status_field = status_fields.get(vinculo.situacao)
|
||||||
|
if status_field:
|
||||||
|
row[status_field] += 1
|
||||||
|
if validate_vinculo(vinculo):
|
||||||
|
row["pendente"] += 1
|
||||||
|
if ano_ingresso(vinculo.semestre_ingresso) == selected_year:
|
||||||
|
row["ingressantes"] += 1
|
||||||
|
row["total"] += 1
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/home.html",
|
||||||
|
{
|
||||||
|
"selected_year": selected_year,
|
||||||
|
"course_rows": rows_by_course.values(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def set_ano_censo(request: HttpRequest) -> HttpResponse:
|
||||||
|
if request.method == "POST":
|
||||||
|
try:
|
||||||
|
ano_censo = int(request.POST.get("ano_censo", ""))
|
||||||
|
except ValueError:
|
||||||
|
messages.error(request, "Ano do censo invalido.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
set_selected_ano_censo(request, ano_censo)
|
||||||
|
except ValueError:
|
||||||
|
messages.error(request, "Ano do censo nao cadastrado.")
|
||||||
|
else:
|
||||||
|
messages.success(request, f"Ano de trabalho alterado para {ano_censo}.")
|
||||||
|
|
||||||
|
next_url = request.POST.get("next") or reverse("home")
|
||||||
|
if not url_has_allowed_host_and_scheme(
|
||||||
|
next_url,
|
||||||
|
allowed_hosts={request.get_host()},
|
||||||
|
require_https=request.is_secure(),
|
||||||
|
):
|
||||||
|
next_url = reverse("home")
|
||||||
|
return redirect(next_url)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def import_alunos_view(request: HttpRequest) -> HttpResponse:
|
||||||
|
result = None
|
||||||
|
form = ImportAlunosForm(request.POST or None, request.FILES or None)
|
||||||
|
if request.method != "POST":
|
||||||
|
form.fields["ano_censo"].initial = get_selected_ano_censo(request)
|
||||||
|
|
||||||
|
if request.method == "POST" and form.is_valid():
|
||||||
|
uploaded_file = form.cleaned_data["arquivo"]
|
||||||
|
content = uploaded_file.read().decode("utf-8-sig")
|
||||||
|
result = import_alunos(
|
||||||
|
lines=content.splitlines(),
|
||||||
|
ano_censo=form.cleaned_data["ano_censo"],
|
||||||
|
)
|
||||||
|
messages.success(request, "Importacao processada.")
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/import_alunos.html",
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"result": result,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_task_active(task_id: str) -> bool:
|
||||||
|
if not task_id:
|
||||||
|
return False
|
||||||
|
return AsyncResult(task_id).state in {"PENDING", "STARTED", "PROGRESS", "RETRY"}
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def task_page_view(request: HttpRequest, operacao: str) -> HttpResponse:
|
||||||
|
config = TASK_OPERATIONS.get(operacao)
|
||||||
|
if config is None:
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
raise Http404("Operacao desconhecida")
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/task_page.html",
|
||||||
|
{
|
||||||
|
"operacao": operacao,
|
||||||
|
"label": config["label"],
|
||||||
|
"task_id": request.session.get(f"task_id:{operacao}", ""),
|
||||||
|
"selected_year": get_selected_ano_censo(request),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def start_task_view(request: HttpRequest, operacao: str) -> HttpResponse:
|
||||||
|
config = TASK_OPERATIONS.get(operacao)
|
||||||
|
if config is None:
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
raise Http404("Operacao desconhecida")
|
||||||
|
if request.method != "POST":
|
||||||
|
return HttpResponseNotAllowed(["POST"])
|
||||||
|
|
||||||
|
session_key = f"task_id:{operacao}"
|
||||||
|
existing_task_id = request.session.get(session_key, "")
|
||||||
|
if is_task_active(existing_task_id):
|
||||||
|
return JsonResponse({"task_id": existing_task_id, "already_running": True})
|
||||||
|
|
||||||
|
page_size = int(request.POST.get("page_size") or 100)
|
||||||
|
threads = int(request.POST.get("threads") or 4)
|
||||||
|
|
||||||
|
if operacao == "pessoas-ingressantes":
|
||||||
|
primeiro_ano = int(
|
||||||
|
request.POST.get("primeiro_ano") or get_selected_ano_censo(request)
|
||||||
|
)
|
||||||
|
async_result = config["task"].delay(primeiro_ano=primeiro_ano, page_size=page_size)
|
||||||
|
elif operacao == "vinculos-censup":
|
||||||
|
ano = int(request.POST.get("ano") or get_selected_ano_censo(request))
|
||||||
|
async_result = config["task"].delay(ano=ano, page_size=page_size, threads=threads)
|
||||||
|
else:
|
||||||
|
async_result = config["task"].delay(page_size=page_size, threads=threads)
|
||||||
|
|
||||||
|
request.session[session_key] = async_result.id
|
||||||
|
return JsonResponse({"task_id": async_result.id, "already_running": False})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def task_status_view(request: HttpRequest, task_id: str) -> HttpResponse:
|
||||||
|
result = AsyncResult(task_id)
|
||||||
|
data: dict[str, Any] = {"state": result.state}
|
||||||
|
if result.state == "PROGRESS":
|
||||||
|
data["meta"] = result.info
|
||||||
|
elif result.state == "SUCCESS":
|
||||||
|
data["result"] = result.result
|
||||||
|
elif result.state == "FAILURE":
|
||||||
|
data["error"] = str(result.info)
|
||||||
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def processar_situacao_view(request: HttpRequest) -> HttpResponse:
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
result = None
|
||||||
|
form = ProcessarSituacaoForm(request.POST or None)
|
||||||
|
|
||||||
|
if request.method == "POST" and form.is_valid():
|
||||||
|
matriculas = form.cleaned_data["matriculas"]
|
||||||
|
situacao = form.cleaned_data["situacao"]
|
||||||
|
vinculos = Vinculo.objects.filter(
|
||||||
|
ano_censo=selected_year,
|
||||||
|
matricula__in=matriculas,
|
||||||
|
)
|
||||||
|
found_matriculas = set(vinculos.values_list("matricula", flat=True))
|
||||||
|
updated = vinculos.update(situacao=situacao)
|
||||||
|
result = {
|
||||||
|
"updated": updated,
|
||||||
|
"requested": len(matriculas),
|
||||||
|
"not_found": [
|
||||||
|
matricula
|
||||||
|
for matricula in matriculas
|
||||||
|
if matricula not in found_matriculas
|
||||||
|
],
|
||||||
|
"situacao": dict(Vinculo.Situacao.choices).get(int(situacao), situacao),
|
||||||
|
"ano_censo": selected_year,
|
||||||
|
}
|
||||||
|
messages.success(request, "Situacao processada.")
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/processar_situacao.html",
|
||||||
|
{
|
||||||
|
"form": form,
|
||||||
|
"result": result,
|
||||||
|
"selected_year": selected_year,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def crud_list(request: HttpRequest, slug: str) -> HttpResponse:
|
||||||
|
config = get_crud_config(slug)
|
||||||
|
query = request.GET.get("q", "").strip()
|
||||||
|
queryset = config.model.objects.all()
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
|
||||||
|
if config.model is Vinculo:
|
||||||
|
queryset = queryset.filter(ano_censo=selected_year)
|
||||||
|
|
||||||
|
if query:
|
||||||
|
queryset = queryset.filter(build_search_query(config, query))
|
||||||
|
|
||||||
|
paginator = Paginator(queryset, 20)
|
||||||
|
page_obj = paginator.get_page(request.GET.get("page"))
|
||||||
|
rows = [
|
||||||
|
{
|
||||||
|
"object": obj,
|
||||||
|
"values": [format_list_field_value(obj, field) for field in config.list_fields],
|
||||||
|
}
|
||||||
|
for obj in page_obj.object_list
|
||||||
|
]
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/crud/list.html",
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"query": query,
|
||||||
|
"page_obj": page_obj,
|
||||||
|
"rows": rows,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def crud_detail(request: HttpRequest, slug: str, pk: str) -> HttpResponse:
|
||||||
|
config = get_crud_config(slug)
|
||||||
|
obj = get_object_or_404(config.model, pk=pk)
|
||||||
|
vinculo_navigation = vinculo_person_navigation(obj) if isinstance(obj, Vinculo) else None
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/crud/detail.html",
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"object": obj,
|
||||||
|
"fields": object_fields(obj),
|
||||||
|
"vinculo_navigation": vinculo_navigation,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def crud_create(request: HttpRequest, slug: str) -> HttpResponse:
|
||||||
|
config = get_crud_config(slug)
|
||||||
|
form_class = build_model_form(config.model)
|
||||||
|
form = form_class(request.POST or None)
|
||||||
|
|
||||||
|
if request.method == "POST" and form.is_valid():
|
||||||
|
obj = form.save()
|
||||||
|
messages.success(request, f"{config.title} salvo com sucesso.")
|
||||||
|
return redirect("crud_detail", slug=slug, pk=obj.pk)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/crud/form.html",
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"form": form,
|
||||||
|
"action": "Criar",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def crud_update(request: HttpRequest, slug: str, pk: str) -> HttpResponse:
|
||||||
|
config = get_crud_config(slug)
|
||||||
|
obj = get_object_or_404(config.model, pk=pk)
|
||||||
|
form_class = build_model_form(config.model)
|
||||||
|
form = form_class(request.POST or None, instance=obj)
|
||||||
|
|
||||||
|
if request.method == "POST" and form.is_valid():
|
||||||
|
obj = form.save()
|
||||||
|
messages.success(request, f"{config.title} atualizado com sucesso.")
|
||||||
|
return redirect("crud_detail", slug=slug, pk=obj.pk)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/crud/form.html",
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"form": form,
|
||||||
|
"object": obj,
|
||||||
|
"action": "Editar",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def crud_delete(request: HttpRequest, slug: str, pk: str) -> HttpResponse:
|
||||||
|
config = get_crud_config(slug)
|
||||||
|
obj = get_object_or_404(config.model, pk=pk)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
obj.delete()
|
||||||
|
messages.success(request, f"{config.title} excluido com sucesso.")
|
||||||
|
return redirect("crud_list", slug=slug)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/crud/confirm_delete.html",
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"object": obj,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def pending_required_fields(request: HttpRequest) -> HttpResponse:
|
||||||
|
pending = []
|
||||||
|
selected_year = get_selected_ano_censo(request)
|
||||||
|
for config in CRUD_LINKS:
|
||||||
|
queryset = config.model.objects.all()
|
||||||
|
if config.model is Vinculo:
|
||||||
|
queryset = queryset.filter(ano_censo=selected_year)
|
||||||
|
|
||||||
|
for obj in queryset:
|
||||||
|
missing = missing_required_fields(obj)
|
||||||
|
if missing:
|
||||||
|
pending.append(
|
||||||
|
{
|
||||||
|
"config": config,
|
||||||
|
"object": obj,
|
||||||
|
"missing": missing,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
paginator = Paginator(pending, 20)
|
||||||
|
page_obj = paginator.get_page(request.GET.get("page"))
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"core/pending_required_fields.html",
|
||||||
|
{
|
||||||
|
"page_obj": page_obj,
|
||||||
|
"total_pending": len(pending),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_crud_config(slug: str) -> CrudConfig:
|
||||||
|
return get_object_or_404_config(slug)
|
||||||
|
|
||||||
|
|
||||||
|
def get_object_or_404_config(slug: str) -> CrudConfig:
|
||||||
|
config = CRUD_CONFIGS.get(slug)
|
||||||
|
if config is None:
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
raise Http404("Cadastro nao encontrado")
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def build_search_query(config: CrudConfig, query: str) -> Q:
|
||||||
|
filters = Q()
|
||||||
|
for field, lookup in config.search_fields:
|
||||||
|
if lookup == "int":
|
||||||
|
if query.isdigit():
|
||||||
|
filters |= Q(**{field: int(query)})
|
||||||
|
else:
|
||||||
|
filters |= Q(**{f"{field}__{lookup}": query})
|
||||||
|
return filters
|
||||||
|
|
||||||
|
|
||||||
|
def build_model_form(model: type[Model]) -> type[forms.ModelForm]:
|
||||||
|
form_class = modelform_factory(model, fields="__all__")
|
||||||
|
|
||||||
|
class StyledForm(form_class):
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
for field in self.fields.values():
|
||||||
|
css_class = "form-check-input" if isinstance(
|
||||||
|
field.widget,
|
||||||
|
forms.CheckboxInput,
|
||||||
|
) else "form-control"
|
||||||
|
current_class = field.widget.attrs.get("class", "")
|
||||||
|
field.widget.attrs["class"] = f"{current_class} {css_class}".strip()
|
||||||
|
|
||||||
|
return StyledForm
|
||||||
|
|
||||||
|
|
||||||
|
def format_field_value(obj: Model, field: str) -> Any:
|
||||||
|
value = getattr(obj, field)
|
||||||
|
display_method = getattr(obj, f"get_{field}_display", None)
|
||||||
|
if callable(display_method):
|
||||||
|
return display_method()
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def format_list_field_value(obj: Model, field: str) -> dict[str, Any]:
|
||||||
|
raw_value = getattr(obj, field)
|
||||||
|
is_status = isinstance(obj, Curso) and field == "situacao_funcionamento_curso"
|
||||||
|
return {
|
||||||
|
"value": format_field_value(obj, field),
|
||||||
|
"is_boolean": isinstance(raw_value, bool),
|
||||||
|
"is_status": is_status,
|
||||||
|
"status_class": course_status_class(raw_value) if is_status else "",
|
||||||
|
"raw": raw_value,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def course_status_class(value: str) -> str:
|
||||||
|
normalized = str(value or "").strip().lower()
|
||||||
|
if normalized == "em atividade":
|
||||||
|
return "bg-green-lt text-green"
|
||||||
|
if normalized == "em extinção" or normalized == "em extincao":
|
||||||
|
return "bg-yellow-lt text-yellow"
|
||||||
|
return "bg-secondary-lt text-secondary"
|
||||||
|
|
||||||
|
|
||||||
|
def object_fields(obj: Model) -> list[tuple[str, Any]]:
|
||||||
|
fields = []
|
||||||
|
for field in obj._meta.fields:
|
||||||
|
value = format_field_value(obj, field.name)
|
||||||
|
fields.append((field.verbose_name.title(), value))
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
|
def vinculo_person_navigation(vinculo: Vinculo) -> dict[str, Any]:
|
||||||
|
vinculos = list(
|
||||||
|
Vinculo.objects.filter(pessoa=vinculo.pessoa)
|
||||||
|
.select_related("curso", "pessoa")
|
||||||
|
.order_by("-ano_censo", "curso__descricao", "id")
|
||||||
|
)
|
||||||
|
current_index = next(
|
||||||
|
(
|
||||||
|
index
|
||||||
|
for index, pessoa_vinculo in enumerate(vinculos)
|
||||||
|
if pessoa_vinculo.pk == vinculo.pk
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
previous_vinculo = None
|
||||||
|
next_vinculo = None
|
||||||
|
if current_index is not None:
|
||||||
|
if current_index > 0:
|
||||||
|
previous_vinculo = vinculos[current_index - 1]
|
||||||
|
if current_index < len(vinculos) - 1:
|
||||||
|
next_vinculo = vinculos[current_index + 1]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"pessoa": vinculo.pessoa,
|
||||||
|
"vinculos": vinculos,
|
||||||
|
"previous": previous_vinculo,
|
||||||
|
"next": next_vinculo,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def missing_required_fields(obj: Model) -> list[str]:
|
||||||
|
missing = []
|
||||||
|
for field in obj._meta.fields:
|
||||||
|
if field.primary_key or field.auto_created or field.blank or field.null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
value = getattr(obj, field.name)
|
||||||
|
if value is None or value == "":
|
||||||
|
missing.append(field.verbose_name.title())
|
||||||
|
|
||||||
|
if isinstance(obj, Curso) and obj.carga_horaria_total == 0:
|
||||||
|
missing.append("Carga Horaria Total")
|
||||||
|
|
||||||
|
return missing
|
||||||
|
|
||||||
|
|
||||||
|
def crud_list_url(slug: str) -> str:
|
||||||
|
return reverse("crud_list", kwargs={"slug": slug})
|
||||||
43
core/year.py
Normal file
43
core/year.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from django.http import HttpRequest
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from .models import AnoCenso
|
||||||
|
|
||||||
|
SESSION_KEY = "ano_censo"
|
||||||
|
|
||||||
|
|
||||||
|
def default_ano_censo() -> int:
|
||||||
|
configured_year = (
|
||||||
|
AnoCenso.objects.order_by("-ano")
|
||||||
|
.values_list("ano", flat=True)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return configured_year or timezone.localdate().year - 1
|
||||||
|
|
||||||
|
|
||||||
|
def available_anos_censo() -> list[int]:
|
||||||
|
years = list(AnoCenso.objects.order_by("-ano").values_list("ano", flat=True))
|
||||||
|
return years or [default_ano_censo()]
|
||||||
|
|
||||||
|
|
||||||
|
def get_selected_ano_censo(request: HttpRequest) -> int:
|
||||||
|
raw_value = request.session.get(SESSION_KEY)
|
||||||
|
try:
|
||||||
|
selected_year = int(raw_value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
selected_year = default_ano_censo()
|
||||||
|
request.session[SESSION_KEY] = selected_year
|
||||||
|
return selected_year
|
||||||
|
|
||||||
|
if AnoCenso.objects.filter(ano=selected_year).exists():
|
||||||
|
return selected_year
|
||||||
|
|
||||||
|
selected_year = default_ano_censo()
|
||||||
|
request.session[SESSION_KEY] = selected_year
|
||||||
|
return selected_year
|
||||||
|
|
||||||
|
|
||||||
|
def set_selected_ano_censo(request: HttpRequest, ano_censo: int) -> None:
|
||||||
|
if not AnoCenso.objects.filter(ano=ano_censo).exists():
|
||||||
|
raise ValueError("Ano do censo nao cadastrado.")
|
||||||
|
request.session[SESSION_KEY] = ano_censo
|
||||||
34
docker-compose.yml
Normal file
34
docker-compose.yml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: autocensup
|
||||||
|
POSTGRES_USER: autocensup
|
||||||
|
POSTGRES_PASSWORD: autocensup
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U autocensup -d autocensup"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
valkey:
|
||||||
|
image: valkey/valkey:8-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- valkey_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "valkey-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
valkey_data:
|
||||||
2322
docs/REGRAS_ARQUIVO_ALUNO.md
Normal file
2322
docs/REGRAS_ARQUIVO_ALUNO.md
Normal file
File diff suppressed because it is too large
Load Diff
9584
docs/aluno_exportacao.txt
Normal file
9584
docs/aluno_exportacao.txt
Normal file
File diff suppressed because it is too large
Load Diff
55
docs/cursos.csv
Normal file
55
docs/cursos.csv
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
CODIGO_IES;NOME_IES;CODIGO_CURSO;NOME_CURSO;TEM_ALUNO_VINCULADO;MOTIVO_NAO_POSSUI_ALUNO;CODIGO_CURSO_TITULAR;NOME_CURSO_TITULAR;CURSO_ATUALIZADO;SITUACAO_FUNCIONAMENTO_CURSO;DT_INICIO_FUNCIONAMENTO;FORMATO_OFERTA;GRAU_ACADEMICO;NIVEL_ACADEMICO;ATRIBUTO_INGRESSO;CURSO_GRATUITO;ROTULO_CLASSIFICACAO_CINE;CURSO_FINANCIADO_CONVENIO;PRAZ_INTEG_MATUTINO;PRAZ_INTEG_VESPERTINO;PRAZ_INTEG_NOTURNO;PRAZ_INTEG_INTEGRAL;PRAZ_INTEG_EAD;VAGA_NOVA_MATUTINO;VAGA_NOVA_VESPERTINO;VAGA_NOVA_NOTURNO;VAGA_NOVA_INTEGRAL;VAGA_NOVA_EAD;VAGA_REMANESCENTE_MATUTINO;VAGA_REMANESCENTE_VESPERTINO;VAGA_REMANESCENTE_NOTURNO;VAGA_REMANESCENTE_INTEGRAL;VAGA_REMANESCENTE_EAD;VAGA_PROGESP_MATUTINO;VAGA_PROGESP_VESPERTINO;VAGA_PROGESP_NOTURNO;VAGA_PROGESP_INTEGRAL;VAGA_PROGESP_EAD;CAND_NOVA_MATUTINO;CAND_NOVA_VESPERTINO;CAND_NOVA_NOTURNO;CAND_NOVA_INTEGRAL;CAND_NOVA_EAD;CAND_REMANESCENTE_MATUTINO;CAND_REMANESCENTE_VESPERTINO;CAND_REMANESCENTE_NOTURNO;CAND_REMANESCENTE_INTEGRAL;CAND_REMANESCENTE_EAD;CAND_PROGESPMATUTINO;CAND_PROGESPVESPERTINO;CAND_PROGESPNOTURNO;CAND_PROGESPINTEGRAL;CAND_PROGESPEAD;OFERECE_DISCIPLINA_EAD;PERCENTUAL_EAD;CONDICOES_PCD;GUIA_INTERPRETE;MATERIAL_AUDIO;MATERIAL_BRAILE;MATERIAL_PEDAGOGICO_TATIL;MATERIAL_DID_DIG_ACESSIVEL;RECURSO_INFORMATICA_ACESSIVEL;RECURSOS_ACESS_COMUNICACAO;MATERIAL_DIDATICO_LIBRAS;MATERIAL_DID_IMP_ACESSIVEL;TRADUTOR_INTERPRETE_LIBRAS;MATERIAL_IMP_CARACTER_AMPLIADO;DISCIPLINA_LIBRAS_OFERTADA;HORARIO_RELATORIO
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1675405;ENGENHARIA DE SOFTWARE;Sim;;;;Validação de dados concluída;Em atividade;2024-05-16 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0613E01;;5;;;;;100;;;;;10;;;;;0;;;;;1741;;;;;10;;;;;0;;;;;Não;;Sim;;Sim;;;Sim;Sim;Sim;;;;;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1621019;MEDICINA;Sim;;;;Validação de dados concluída;Em atividade;2024-07-05 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0912M01;;;;;9;;;;;72;;;;;12;;;;;0;;;;;698;;;;;0;;;;;0;;Não;;Sim;;;;;Sim;Sim;Sim;;Sim;;;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;96361;NUTRIÇÃO;Sim;;;;Validação de dados concluída;Em atividade;2007-02-12 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0915N01;;;4;;;;;100;;;;;20;;;;;0;;;;;818;;;;;20;;;;;0;;;;Não;;Sim;Não;Não;Sim;Sim;Sim;Sim;Sim;Não;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1353263;ODONTOLOGIA;Sim;;;;Validação de dados concluída;Em atividade;2017-11-27 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0911O01;;;;;5;;;;;172;;;;;40;;;;;0;;;;;1763;;;;;40;;;;;0;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Sim;;;;Validação de dados concluída;Em atividade;2021-04-03 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0612G01;;;;;;2.5;;;;;200;;;;;0;;;;;0;;;;;710;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em extinção;;EaD;Licenciatura;Graduação;Normal;Não;0113P01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Sim;;;;Validação de dados concluída;Em extinção;2020-03-09 00:00:00;EaD;Licenciatura;Graduação;Normal;Não;0113P01;;;;;;4;;;;;200;;;;;0;;;;;0;;;;;912;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;18147;PSICOLOGIA;Sim;;;;Validação de dados concluída;Em atividade;1998-10-05 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0313P01;;;4;4;;;;146;50;;;;10;0;;;;0;0;;;;1658;12;;;;10;0;;;;0;0;;;Sim;20;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;116722;SERVIÇO SOCIAL;Não;Curso extinto;;;Validação de dados concluída;Em extinção;2009-02-09 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0923S01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Sim;;;;Validação de dados concluída;Em extinção;2020-03-09 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0923S01;;;;;;4;;;;;200;;;;;20;;;;;0;;;;;603;;;;;20;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Sim;;;;Validação de dados concluída;Em atividade;2021-10-01 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0416G01;;;;;;2;;;;;100;;;;;0;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Sim;;;;Validação de dados concluída;Em extinção;2021-09-29 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0914B01;;;;;;4;;;;;200;;;;;20;;;;;0;;;;;810;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;54906;NORMAL SUPERIOR;Não;Curso extinto;;;Validação de dados concluída;Em extinção;2002-08-28 00:00:00;Presencial;Licenciatura;Graduação;Normal;Não;0113P01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1130233;ENGENHARIA CIVIL;Sim;;;;Validação de dados concluída;Em atividade;2011-08-04 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0732E01;;;5;5;;;;100;100;;;;0;10;;;;0;0;;;;0;829;;;;0;10;;;;0;0;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1130234;ENGENHARIA ELÉTRICA;Sim;;;;Validação de dados concluída;Em atividade;2012-02-07 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0713E05;;;5;5;;;;50;50;;;;2;15;;;;0;0;;;;0;808;;;;0;15;;;;0;0;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0413G07;;;;;;2;;;;;200;;;;;20;;;;;0;;;;;732;;;;;5;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0412G01;;;;;;2;;;;;200;;;;;20;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0413L01;;;;;;2.5;;;;;200;;;;;20;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0414M01;;;;;;2;;;;;200;;;;;20;;;;;0;;;;;648;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0613S01;;;;;;3;;;;;200;;;;;20;;;;;0;;;;;689;;;;;20;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;Não;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Sim;;;;Validação de dados concluída;Em extinção;2021-02-15 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;1012E01;;;;;;2.5;;;;;200;;;;;0;;;;;0;;;;;762;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0612R01;;;;;;3;;;;;200;;;;;0;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Sim;;;;Validação de dados concluída;Em extinção;2020-03-09 00:00:00;EaD;Tecnológico;Graduação;Normal;Não;0712G01;;;;;;2;;;;;200;;;;;0;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;105972;ENGENHARIA DE PRODUÇÃO;Sim;;;;Validação de dados concluída;Em atividade;2008-02-11 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0725E02;;;5;5;;;;50;50;;;;0;0;;;;0;0;;;;0;0;;;;0;0;;;;0;0;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Sim;;;;Validação de dados concluída;Em extinção;2020-03-09 00:00:00;EaD;Licenciatura;Graduação;Normal;Não;0115L13;;;;;;4;;;;;200;;;;;0;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1323598;ARQUITETURA E URBANISMO;Sim;;;;Validação de dados concluída;Em atividade;2017-05-03 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0731A02;;;5;5;;;;100;50;;;;18;0;;;;0;0;;;;795;0;;;;18;0;;;;0;0;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1474800;ESTÉTICA E COSMÉTICA;Sim;;;;Validação de dados concluída;Em atividade;2019-03-26 00:00:00;Presencial;Tecnológico;Graduação;Normal;Não;1012E01;;2.5;;;;;100;;;;;10;;;;;0;;;;;964;;;;;10;;;;;0;;;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Sim;;;;Validação de dados concluída;Em extinção;2021-03-05 00:00:00;EaD;Licenciatura;Graduação;Normal;Não;0114M01;;;;;;4;;;;;200;;;;;0;;;;;0;;;;;0;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1572090;MEDICINA VETERINÁRIA;Sim;;;;Validação de dados concluída;Em atividade;2021-02-22 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0841M01;;5;;;;;120;;;;;12;;;;;0;;;;;1484;;;;;12;;;;;0;;;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;48242;ADMINISTRAÇÃO;Sim;;;;Validação de dados concluída;Em atividade;2001-08-13 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0413A01;;4;;4;;;80;;80;;;10;;10;;;0;;0;;;758;;561;;;10;;10;;;0;;0;;;Sim;20;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Não;Curso representado por outro código de curso;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;;EaD;Bacharelado;Graduação;Normal;Não;0413A01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Sim;;;;Validação de dados concluída;Em extinção;2021-03-15 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0713E05;;;;;;5;;;;;200;;;;;10;;;;;0;;;;;341;;;;;10;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Sim;;;;Validação de dados concluída;Em extinção;2021-04-30 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0732E01;;;;;;5;;;;;200;;;;;20;;;;;0;;;;;306;;;;;0;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Sim;;;;Validação de dados concluída;Em extinção;2021-03-05 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0915N01;;;;;;4;;;;;200;;;;;20;;;;;0;;;;;598;;;;;20;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Sim;;;;Validação de dados concluída;Em extinção;2021-03-29 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0915E01;;;;;;4;;;;;200;;;;;15;;;;;0;;;;;758;;;;;15;;;;;0;;;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em extinção;2021-03-08 00:00:00;EaD;Licenciatura;Graduação;Normal;Não;0114E03;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0413A01;;;;;;4;;;;;200;;;;;20;;;;;0;;;;;725;;;;;0;;;;;0;;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;Não;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;48239;CIÊNCIAS CONTÁBEIS;Sim;;;;Validação de dados concluída;Em atividade;2000-08-10 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0411C01;;4;;4;;;80;;80;;;10;;5;;;0;;0;;;945;;1187;;;10;;5;;;0;;0;;;Sim;20;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Sim;;;;Validação de dados concluída;Em atividade;2020-03-09 00:00:00;EaD;Bacharelado;Graduação;Normal;Não;0411C01;;;;;;4;;;;;200;;;;;25;;;;;0;;;;;831;;;;;25;;;;;0;;;Sim;Não;;Sim;Sim;Sim;Sim;Sim;Não;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;74246;COMUNICAÇÃO SOCIAL;Não;Curso extinto;;;Validação de dados concluída;Em extinção;2005-02-14 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0321C01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;55600;DIREITO;Sim;;;;Validação de dados concluída;Em atividade;2002-08-26 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0421D01;;;5;5;;;;80;80;;;;40;40;;;;0;0;;;;3297;783;;;;40;40;;;;0;0;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;5000011;EDUCAÇÃO FÍSICA;Sim;;;;Validação de dados concluída;Em atividade;2010-02-08 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0915E01;;;4;;;;;200;;;;;20;;;;;0;;;;;1061;;;;;20;;;;;0;;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;86830;ENFERMAGEM;Sim;;;;Validação de dados concluída;Em atividade;2006-02-06 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0913E01;;4.5;4.5;;;;100;100;;;;5;5;;;;0;0;;;;0;0;;;;5;5;;;;0;0;;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;108702;FARMÁCIA;Sim;;;;Validação de dados concluída;Em atividade;2008-03-03 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0916F01;;5;;;;;160;;;;;20;;;;;0;;;;;1644;;;;;20;;;;;0;;;;;Não;;Sim;;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;86832;FISIOTERAPIA;Sim;;;;Validação de dados concluída;Em atividade;2006-02-06 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0915F01;;4.5;;;;;100;;;;;20;;;;;0;;;;;1173;;;;;20;;;;;0;;;;;Não;;Sim;Não;Não;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0914B01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0915E01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Licenciatura;Graduação;Normal;Não;0113P01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0732E01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0915N01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0923S01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Bacharelado;Graduação;Normal;Não;0713E05;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1697901;TERAPIA OCUPACIONAL;Sim;;;;Validação de dados concluída;Em atividade;2025-02-28 00:00:00;Presencial;Bacharelado;Graduação;Normal;Não;0915T01;;2.5;;;;;80;;;;;20;;;;;0;;;;;525;;;;;20;;;;;0;;;;;Sim;20;Sim;;;Sim;Sim;Sim;Sim;Sim;;Sim;Sim;Sim;Sim;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Não;Curso ativo sem demanda;;;Validação de dados concluída;Em atividade;;Semipresencial;Tecnológico;Graduação;Normal;Não;1012E01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30-04-2026 15:39:50
|
||||||
|
215
docs/cursos_locais.csv
Normal file
215
docs/cursos_locais.csv
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
CODIGOIES;NOMEIES;CODIGOCURSO;NOMECURSO;CURSOATUALIZADO;SITFUNCIONAMENTOCURSO;FORMATO_OFERTA;GRAUACADEMICO;NIVELACADEMICO;ATRIBUTOINGRESSO;TEMALUNOVINCULADO;MOTIVONAOPOSSUIALUNO;CODIGOLOCALOFERTA;NOMELOCALOFERTA;NOMELOGRADOURO;NUMEROLOGRADOURO;COMPLEMENTOLOUGRADOURO;NOMEBAIRRO;CODIGOMUNICIPIO;CODIGOCEP;PAÍS;ENDERECONEAD;ENDERECOPOLO;ENDERECOREITORIA;ENDERECOPOLOUAB;ENDERECOUNIDADEACADEMICA;ENDERECOSEDE;ALUNOVINCULADO;HORARIORELATORIO
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1130233;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;48239;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1323598;ARQUITETURA E URBANISMO;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574830;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1705270;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Semipresencial;Tecnológico;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523533;GESTÃO FINANCEIRA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1556205;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1621019;MEDICINA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1708828;BIOMEDICINA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1697901;TERAPIA OCUPACIONAL;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1474800;ESTÉTICA E COSMÉTICA;Validação de dados concluída;Em atividade;Presencial;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523522;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523529;LOGÍSTICA;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702422;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1575411;GESTÃO DA TECNOLOGIA DA INFORMAÇÃO;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574074;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1675405;ENGENHARIA DE SOFTWARE;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523543;REDES DE COMPUTADORES;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;18147;PSICOLOGIA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;105972;ENGENHARIA DE PRODUÇÃO;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;5000011;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;96361;NUTRIÇÃO;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;74246;COMUNICAÇÃO SOCIAL;Validação de dados concluída;Em extinção;Presencial;Bacharelado;Graduação;Normal;Não;Curso extinto;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574798;NUTRIÇÃO;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;48242;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;86832;FISIOTERAPIA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595805;GESTÃO COMERCIAL;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523525;GESTÃO AMBIENTAL;Validação de dados concluída;Em extinção;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;108702;FARMÁCIA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701679;SERVIÇO SOCIAL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;116722;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;Presencial;Bacharelado;Graduação;Normal;Não;Curso extinto;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701678;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1374263;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Não;Curso representado por outro código de curso;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523515;ANÁLISE E DESENVOLVIMENTO DE SISTEMAS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;86830;ENFERMAGEM;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1130234;ENGENHARIA ELÉTRICA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523542;MARKETING;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523523;CIÊNCIAS CONTÁBEIS;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1353263;ODONTOLOGIA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1572090;MEDICINA VETERINÁRIA;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;55600;DIREITO;Validação de dados concluída;Em atividade;Presencial;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523521;ADMINISTRAÇÃO;Validação de dados concluída;Em atividade;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1702423;ENGENHARIA CIVIL;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574800;MATEMÁTICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1703931;PEDAGOGIA;Validação de dados concluída;Em atividade;Semipresencial;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523519;SERVIÇO SOCIAL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574569;ENGENHARIA CIVIL;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1373944;PEDAGOGIA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1595830;BIOMEDICINA;Validação de dados concluída;Em extinção;EaD;Bacharelado;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523528;GESTÃO DE RECURSOS HUMANOS;Validação de dados concluída;Em atividade;EaD;Tecnológico;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;1;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1701680;NUTRIÇÃO;Validação de dados concluída;Em atividade;Semipresencial;Bacharelado;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1523508;LETRAS - PORTUGUÊS;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Sim;;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;54906;NORMAL SUPERIOR;Validação de dados concluída;Em extinção;Presencial;Licenciatura;Graduação;Normal;Não;Curso extinto;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658275;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;UNIDADE - TERESINA - SAO PEDRO;Sao Pedro;2211001;64019625;Brasil;Não;Sim;Sim;Não;Sim;Sim;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;658976;UNIDADE - TERESINA - SAO PEDRO;Avenida Valter Alencar;665;-;Sao Pedro;2211001;64019625;Brasil;Não;Não;Sim;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076070;Anexo I;Avenida Barão de Gurguéia;2636;- até 1200 - lado par;Vermelha;2211001;64018290;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1076073;Anexo II;Avenida Professor Valter Alencar;855;Anexo II;São Pedro;2211001;64019625;Brasil;Não;Não;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079603;Christus Faculdade do Piauí;Rua Acelino Rezende;132;-;Fonte dos Matos;2208403;64260000;Brasil;Não;Sim;Não;Não;Sim;Não;0;30-04-2026 15:39:50
|
||||||
|
1131;CENTRO UNIVERSITÁRIO SANTO AGOSTINHO;1574973;EDUCAÇÃO FÍSICA;Validação de dados concluída;Em extinção;EaD;Licenciatura;Graduação;Normal;Não;Curso ativo sem demanda;1079719;Associação Teresinense de Ensino -ATE;Av. Presidente Vargas;02;-;Centro;2207702;64200970;Brasil;Não;Sim;Não;Não;Não;Não;0;30-04-2026 15:39:50
|
||||||
|
BIN
docs/leiaute_aluno_2025.xlsx
Normal file
BIN
docs/leiaute_aluno_2025.xlsx
Normal file
Binary file not shown.
BIN
docs/tabela_municipio_2025.xlsx
Normal file
BIN
docs/tabela_municipio_2025.xlsx
Normal file
Binary file not shown.
BIN
docs/tabela_paises_2025.xlsx
Normal file
BIN
docs/tabela_paises_2025.xlsx
Normal file
Binary file not shown.
BIN
docs/tabela_uf_2025.xlsx
Normal file
BIN
docs/tabela_uf_2025.xlsx
Normal file
Binary file not shown.
5
main.py
Normal file
5
main.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from manage import main
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
17
manage.py
Normal file
17
manage.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
11
pyproject.toml
Normal file
11
pyproject.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[project]
|
||||||
|
name = "autocensup"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Aplicacao Django com PostgreSQL"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"django>=5.2,<6.0",
|
||||||
|
"psycopg[binary]>=3.2,<4.0",
|
||||||
|
"celery[redis]>=5.4,<6.0",
|
||||||
|
]
|
||||||
284
templates/base.html
Normal file
284
templates/base.html
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="pt-br">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="description" content="Autocensup">
|
||||||
|
<title>{% block title %}Autocensup{% endblock %}</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/css/tabler.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css">
|
||||||
|
{% block styles %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/js/demo-theme.min.js"></script>
|
||||||
|
<div class="page">
|
||||||
|
<header class="navbar navbar-expand-md d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<button
|
||||||
|
class="navbar-toggler"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#navbar-menu"
|
||||||
|
aria-controls="navbar-menu"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="Alternar navegacao"
|
||||||
|
>
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
||||||
|
<a href="{% url 'home' %}" class="text-decoration-none">
|
||||||
|
Autocensup
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-nav flex-row order-md-last">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="nav-item me-2">
|
||||||
|
<form method="post" action="{% url 'set_ano_censo' %}" class="d-flex align-items-center gap-2">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="next" value="{{ request.get_full_path }}">
|
||||||
|
<label class="text-secondary text-nowrap mb-0" for="ano-censo-select">Ano</label>
|
||||||
|
<select
|
||||||
|
id="ano-censo-select"
|
||||||
|
name="ano_censo"
|
||||||
|
class="form-select form-select-sm w-auto"
|
||||||
|
onchange="this.form.submit()"
|
||||||
|
>
|
||||||
|
{% for ano in available_anos_censo %}
|
||||||
|
<option value="{{ ano }}"{% if ano == selected_ano_censo %} selected{% endif %}>
|
||||||
|
{{ ano }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="nav-item">
|
||||||
|
<form method="post" action="{% url 'logout' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-outline-primary">
|
||||||
|
<i class="ti ti-logout me-2"></i>
|
||||||
|
Sair
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<header class="navbar-expand-md">
|
||||||
|
<div class="collapse navbar-collapse" id="navbar-menu">
|
||||||
|
<div class="navbar">
|
||||||
|
<div class="container-xl">
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'home' %}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-home"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Inicio</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a
|
||||||
|
class="nav-link dropdown-toggle"
|
||||||
|
href="#navbar-tabelas"
|
||||||
|
data-bs-toggle="dropdown"
|
||||||
|
data-bs-auto-close="outside"
|
||||||
|
role="button"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-database"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Tabelas</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a class="dropdown-item" href="{% url 'crud_list' 'anos-censo' %}">
|
||||||
|
<i class="ti ti-calendar-stats me-2"></i>
|
||||||
|
Anos do Censo
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'crud_list' 'ufs' %}">
|
||||||
|
<i class="ti ti-map-pin me-2"></i>
|
||||||
|
UFs
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'crud_list' 'municipios' %}">
|
||||||
|
<i class="ti ti-building-community me-2"></i>
|
||||||
|
Municipios
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'crud_list' 'fallbacks-cursos' %}">
|
||||||
|
<i class="ti ti-replace me-2"></i>
|
||||||
|
Fallbacks de Curso
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'crud_list' 'paises' %}">
|
||||||
|
<i class="ti ti-world me-2"></i>
|
||||||
|
Paises
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'crud_list' 'cursos' %}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-school"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Cursos</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'crud_list' 'pessoas' %}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-user"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Pessoas</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'crud_list' 'vinculos' %}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-link"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Vinculos</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'pending_required_fields' %}">
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-alert-triangle"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Pendencias</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a
|
||||||
|
class="nav-link dropdown-toggle"
|
||||||
|
href="#navbar-importacoes"
|
||||||
|
data-bs-toggle="dropdown"
|
||||||
|
data-bs-auto-close="outside"
|
||||||
|
role="button"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-upload"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Importacoes</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a class="dropdown-item" href="{% url 'import_alunos' %}">
|
||||||
|
<i class="ti ti-file-upload me-2"></i>
|
||||||
|
Importar Aluno do CENSUP
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'processar_situacao' %}">
|
||||||
|
<i class="ti ti-list-check me-2"></i>
|
||||||
|
Processar Situacao
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-divider"></div>
|
||||||
|
<a class="dropdown-item" href="{% url 'task_page' 'pessoas-ingressantes' %}">
|
||||||
|
<i class="ti ti-users-plus me-2"></i>
|
||||||
|
Pessoas Ingressantes
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'task_page' 'vinculos-censup' %}">
|
||||||
|
<i class="ti ti-link-plus me-2"></i>
|
||||||
|
Vinculos Censup
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'task_page' 'carga-horaria-censup' %}">
|
||||||
|
<i class="ti ti-clock-hour-4 me-2"></i>
|
||||||
|
Carga Horaria Censup
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a
|
||||||
|
class="nav-link dropdown-toggle"
|
||||||
|
href="#navbar-exportacoes"
|
||||||
|
data-bs-toggle="dropdown"
|
||||||
|
data-bs-auto-close="outside"
|
||||||
|
role="button"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||||
|
<i class="ti ti-download"></i>
|
||||||
|
</span>
|
||||||
|
<span class="nav-link-title">Exportacao</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'todos' %}">
|
||||||
|
<i class="ti ti-file-download me-2"></i>
|
||||||
|
Todos
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'ingressantes' %}">
|
||||||
|
<i class="ti ti-users-plus me-2"></i>
|
||||||
|
Apenas Ingressantes
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'desvinculado' %}">
|
||||||
|
<i class="ti ti-user-off me-2"></i>
|
||||||
|
Apenas Desvinculado
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'cursando' %}">
|
||||||
|
<i class="ti ti-school me-2"></i>
|
||||||
|
Apenas Cursando
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'transferido' %}">
|
||||||
|
<i class="ti ti-transfer me-2"></i>
|
||||||
|
Apenas Transferido
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'falecido' %}">
|
||||||
|
<i class="ti ti-cross me-2"></i>
|
||||||
|
Apenas Falecido
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-item" href="{% url 'export_alunos' 'formado' %}">
|
||||||
|
<i class="ti ti-certificate me-2"></i>
|
||||||
|
Apenas Formado
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<div class="page-header d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<div class="page-pretitle">{% block page_pretitle %}Sistema{% endblock %}</div>
|
||||||
|
<h1 class="page-title">{% block page_title %}Autocensup{% endblock %}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto ms-auto d-print-none">
|
||||||
|
{% block page_actions %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-body">
|
||||||
|
<main class="container-xl">
|
||||||
|
{% if messages %}
|
||||||
|
<div class="mb-3">
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-{{ message.tags|default:'info' }}" role="alert">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer footer-transparent d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="row text-center align-items-center flex-row-reverse">
|
||||||
|
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
|
||||||
|
<span class="text-secondary">Autocensup</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/js/tabler.min.js"></script>
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
templates/core/crud/confirm_delete.html
Normal file
23
templates/core/crud/confirm_delete.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Excluir {{ object }} | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}{{ config.title }}{% endblock %}
|
||||||
|
{% block page_title %}Excluir registro{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post" class="card">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
Confirma a exclusao de <strong>{{ object }}</strong>?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-end">
|
||||||
|
<a href="{% url 'crud_detail' config.slug object.pk %}" class="btn">Cancelar</a>
|
||||||
|
<button type="submit" class="btn btn-danger">
|
||||||
|
<i class="ti ti-trash me-2"></i>
|
||||||
|
Excluir
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
86
templates/core/crud/detail.html
Normal file
86
templates/core/crud/detail.html
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ object }} | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}{{ config.title }}{% endblock %}
|
||||||
|
{% block page_title %}{{ object }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_actions %}
|
||||||
|
<div class="btn-list">
|
||||||
|
<a href="{% url 'crud_list' config.slug %}" class="btn">
|
||||||
|
<i class="ti ti-arrow-left me-2"></i>
|
||||||
|
Voltar
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'crud_update' config.slug object.pk %}" class="btn btn-primary">
|
||||||
|
<i class="ti ti-pencil me-2"></i>
|
||||||
|
Editar
|
||||||
|
</a>
|
||||||
|
{% if vinculo_navigation.previous %}
|
||||||
|
<a href="{% url 'crud_detail' config.slug vinculo_navigation.previous.pk %}" class="btn">
|
||||||
|
<i class="ti ti-chevron-left me-2"></i>
|
||||||
|
Vínculo anterior
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if vinculo_navigation.next %}
|
||||||
|
<a href="{% url 'crud_detail' config.slug vinculo_navigation.next.pk %}" class="btn">
|
||||||
|
Próximo vínculo
|
||||||
|
<i class="ti ti-chevron-right ms-2"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table">
|
||||||
|
<tbody>
|
||||||
|
{% for label, value in fields %}
|
||||||
|
<tr>
|
||||||
|
<th class="w-25">{{ label }}</th>
|
||||||
|
<td>{{ value|default:"-" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if vinculo_navigation %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">Vínculos de {{ vinculo_navigation.pessoa }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Ano</th>
|
||||||
|
<th>Curso</th>
|
||||||
|
<th>Situação</th>
|
||||||
|
<th class="text-end">Ações</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for pessoa_vinculo in vinculo_navigation.vinculos %}
|
||||||
|
<tr {% if pessoa_vinculo.pk == object.pk %}class="table-active"{% endif %}>
|
||||||
|
<td>{{ pessoa_vinculo.ano_censo }}</td>
|
||||||
|
<td>{{ pessoa_vinculo.curso }}</td>
|
||||||
|
<td>{{ pessoa_vinculo.get_situacao_display }}</td>
|
||||||
|
<td class="text-end">
|
||||||
|
{% if pessoa_vinculo.pk == object.pk %}
|
||||||
|
<span class="badge bg-primary-lt">Atual</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'crud_detail' config.slug pessoa_vinculo.pk %}" class="btn btn-sm">
|
||||||
|
<i class="ti ti-arrow-right me-2"></i>
|
||||||
|
Ver vínculo
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
53
templates/core/crud/form.html
Normal file
53
templates/core/crud/form.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ action }} {{ config.title }} | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Cadastros{% endblock %}
|
||||||
|
{% block page_title %}{{ action }} {{ config.title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_actions %}
|
||||||
|
<a href="{% url 'crud_list' config.slug %}" class="btn">
|
||||||
|
<i class="ti ti-arrow-left me-2"></i>
|
||||||
|
Voltar
|
||||||
|
</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post" class="card">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="card-body">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="row">
|
||||||
|
{% for field in form %}
|
||||||
|
<div class="col-md-6 col-xl-4 mb-3">
|
||||||
|
{% if field.field.widget.input_type == "checkbox" %}
|
||||||
|
<label class="form-check mt-4">
|
||||||
|
{{ field }}
|
||||||
|
<span class="form-check-label">{{ field.label }}</span>
|
||||||
|
</label>
|
||||||
|
{% else %}
|
||||||
|
<label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||||
|
{{ field }}
|
||||||
|
{% endif %}
|
||||||
|
{% if field.help_text %}
|
||||||
|
<small class="form-hint">{{ field.help_text }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-end">
|
||||||
|
<a href="{% url 'crud_list' config.slug %}" class="btn">Cancelar</a>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="ti ti-device-floppy me-2"></i>
|
||||||
|
Salvar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
120
templates/core/crud/list.html
Normal file
120
templates/core/crud/list.html
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ config.title }} | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Cadastros{% endblock %}
|
||||||
|
{% block page_title %}{{ config.title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_actions %}
|
||||||
|
<a href="{% url 'crud_create' config.slug %}" class="btn btn-primary">
|
||||||
|
<i class="ti ti-plus me-2"></i>
|
||||||
|
Novo
|
||||||
|
</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row row-cards">
|
||||||
|
<div class="col-12">
|
||||||
|
<form method="get" class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="input-icon">
|
||||||
|
<span class="input-icon-addon">
|
||||||
|
<i class="ti ti-search"></i>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
name="q"
|
||||||
|
value="{{ query }}"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Pesquisar"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{% for field in config.list_fields %}
|
||||||
|
<th>{{ field }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
<th class="w-1"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in rows %}
|
||||||
|
<tr>
|
||||||
|
{% for item in row.values %}
|
||||||
|
<td>
|
||||||
|
{% if item.is_boolean %}
|
||||||
|
{% if item.raw %}
|
||||||
|
<span class="text-green" title="Sim">
|
||||||
|
<i class="ti ti-check"></i>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-secondary" title="Nao">-</span>
|
||||||
|
{% endif %}
|
||||||
|
{% elif item.is_status %}
|
||||||
|
{% if item.value %}
|
||||||
|
<span class="badge {{ item.status_class }}">{{ item.value }}</span>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{{ item.value|default:"-" }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
<td>
|
||||||
|
<div class="btn-list flex-nowrap">
|
||||||
|
<a href="{% url 'crud_detail' config.slug row.object.pk %}" class="btn btn-icon" aria-label="Ver">
|
||||||
|
<i class="ti ti-eye"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'crud_update' config.slug row.object.pk %}" class="btn btn-icon" aria-label="Editar">
|
||||||
|
<i class="ti ti-pencil"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'crud_delete' config.slug row.object.pk %}" class="btn btn-icon text-danger" aria-label="Excluir">
|
||||||
|
<i class="ti ti-trash"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="{{ config.list_fields|length|add:1 }}" class="text-center text-secondary">
|
||||||
|
Nenhum registro encontrado.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
|
<div class="card-footer d-flex align-items-center">
|
||||||
|
<p class="m-0 text-secondary">
|
||||||
|
Pagina {{ page_obj.number }} de {{ page_obj.paginator.num_pages }}
|
||||||
|
</p>
|
||||||
|
<ul class="pagination m-0 ms-auto">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?q={{ query }}&page={{ page_obj.previous_page_number }}">
|
||||||
|
<i class="ti ti-chevron-left"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?q={{ query }}&page={{ page_obj.next_page_number }}">
|
||||||
|
<i class="ti ti-chevron-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
59
templates/core/home.html
Normal file
59
templates/core/home.html
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Painel{% endblock %}
|
||||||
|
{% block page_title %}Vinculos por curso - {{ selected_year }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Curso</th>
|
||||||
|
<th class="text-end">Desvinculado</th>
|
||||||
|
<th class="text-end">Cursando</th>
|
||||||
|
<th class="text-end">Transferido</th>
|
||||||
|
<th class="text-end">Falecido</th>
|
||||||
|
<th class="text-end">Formado</th>
|
||||||
|
<th class="text-end">Pendente</th>
|
||||||
|
<th class="text-end">Ingressantes</th>
|
||||||
|
<th class="text-end">Quantidade de vinculos</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in course_rows %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'crud_list' 'vinculos' %}?q={{ row.curso.codigo_mec }}">
|
||||||
|
{{ row.curso.descricao }}
|
||||||
|
</a>
|
||||||
|
<div class="text-secondary small">{{ row.curso.codigo_mec }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">{{ row.desvinculado }}</td>
|
||||||
|
<td class="text-end">{{ row.cursando }}</td>
|
||||||
|
<td class="text-end">{{ row.transferido }}</td>
|
||||||
|
<td class="text-end">{{ row.falecido }}</td>
|
||||||
|
<td class="text-end">{{ row.formado }}</td>
|
||||||
|
<td class="text-end">
|
||||||
|
{% if row.pendente %}
|
||||||
|
<span class="badge bg-yellow-lt text-yellow">{{ row.pendente }}</span>
|
||||||
|
{% else %}
|
||||||
|
{{ row.pendente }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-end">{{ row.ingressantes }}</td>
|
||||||
|
<td class="text-end font-weight-medium">{{ row.total }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="9" class="text-center text-secondary">
|
||||||
|
Nenhum vinculo encontrado para o ano selecionado.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
98
templates/core/import_alunos.html
Normal file
98
templates/core/import_alunos.html
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Importar Aluno do CENSUP | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Importacao{% endblock %}
|
||||||
|
{% block page_title %}Importar Aluno do CENSUP{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row row-cards">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<form method="post" enctype="multipart/form-data" class="card">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="card-body">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">{{ form.non_field_errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.ano_censo.id_for_label }}">Ano do censo</label>
|
||||||
|
{{ form.ano_censo }}
|
||||||
|
{% for error in form.ano_censo.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.arquivo.id_for_label }}">Arquivo TXT</label>
|
||||||
|
{{ form.arquivo }}
|
||||||
|
{% for error in form.arquivo.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-end">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="ti ti-upload me-2"></i>
|
||||||
|
Importar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if result %}
|
||||||
|
<div class="col-lg-7">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">Resultado</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Pessoas criadas</div>
|
||||||
|
<div class="h1">{{ result.pessoas_created }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Pessoas atualizadas</div>
|
||||||
|
<div class="h1">{{ result.pessoas_updated }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Vinculos criados</div>
|
||||||
|
<div class="h1">{{ result.vinculos_created }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Vinculos atualizados</div>
|
||||||
|
<div class="h1">{{ result.vinculos_updated }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Linha</th>
|
||||||
|
<th>Tipo</th>
|
||||||
|
<th>Identificador</th>
|
||||||
|
<th>Erro</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for error in result.errors %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ error.line }}</td>
|
||||||
|
<td>{{ error.record_type }}</td>
|
||||||
|
<td>{{ error.identifier|default:"-" }}</td>
|
||||||
|
<td>{{ error.message }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center text-secondary">
|
||||||
|
Nenhum erro encontrado.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
68
templates/core/pending_required_fields.html
Normal file
68
templates/core/pending_required_fields.html
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Pendencias | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Verificacao{% endblock %}
|
||||||
|
{% block page_title %}Campos obrigatorios pendentes{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">{{ total_pending }} registro(s) com pendencia</h2>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Cadastro</th>
|
||||||
|
<th>Registro</th>
|
||||||
|
<th>Campos pendentes</th>
|
||||||
|
<th class="w-1"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in page_obj.object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.config.title }}</td>
|
||||||
|
<td>{{ item.object }}</td>
|
||||||
|
<td>{{ item.missing|join:", " }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'crud_update' item.config.slug item.object.pk %}" class="btn btn-icon" aria-label="Editar">
|
||||||
|
<i class="ti ti-pencil"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center text-secondary">
|
||||||
|
Nenhuma pendencia encontrada.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
|
<div class="card-footer d-flex align-items-center">
|
||||||
|
<p class="m-0 text-secondary">
|
||||||
|
Pagina {{ page_obj.number }} de {{ page_obj.paginator.num_pages }}
|
||||||
|
</p>
|
||||||
|
<ul class="pagination m-0 ms-auto">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">
|
||||||
|
<i class="ti ti-chevron-left"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}">
|
||||||
|
<i class="ti ti-chevron-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
92
templates/core/processar_situacao.html
Normal file
92
templates/core/processar_situacao.html
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Processar Situacao | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Processamento{% endblock %}
|
||||||
|
{% block page_title %}Processar Situacao - {{ selected_year }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row row-cards">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<form method="post" class="card">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="card-body">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">{{ form.non_field_errors }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.matriculas.id_for_label }}">Matricula</label>
|
||||||
|
{{ form.matriculas }}
|
||||||
|
{% for error in form.matriculas.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.situacao.id_for_label }}">Situacao</label>
|
||||||
|
{{ form.situacao }}
|
||||||
|
{% for error in form.situacao.errors %}
|
||||||
|
<div class="invalid-feedback d-block">{{ error }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-end">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<i class="ti ti-list-check me-2"></i>
|
||||||
|
Aplicar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if result %}
|
||||||
|
<div class="col-lg-7">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="card-title">Resultado</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Ano</div>
|
||||||
|
<div class="h1">{{ result.ano_censo }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Matriculas informadas</div>
|
||||||
|
<div class="h1">{{ result.requested }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Vinculos atualizados</div>
|
||||||
|
<div class="h1">{{ result.updated }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<div class="subheader">Situacao</div>
|
||||||
|
<div class="h3">{{ result.situacao }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-vcenter card-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Matricula nao encontrada</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for matricula in result.not_found %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ matricula }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center text-secondary">
|
||||||
|
Todas as matriculas informadas foram encontradas para o ano selecionado.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
172
templates/core/task_page.html
Normal file
172
templates/core/task_page.html
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ label }} | Autocensup{% endblock %}
|
||||||
|
{% block page_pretitle %}Tarefas assincronas{% endblock %}
|
||||||
|
{% block page_title %}{{ label }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% csrf_token %}
|
||||||
|
<div
|
||||||
|
id="task-app"
|
||||||
|
data-operacao="{{ operacao }}"
|
||||||
|
data-start-url="{% url 'start_task' operacao %}"
|
||||||
|
data-status-url-base="{% url 'task_status' 'PLACEHOLDER' %}"
|
||||||
|
data-initial-task-id="{{ task_id }}"
|
||||||
|
>
|
||||||
|
<div class="row row-cards">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
{% if operacao == "pessoas-ingressantes" %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="primeiro_ano">Ano de referencia</label>
|
||||||
|
<input type="number" id="primeiro_ano" class="form-control" value="{{ selected_year }}">
|
||||||
|
</div>
|
||||||
|
{% elif operacao == "vinculos-censup" %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="ano">Ano do censo</label>
|
||||||
|
<input type="number" id="ano" class="form-control" value="{{ selected_year }}">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<button id="btn-iniciar" type="button" class="btn btn-primary" {% if task_id %}disabled{% endif %}>
|
||||||
|
<i class="ti ti-player-play me-2"></i>
|
||||||
|
Iniciar
|
||||||
|
</button>
|
||||||
|
<span id="status-label" class="text-secondary ms-2"></span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body border-top">
|
||||||
|
<div class="progress mb-2" style="height: 1.5rem;">
|
||||||
|
<div
|
||||||
|
id="progress-bar"
|
||||||
|
class="progress-bar"
|
||||||
|
role="progressbar"
|
||||||
|
style="width: 0%"
|
||||||
|
>
|
||||||
|
<span id="progress-text"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="progress-message" class="text-secondary small"></div>
|
||||||
|
<div id="result-box" class="mt-3"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const app = document.getElementById("task-app");
|
||||||
|
const operacao = app.dataset.operacao;
|
||||||
|
const startUrl = app.dataset.startUrl;
|
||||||
|
const statusUrlBase = app.dataset.statusUrlBase;
|
||||||
|
let taskId = app.dataset.initialTaskId || null;
|
||||||
|
let polling = null;
|
||||||
|
|
||||||
|
const btn = document.getElementById("btn-iniciar");
|
||||||
|
const statusLabel = document.getElementById("status-label");
|
||||||
|
const progressBar = document.getElementById("progress-bar");
|
||||||
|
const progressText = document.getElementById("progress-text");
|
||||||
|
const progressMessage = document.getElementById("progress-message");
|
||||||
|
const resultBox = document.getElementById("result-box");
|
||||||
|
|
||||||
|
function getCsrfToken() {
|
||||||
|
const match = document.cookie.match(/csrftoken=([^;]+)/);
|
||||||
|
return match ? match[1] : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBusy(busy) {
|
||||||
|
btn.disabled = busy;
|
||||||
|
btn.innerHTML = busy
|
||||||
|
? '<i class="ti ti-loader-2 me-2"></i>Em andamento...'
|
||||||
|
: '<i class="ti ti-player-play me-2"></i>Iniciar';
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPolling() {
|
||||||
|
if (polling) {
|
||||||
|
clearInterval(polling);
|
||||||
|
polling = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProgress(data) {
|
||||||
|
if (data.state === "PROGRESS" && data.meta) {
|
||||||
|
const total = data.meta.total || 0;
|
||||||
|
const processed = data.meta.processed || 0;
|
||||||
|
const pct = total > 0 ? Math.round((processed / total) * 100) : 0;
|
||||||
|
progressBar.style.width = pct + "%";
|
||||||
|
progressText.textContent = pct + "%";
|
||||||
|
progressMessage.textContent =
|
||||||
|
processed + "/" + total + " - " + (data.meta.message || "");
|
||||||
|
statusLabel.textContent = "Em andamento";
|
||||||
|
setBusy(true);
|
||||||
|
} else if (data.state === "SUCCESS") {
|
||||||
|
progressBar.style.width = "100%";
|
||||||
|
progressText.textContent = "100%";
|
||||||
|
statusLabel.textContent = "Concluido";
|
||||||
|
setBusy(false);
|
||||||
|
resultBox.innerHTML =
|
||||||
|
'<pre class="bg-light p-2 rounded">' +
|
||||||
|
JSON.stringify(data.result, null, 2) +
|
||||||
|
"</pre>";
|
||||||
|
stopPolling();
|
||||||
|
} else if (data.state === "FAILURE") {
|
||||||
|
statusLabel.textContent = "Falhou";
|
||||||
|
setBusy(false);
|
||||||
|
resultBox.innerHTML =
|
||||||
|
'<div class="text-danger">' +
|
||||||
|
(data.error || "Erro desconhecido") +
|
||||||
|
"</div>";
|
||||||
|
stopPolling();
|
||||||
|
} else {
|
||||||
|
statusLabel.textContent = "Iniciando...";
|
||||||
|
setBusy(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function poll() {
|
||||||
|
fetch(statusUrlBase.replace("PLACEHOLDER", taskId))
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then(updateProgress)
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startPolling() {
|
||||||
|
poll();
|
||||||
|
polling = setInterval(poll, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
setBusy(true);
|
||||||
|
statusLabel.textContent = "Iniciando...";
|
||||||
|
const formData = new FormData();
|
||||||
|
if (operacao === "pessoas-ingressantes") {
|
||||||
|
formData.append(
|
||||||
|
"primeiro_ano",
|
||||||
|
document.getElementById("primeiro_ano").value
|
||||||
|
);
|
||||||
|
} else if (operacao === "vinculos-censup") {
|
||||||
|
formData.append("ano", document.getElementById("ano").value);
|
||||||
|
}
|
||||||
|
fetch(startUrl, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "X-CSRFToken": getCsrfToken() },
|
||||||
|
body: formData,
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
taskId = data.task_id;
|
||||||
|
if (data.already_running) {
|
||||||
|
statusLabel.textContent = "Ja em andamento - acompanhando...";
|
||||||
|
}
|
||||||
|
startPolling();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (taskId) {
|
||||||
|
startPolling();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
65
templates/registration/login.html
Normal file
65
templates/registration/login.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="pt-br">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Login | Autocensup</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/css/tabler.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/dist/tabler-icons.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="d-flex flex-column">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/js/demo-theme.min.js"></script>
|
||||||
|
<div class="page page-center">
|
||||||
|
<div class="container container-tight py-4">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="navbar-brand navbar-brand-autodark">Autocensup</h1>
|
||||||
|
</div>
|
||||||
|
<form class="card card-md" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h2 text-center mb-4">Entrar no sistema</h2>
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
Usuario ou senha invalidos.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if next %}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
{% endif %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.username.id_for_label }}">Usuario</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="{{ form.username.html_name }}"
|
||||||
|
id="{{ form.username.id_for_label }}"
|
||||||
|
class="form-control"
|
||||||
|
value="{{ form.username.value|default:'' }}"
|
||||||
|
autocomplete="username"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" for="{{ form.password.id_for_label }}">Senha</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="{{ form.password.html_name }}"
|
||||||
|
id="{{ form.password.id_for_label }}"
|
||||||
|
class="form-control"
|
||||||
|
autocomplete="current-password"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-footer">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
<i class="ti ti-login me-2"></i>
|
||||||
|
Entrar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.4.0/dist/js/tabler.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
333
uv.lock
Normal file
333
uv.lock
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "amqp"
|
||||||
|
version = "5.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "vine" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/79/fc/ec94a357dfc6683d8c86f8b4cfa5416a4c36b28052ec8260c77aca96a443/amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432", size = 129013, upload-time = "2024-11-12T19:55:44.051Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2", size = 50944, upload-time = "2024-11-12T19:55:41.782Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asgiref"
|
||||||
|
version = "3.11.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocensup"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "celery", extra = ["redis"] },
|
||||||
|
{ name = "django" },
|
||||||
|
{ name = "psycopg", extra = ["binary"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "celery", extras = ["redis"], specifier = ">=5.4,<6.0" },
|
||||||
|
{ name = "django", specifier = ">=5.2,<6.0" },
|
||||||
|
{ name = "psycopg", extras = ["binary"], specifier = ">=3.2,<4.0" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "billiard"
|
||||||
|
version = "4.2.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/58/23/b12ac0bcdfb7360d664f40a00b1bda139cbbbced012c34e375506dbd0143/billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f", size = 156537, upload-time = "2025-11-30T13:28:48.52Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5", size = 87070, upload-time = "2025-11-30T13:28:47.016Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "celery"
|
||||||
|
version = "5.6.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "billiard" },
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "click-didyoumean" },
|
||||||
|
{ name = "click-plugins" },
|
||||||
|
{ name = "click-repl" },
|
||||||
|
{ name = "kombu" },
|
||||||
|
{ name = "python-dateutil" },
|
||||||
|
{ name = "tzlocal" },
|
||||||
|
{ name = "vine" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e8/b4/a1233943ab5c8ea05fb877a88a0a0622bf47444b99e4991a8045ac37ea1d/celery-5.6.3.tar.gz", hash = "sha256:177006bd2054b882e9f01be59abd8529e88879ef50d7918a7050c5a9f4e12912", size = 1742243, upload-time = "2026-03-26T12:14:51.76Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl", hash = "sha256:0808f42f80909c4d5833202360ffafb2a4f83f4d8e23e1285d926610e9a7afa6", size = 451235, upload-time = "2026-03-26T12:14:49.491Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
redis = [
|
||||||
|
{ name = "kombu", extra = ["redis"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.4.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click-didyoumean"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/30/ce/217289b77c590ea1e7c24242d9ddd6e249e52c795ff10fac2c50062c48cb/click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463", size = 3089, upload-time = "2024-03-24T08:22:07.499Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c", size = 3631, upload-time = "2024-03-24T08:22:06.356Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click-plugins"
|
||||||
|
version = "1.1.1.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click-repl"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "prompt-toolkit" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cb/a2/57f4ac79838cfae6912f997b4d1a64a858fb0c86d7fcaae6f7b58d267fca/click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", size = 10449, upload-time = "2023-06-15T12:43:51.141Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812", size = 10289, upload-time = "2023-06-15T12:43:48.626Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django"
|
||||||
|
version = "5.2.14"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "asgiref" },
|
||||||
|
{ name = "sqlparse" },
|
||||||
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/65/95/95f7faa0950867afaa0bef2460c6263afd6a2c78cc9434046ed28160b015/django-5.2.14.tar.gz", hash = "sha256:58a63ba841662e5c686b57ba1fec52ddd68c0b93bd96ac3029d55728f00bf8a2", size = 10895118, upload-time = "2026-05-05T13:57:31.104Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/44/f172870cf87aa25afef48fb72adba89ee8b77fcab6f3b23d240b923f1528/django-5.2.14-py3-none-any.whl", hash = "sha256:6f712143bd3064310d1f50fac859c3e9a274bdcfc9595339853be7779297fc76", size = 8311320, upload-time = "2026-05-05T13:57:25.795Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kombu"
|
||||||
|
version = "5.6.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "amqp" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "tzdata" },
|
||||||
|
{ name = "vine" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b6/a5/607e533ed6c83ae1a696969b8e1c137dfebd5759a2e9682e26ff1b97740b/kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55", size = 472594, upload-time = "2025-12-29T20:30:07.779Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93", size = 214219, upload-time = "2025-12-29T20:30:05.74Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
redis = [
|
||||||
|
{ name = "redis" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prompt-toolkit"
|
||||||
|
version = "3.0.52"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "wcwidth" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psycopg"
|
||||||
|
version = "3.3.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
binary = [
|
||||||
|
{ name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psycopg-binary"
|
||||||
|
version = "3.3.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/7d/03818e13ba7f36de93573c93ee3482006d3dfa8b0f8d28df511bad0a1a92/psycopg_binary-3.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5ab28a2a7649df3b72e6b674b4c190e448e8e77cf496a65bd846472048de2089", size = 4591122, upload-time = "2026-05-01T23:27:56.162Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/b9/11b341edf8d54e2694726b273fe9652b254d989f4f63e3ac6816ad6b55f4/psycopg_binary-3.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6402a9d8146cf4b3974ded3fd28a971e83dc6a0333eb7822524a3aa20b546578", size = 4669943, upload-time = "2026-05-01T23:28:04.522Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/18/4665bacd65e7865b4372fcd8abb8b9186ada4b0025f8c2ca691b364a556c/psycopg_binary-3.3.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:580ae30a5f95ccd90008ec697d3ed6a4a2047a516407ad904283fa42086936e9", size = 5469697, upload-time = "2026-05-01T23:28:11.337Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/b1/b83136c6e510593d9b0c759ba5384337bc4ad82d19fda675adc4b2703c84/psycopg_binary-3.3.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7510c37550f91a187e3660a8cc50d4b760f8c3b8b2f89ebc5698cd2c7f2c85d", size = 5152995, upload-time = "2026-05-01T23:28:20.529Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/8d/a9821e2a648afe6091989929982a3b0f00b2631a859cb81379728f08fb75/psycopg_binary-3.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77df19583501ea288eaf15ac0fe7ad01e6d8091a91d5c41df5c718f307d8e31b", size = 6738180, upload-time = "2026-05-01T23:28:30.654Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/58/2e349e8d23905dc2317b80ac65f48fb6f821a4777a4e994a60da91c4850f/psycopg_binary-3.3.4-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:018fbed325936da502feb546642c982dcc4b9ffdea32dfef78dbf3b7f7ad4070", size = 4978828, upload-time = "2026-05-01T23:28:37.277Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/48/57b00d03b4721878326122a1f1e6b0a90b85bcaec56b5b2f8ea6cfa45235/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:17a21953a9e5ff3a16dab692625a3676e2f101db5e40072f39dbee2250194d68", size = 4509757, upload-time = "2026-05-01T23:28:43.078Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/37/33b47d8c007df69aec500df5889767c4d313748e8e9e27a2fef8a6dabcee/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:eb05ee1c2b817d27c537333224c9e83c7afb86fe7296ba970990068baf819b16", size = 4190546, upload-time = "2026-05-01T23:28:50.016Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/c6/32b0835dbc2122617902b649d76a91c1e75406e76bf3d595b0c3bb5ffad6/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:773d573e11f437ce0bdb95b7c18dc58390494f96d43f8b45b9760436114f7652", size = 3926197, upload-time = "2026-05-01T23:28:55.55Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/68/d190ef0c0c5b16ded07831dabc8ddd412f4cdab07ec6e30ed38d9bda0e1f/psycopg_binary-3.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e55ccbdfae79a2ed9c6369c3008a3025817ff9d7e27b32a2d84e2a4267e66e", size = 4236627, upload-time = "2026-05-01T23:29:05.336Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/8f/81dcbc2e8454b74d14881275ea45f00791052dac531a9fa8be1730d1685b/psycopg_binary-3.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:494ca54901be8cf9eb7e02c25b731f2317c378efa44f43e8f9bd0e1184ae7be4", size = 3560782, upload-time = "2026-05-01T23:29:11.967Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/43/13e9c406fbbf354580476e248a16b64802a376873ebe6339e30bb655572d/psycopg_binary-3.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7", size = 4590377, upload-time = "2026-05-01T23:29:18.782Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/be/2923cd7c3683e7afdecf4f10796a18de02f5c5ddc0969aa2ad0a8cdd3bbd/psycopg_binary-3.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31", size = 4669023, upload-time = "2026-05-01T23:29:25.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/a0/2c913d6fe13d6a8bd13597d36739bf47af063ad9399e402cfecab16f3c1e/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70", size = 5467423, upload-time = "2026-05-01T23:29:33.416Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/38/205d10bc1ad0df4a21c5c51659126bd3ea0ef98fcad1e852f78c249bb9c3/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3", size = 5151137, upload-time = "2026-05-01T23:29:42.013Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/fc/f0381ddcd45eff3bb70dbca6823a996048d7f507b2ec3fc92c6fabc0fe87/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c", size = 6736671, upload-time = "2026-05-01T23:29:51.626Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/40/fa545ae152c24327651e5624e4902121e808270be36c10b12e9939be09bc/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae", size = 4979601, upload-time = "2026-05-01T23:29:56.961Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/e4/2f8a47ee97f90cd2b933d0463081d35631ff419de2b8c984a5f369857de0/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc", size = 4510513, upload-time = "2026-05-01T23:30:07.243Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/0e/94e842ff4a7f98ed162580ca2e8b8864b28c1e0350f2443f8ee47f821167/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf", size = 4187243, upload-time = "2026-05-01T23:30:15.352Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/83/fc6c174b672e29b7de996ea77b6cbddf46c891751c3355f6974292baa6b4/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260", size = 3927347, upload-time = "2026-05-01T23:30:21.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/65/768364d4a97a15b1a7f47ba52688c1686f22941d8332a8398cefc468e25f/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf", size = 4236393, upload-time = "2026-05-01T23:30:26.211Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/3b/218efbc9e645becd80cdf651acda05f85cfe546b7a9c0458c7cbc8fe1f74/psycopg_binary-3.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38", size = 3564592, upload-time = "2026-05-01T23:30:31.764Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/a6/828c9185701dab71b234c2a76c38a08b098ebfec5020716b4e93807492b5/psycopg_binary-3.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97", size = 4607292, upload-time = "2026-05-01T23:30:38.962Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/58/5b40dbc9d839045c9dae956960e4fb6d20bcabe6c59a2aa34fc3a371913f/psycopg_binary-3.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829", size = 4687023, upload-time = "2026-05-01T23:30:47.227Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/a9/793f0ac107a9003b48441d0d1f9f616d96e0f37458dd8dc12528ceff55fb/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7", size = 5486985, upload-time = "2026-05-01T23:30:55.517Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/26/42e8533497e2592334f68ec529cf5f840f7fa4e99575a4bb61aa184dbfbf/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277", size = 5168745, upload-time = "2026-05-01T23:31:01.904Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/af/b7151776cc08d5935d45c833ec818a9beb417cf7c08239af1aafbdae78ee/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6", size = 6761486, upload-time = "2026-05-01T23:31:14.511Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/ed/c92533b9124712d592cbf1cd6c76da933a2e0acea81dfe1fbe7e735f0cff/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41", size = 4997427, upload-time = "2026-05-01T23:31:20.901Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/23/ccadfd0de416aa188356daa199453af24087b042e296088706d190ae0295/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228", size = 4533549, upload-time = "2026-05-01T23:31:26.204Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/a0/c8f43cee36386f7bc891ab41a9d31ea07cf9826038e732da79f26b1e5f34/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9", size = 4210256, upload-time = "2026-05-01T23:31:33.884Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/2c/c1547871be3790676e8868b38655496422f94f0978dfb66b74bdba2f1676/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014", size = 3946204, upload-time = "2026-05-01T23:31:39.626Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/b1/f6670f00fa7ea601584623f6c11602ab92117d83eaff885e0210f6de7418/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e", size = 4255811, upload-time = "2026-05-01T23:31:44.986Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dateutil"
|
||||||
|
version = "2.9.0.post0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redis"
|
||||||
|
version = "6.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sqlparse"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.15.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdata"
|
||||||
|
version = "2026.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzlocal"
|
||||||
|
version = "5.4.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/81/5b/879b2f932adfa7a053c360d50bc896c977fa6426109185f7c12ebdd0cb9d/tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4", size = 31170, upload-time = "2026-06-29T08:03:40.026Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15", size = 18115, upload-time = "2026-06-29T08:03:38.666Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vine"
|
||||||
|
version = "5.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/bd/e4/d07b5f29d283596b9727dd5275ccbceb63c44a1a82aa9e4bfd20426762ac/vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0", size = 48980, upload-time = "2023-11-05T08:46:53.857Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636, upload-time = "2023-11-05T08:46:51.205Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wcwidth"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", size = 1466253, upload-time = "2026-06-29T18:11:11.601Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" },
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue
Block a user