Browse Source

Feat(integracao): Endpoint para integração

pull/3858/head
root 10 months ago
parent
commit
9661ce9387
  1. 1
      .gitignore
  2. 40
      LOCALHOST_SETUP.md
  3. 4
      requirements/requirements.txt
  4. 124
      sapl/api/views_sessao.py

1
.gitignore

@ -15,6 +15,7 @@ node_modules/
# Distribution / packaging
.Python
env/
.venv/
build/
develop-eggs/
dist/

40
LOCALHOST_SETUP.md

@ -0,0 +1,40 @@
# Subir o SAPL apontando para o banco remoto (localhost)
Passo a passo para subir o ambiente local usando o Postgres já disponível em `legisinc.com.br:5432`.
## 1) Preparar o ambiente Python
```bash
cd /root/dev/sapl
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements/requirements.txt
```
## 2) Configurar variáveis de ambiente
Edite `sapl/.env` com os valores do banco remoto:
```env
DATABASE_URL=postgresql://kemuel:kasepulvida@legisinc.com.br:5432/sapl
SECRET_KEY=<sua-chave-secreta>
DEBUG=True
EMAIL_USE_TLS=True
EMAIL_PORT=587
```
> Observação: não rode `migrate` contra esse banco se ele for de produção.
## 3) Testar conexão (opcional)
```bash
python manage.py showmigrations --plan
```
## 4) Subir o servidor Django
```bash
python manage.py runserver 0.0.0.0:8001
```
Se preferir sem autoreload: `python manage.py runserver 0.0.0.0:8001 --noreload`.

4
requirements/requirements.txt

@ -16,14 +16,14 @@ django-ratelimit==3.0.1
easy-thumbnails==2.8.5
python-decouple==3.1
dj-database-url==0.5.0
psycopg2-binary==2.9.9
psycopg2-binary==2.9.8
pyyaml==6.0.1
pytz==2019.3
python-magic==0.4.15
unipath==1.1
Pillow==10.3.0
reportlab==3.6.13
WeasyPrint==66
WeasyPrint==66.0
trml2pdf==0.6
gunicorn==23.0.0
more-itertools==8.2.0

124
sapl/api/views_sessao.py

@ -1,4 +1,3 @@
from django.apps.registry import apps
from rest_framework.decorators import action
from rest_framework.response import Response
@ -9,6 +8,10 @@ from sapl.api.serializers import ChoiceSerializer,\
SessaoPlenariaECidadaniaSerializer
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao
from sapl.utils import choice_anos_com_sessaoplenaria
# Add imports for building materias payload
from sapl.sessao.models import ExpedienteMateria, OrdemDia
from sapl.materia.models import MateriaLegislativa, Tramitacao
from django.urls import reverse
ApiViewSetConstrutor.build_class(
@ -45,3 +48,122 @@ class _SessaoPlenariaViewSet:
def ecidadania_list(self, request, *args, **kwargs):
self.serializer_class = SessaoPlenariaECidadaniaSerializer
return self.list(request, *args, **kwargs)
# New endpoint: materias da sessão (expediente e ordem do dia)
@action(detail=True, methods=['get'], url_path='materias')
def materias(self, request, *args, **kwargs):
sessao: SessaoPlenaria = self.get_object()
pk = sessao.pk
# Data de referência da sessão para status de tramitação
data_ref = sessao.data_fim or sessao.data_inicio
def autores_info(m: MateriaLegislativa):
# retorna lista de {id, nome}
return list(m.autores.values('id', 'nome'))
def tramitacao_info(m: MateriaLegislativa):
t = (Tramitacao.objects
.filter(materia=m, data_tramitacao__lte=data_ref)
.order_by('-data_tramitacao', '-id')
.select_related('status')
.first())
status = ''
fase = ''
try:
status = t.status.descricao if t and t.status else ''
except Exception:
status = ''
try:
fase = t.get_turno_display() if t and t.turno else ''
except Exception:
fase = ''
return status, fase
def material_item(m: MateriaLegislativa, status_sessao: str, extra: dict = None):
extra = extra or {}
pdf_url = None
try:
# só expõe URL se houver ao menos 1 PDF acessório
if m.documentoacessorio_set.filter(arquivo__iendswith='pdf').exists():
pdf_url = request.build_absolute_uri(
reverse('sapl.materia:merge_docacessorios', kwargs={'pk': m.pk})
)
except Exception:
pdf_url = None
status_tram, fase_materia = tramitacao_info(m)
return {
'id': m.pk,
'nome_documento': str(m),
'autoria': autores_info(m), # [{id, nome}]
'tipo_materia': {
'id': m.tipo_id,
'nome': getattr(m.tipo, 'descricao', None)
},
'ementa': m.ementa,
'status': status_sessao, # alias de status da sessão
'status_sessao': status_sessao,
'status_tramitacao': status_tram,
'fase_materia': fase_materia,
'quorum': getattr(m.tipo, 'quorum_minimo_votacao', None),
'pdf_url': pdf_url,
'tramitacao_pdf_url': request.build_absolute_uri(
reverse('sapl.relatorios:relatorio_materia_tramitacao', kwargs={'pk': m.pk})
),
**extra
}
# Expediente
expediente_items = []
for em in ExpedienteMateria.objects.select_related('materia', 'materia__tipo').filter(sessao_plenaria_id=pk):
m = em.materia
# Determina status no contexto da sessão (votação/retirada/leitura)
rv = em.registrovotacao_set.filter(materia=m).first()
rp = em.retiradapauta_set.filter(materia=m).first()
rl = em.registroleitura_set.filter(materia=m).first()
if rv:
status_sessao = rv.tipo_resultado_votacao.nome
elif rp:
status_sessao = 'Retirado'
elif rl:
status_sessao = 'Leitura'
else:
status_sessao = ''
expediente_items.append(material_item(
m,
status_sessao,
{
'tipo_votacao': em.get_tipo_votacao_display(),
}
))
# Ordem do Dia
ordem_items = []
for od in OrdemDia.objects.select_related('materia', 'materia__tipo').filter(sessao_plenaria_id=pk):
m = od.materia
rv = od.registrovotacao_set.filter(materia=m).first()
rp = od.retiradapauta_set.filter(materia=m).first()
rl = od.registroleitura_set.filter(materia=m).first()
if rv:
status_sessao = rv.tipo_resultado_votacao.nome
elif rp:
status_sessao = 'Retirado'
elif rl:
status_sessao = 'Leitura'
else:
status_sessao = ''
ordem_items.append(material_item(
m,
status_sessao,
{
'numero_ordem': od.numero_ordem,
'tipo_votacao': od.get_tipo_votacao_display(),
}
))
return Response({
'sessao': pk,
'expediente': expediente_items,
'ordem_dia': ordem_items
})

Loading…
Cancel
Save