Browse Source

Fixes #2030 (#2277)

* Fixes #2030

* Fixes #2030

* Fixes #2030
pull/2299/head
AndreSouto 7 years ago
committed by Edward
parent
commit
a6fc9879d3
  1. 28
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  2. 37
      sapl/relatorios/views.py
  3. 41
      sapl/rules/map_rules.py
  4. 11
      sapl/sessao/forms.py
  5. 28
      sapl/sessao/migrations/0024_ocorrenciasessao.py
  6. 21
      sapl/sessao/migrations/0025_auto_20180919_1116.py
  7. 15
      sapl/sessao/models.py
  8. 6
      sapl/sessao/urls.py
  9. 70
      sapl/sessao/views.py
  10. 6
      sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
  11. 6
      sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
  12. 32
      sapl/templates/sessao/ocorrencia_sessao.html
  13. 2
      sapl/templates/sessao/resumo.html
  14. 1
      sapl/templates/sessao/resumo_ata.html
  15. 2
      sapl/templates/sessao/subnav.yaml

28
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -6,6 +6,9 @@
"""
import time
from django.template.defaultfilters import safe
from django.utils.html import strip_tags
from sapl.sessao.models import ResumoOrdenacao
from trml2pdf import parseString
@ -284,7 +287,25 @@ def oradores(lst_oradores):
return tmp
def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores):
def ocorrencias(lst_ocorrencias):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Ocorrências da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for idx, ocorrencia in enumerate(lst_ocorrencias):
tmp += '\t\t<para style="P3">' + \
str(ocorrencia.conteudo) + '</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
return tmp
def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores, lst_ocorrencias):
"""
"""
arquivoPdf = str(int(time.time() * 100)) + ".pdf"
@ -316,7 +337,8 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
'mat_o_d': votacao(lst_votacao),
'mesa_d': mesa(lst_mesa),
'oradores_exped': oradores_expediente(lst_oradores_expediente),
'oradores_expli': oradores(lst_oradores)
'oradores_expli': oradores(lst_oradores),
'ocorr_sessao': ocorrencias(lst_ocorrencias)
}
if ordenacao:
@ -330,6 +352,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += dict_ord_template[ordenacao.oitavo]
tmp += dict_ord_template[ordenacao.nono]
tmp += dict_ord_template[ordenacao.decimo]
else:
tmp += inf_basicas(inf_basicas_dic)
tmp += mesa(lst_mesa)
@ -340,6 +363,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += presenca_ordem_dia(lst_presenca_ordem_dia)
tmp += votacao(lst_votacao)
tmp += oradores(lst_oradores)
tmp += ocorrencias(lst_ocorrencias)
tmp += '\t</story>\n'
tmp += '</document>\n'

37
sapl/relatorios/views.py

@ -17,7 +17,7 @@ from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, Orador, OradorExpediente,
OrdemDia, PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca)
SessaoPlenariaPresenca, OcorrenciaSessao)
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, ExtraiTag, TrocaTag, filiacao_data
@ -514,13 +514,13 @@ def get_sessao_plenaria(sessao, casa):
dic_presenca['sgl_partido'] = partido_sigla
lst_presenca_sessao.append(dic_presenca)
# Exibe os Expedientes
lst_expedientes = []
expedientes = ExpedienteSessao.objects.filter(
sessao_plenaria=sessao).order_by('tipo__nome')
for e in expedientes:
dic_expedientes = {}
dic_expedientes["nom_expediente"] = e.tipo.nome
conteudo = e.conteudo
@ -539,6 +539,7 @@ def get_sessao_plenaria(sessao, casa):
if dic_expedientes:
lst_expedientes.append(dic_expedientes)
# Lista das matérias do Expediente, incluindo o resultado das votacoes
lst_expediente_materia = []
for expediente_materia in ExpedienteMateria.objects.filter(
@ -727,6 +728,28 @@ def get_sessao_plenaria(sessao, casa):
dic_oradores['sgl_partido'] = sigla
lst_oradores.append(dic_oradores)
# Ocorrências da Sessão
lst_ocorrencias = []
ocorrencias = OcorrenciaSessao.objects.filter(
sessao_plenaria=sessao)
for o in ocorrencias:
conteudo = o.conteudo
# unescape HTML codes
# https://github.com/interlegis/sapl/issues/1046
conteudo = re.sub('style=".*?"', '', conteudo)
conteudo = html.unescape(conteudo)
# escape special character '&'
# https://github.com/interlegis/sapl/issues/1009
conteudo = conteudo.replace('&', '&amp;')
o.conteudo = conteudo
lst_ocorrencias.append(o)
return (inf_basicas_dic,
lst_mesa,
lst_presenca_sessao,
@ -735,7 +758,8 @@ def get_sessao_plenaria(sessao, casa):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_oradores)
lst_oradores,
lst_ocorrencias)
def get_turno(dic, materia, sessao_data_inicio):
@ -785,7 +809,9 @@ def relatorio_sessao_plenaria(request, pk):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_oradores) = get_sessao_plenaria(sessao, casa)
lst_oradores,
lst_ocorrencias) = get_sessao_plenaria(sessao, casa)
for idx in range(len(lst_expedientes)):
txt_expedientes = lst_expedientes[idx]['txt_expediente']
@ -806,7 +832,8 @@ def relatorio_sessao_plenaria(request, pk):
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_oradores)
lst_oradores,
lst_ocorrencias)
response.write(pdf)
return response

41
sapl/rules/map_rules.py

@ -1,23 +1,3 @@
from sapl.base import models as base
from sapl.comissoes import models as comissoes
from sapl.compilacao import models as compilacao
from sapl.lexml import models as lexml
from sapl.materia import models as materia
from sapl.norma import models as norma
from sapl.painel import models as painel
from sapl.parlamentares import models as parlamentares
from sapl.protocoloadm import models as protocoloadm
from sapl.audiencia import models as audiencia
from sapl.rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST,
SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_ANONYMOUS,
SAPL_GROUP_AUTOR, SAPL_GROUP_COMISSOES,
SAPL_GROUP_GERAL, SAPL_GROUP_LOGIN_SOCIAL,
SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA,
SAPL_GROUP_PAINEL, SAPL_GROUP_PARLAMENTAR,
SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO,
SAPL_GROUP_VOTANTE)
from sapl.sessao import models as sessao
"""
Todas as permissões do django framework seguem o padrão
@ -46,6 +26,26 @@ negócio trabalham com os cinco radiais de permissão
e com qualquer outro tipo de permissão customizada, nesta ordem de precedência.
"""
from sapl.audiencia import models as audiencia
from sapl.base import models as base
from sapl.comissoes import models as comissoes
from sapl.compilacao import models as compilacao
from sapl.lexml import models as lexml
from sapl.materia import models as materia
from sapl.norma import models as norma
from sapl.painel import models as painel
from sapl.parlamentares import models as parlamentares
from sapl.protocoloadm import models as protocoloadm
from sapl.rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST,
SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_ANONYMOUS,
SAPL_GROUP_AUTOR, SAPL_GROUP_COMISSOES,
SAPL_GROUP_GERAL, SAPL_GROUP_LOGIN_SOCIAL,
SAPL_GROUP_MATERIA, SAPL_GROUP_NORMA,
SAPL_GROUP_PAINEL, SAPL_GROUP_PARLAMENTAR,
SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO,
SAPL_GROUP_VOTANTE)
from sapl.sessao import models as sessao
__base__ = [RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE]
__listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE]
@ -161,6 +161,7 @@ rules_group_sessao = {
(sessao.SessaoPlenaria, __base__),
(sessao.SessaoPlenariaPresenca, __base__),
(sessao.ExpedienteMateria, __base__),
(sessao.OcorrenciaSessao, __base__),
(sessao.IntegranteMesa, __base__),
(sessao.ExpedienteSessao, __base__),
(sessao.Orador, __base__),

11
sapl/sessao/forms.py

@ -22,7 +22,7 @@ from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
from .models import (Bancada, Bloco, ExpedienteMateria, Orador,
OradorExpediente, OrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, TipoResultadoVotacao)
SessaoPlenariaPresenca, TipoResultadoVotacao, OcorrenciaSessao)
def recupera_anos():
@ -54,7 +54,8 @@ ORDENACAO_RESUMO = [('cont_mult', 'Conteúdo Multimídia'),
('mat_o_d', 'Matérias da Ordem do Dia'),
('mesa_d', 'Mesa Diretora'),
('oradores_exped', 'Oradores do Expediente'),
('oradores_expli', 'Oradores das Explicações Pessoais')]
('oradores_expli', 'Oradores das Explicações Pessoais'),
('ocorrencia_sessao', 'Ocorrências da Sessão')]
class SessaoPlenariaForm(ModelForm):
@ -412,6 +413,12 @@ class MesaForm(forms.Form):
class ExpedienteForm(forms.Form):
conteudo = forms.CharField(required=False, widget=forms.Textarea)
class OcorrenciaSessaoForm(ModelForm):
class Meta:
model = OcorrenciaSessao
fields = ['conteudo']
class VotacaoForm(forms.Form):
votos_sim = forms.CharField(label='Sim')

28
sapl/sessao/migrations/0024_ocorrenciasessao.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2018-09-18 13:44
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sessao', '0023_auto_20180914_1315'),
]
operations = [
migrations.CreateModel(
name='OcorrenciaSessao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('conteudo', models.TextField(blank=True, verbose_name='Ocorrências da Sessão Plenária')),
('sessao_plenaria', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='sessao.SessaoPlenaria')),
],
options={
'verbose_name_plural': 'Ocorrências da Sessão Plenaria',
'verbose_name': 'Ocorrência da Sessão Plenaria',
},
),
]

21
sapl/sessao/migrations/0025_auto_20180919_1116.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-09-19 14:16
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sessao', '0024_ocorrenciasessao'),
]
operations = [
migrations.AlterField(
model_name='ocorrenciasessao',
name='sessao_plenaria',
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='sessao.SessaoPlenaria'),
),
]

15
sapl/sessao/models.py

@ -301,6 +301,21 @@ class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
return '%s - %s' % (self.tipo, self.sessao_plenaria)
@reversion.register()
class OcorrenciaSessao(models.Model): # OcorrenciaSessaoPlenaria
sessao_plenaria = models.OneToOneField(SessaoPlenaria,
on_delete=models.PROTECT)
conteudo = models.TextField(
blank=True, verbose_name=_('Ocorrências da Sessão Plenária'))
class Meta:
verbose_name = _('Ocorrência da Sessão Plenaria')
verbose_name_plural = _('Ocorrências da Sessão Plenaria')
def __str__(self):
return '%s - %s' % (self.sessao_plenaria, self.conteudo)
@reversion.register()
class IntegranteMesa(models.Model): # MesaSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,

6
sapl/sessao/urls.py

@ -3,7 +3,7 @@ from django.conf.urls import include, url
from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
AdicionarVariasMateriasOrdemDia, BancadaCrud,
BlocoCrud, CargoBancadaCrud,
ExpedienteMateriaCrud, ExpedienteView,
ExpedienteMateriaCrud, ExpedienteView, OcorrenciaSessaoView,
MateriaOrdemDiaCrud, MesaView, OradorCrud,
OradorExpedienteCrud, PainelView,
PautaSessaoDetailView, PautaSessaoView,
@ -100,6 +100,8 @@ urlpatterns = [
# Subnav sessão
url(r'^sessao/(?P<pk>\d+)/expediente$',
ExpedienteView.as_view(), name='expediente'),
url(r'^sessao/(?P<pk>\d+)/ocorrencia_sessao$',
OcorrenciaSessaoView.as_view(), name='ocorrencia_sessao'),
url(r'^sessao/(?P<pk>\d+)/presenca$',
PresencaView.as_view(), name='presenca'),
url(r'^sessao/(?P<pk>\d+)/painel$',
@ -110,7 +112,7 @@ urlpatterns = [
url(r'^sessao/(?P<pk>\d+)/resumo$',
ResumoView.as_view(), name='resumo'),
url(r'^sessao/(?P<pk>\d+)/resumo_ata$',
ResumoAtaView.as_view(), name='resumo_ata'),
ResumoAtaView.as_view(), name='resumo_ata'),
url(r'^sessao/pesquisar-sessao$',
PesquisarSessaoPlenariaView.as_view(), name='pesquisar_sessao'),
url(r'^sessao/(?P<pk>\d+)/matordemdia/votnom/(?P<oid>\d+)/(?P<mid>\d+)$',

70
sapl/sessao/views.py

@ -37,13 +37,13 @@ from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.utils import show_results_filter_set, remover_acentos
from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, BlocoForm,
ExpedienteForm, ListMateriaForm, MesaForm,
ExpedienteForm, OcorrenciaSessaoForm, ListMateriaForm, MesaForm,
OradorExpedienteForm, OradorForm, PautaSessaoFilterSet,
PresencaForm, ResumoOrdenacaoForm, SessaoPlenariaFilterSet,
SessaoPlenariaForm, VotacaoEditForm, VotacaoForm,
VotacaoNominalForm)
from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
ExpedienteMateria, ExpedienteSessao, IntegranteMesa,
ExpedienteMateria, ExpedienteSessao, OcorrenciaSessao, IntegranteMesa,
MateriaLegislativa, Orador, OradorExpediente, OrdemDia,
PresencaOrdemDia, RegistroVotacao, ResumoOrdenacao,
SessaoPlenaria, SessaoPlenariaPresenca, TipoExpediente,
@ -1175,7 +1175,8 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
'setimo': ordenacao.setimo,
'oitavo': ordenacao.oitavo,
'nono': ordenacao.nono,
'decimo': ordenacao.decimo})
'decimo': ordenacao.decimo,
'decimo_primeiro': ordenacao.decimo_primeiro})
return initial
def form_valid(self, form):
@ -1191,6 +1192,7 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
ordenacao.oitavo = form.cleaned_data['oitavo']
ordenacao.nono = form.cleaned_data['nono']
ordenacao.decimo = form.cleaned_data['decimo']
ordenacao.decimo_primeiro = form.cleaned_data['decimo_primeiro']
ordenacao.save()
@ -1280,6 +1282,7 @@ class ResumoView(DetailView):
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
context.update({'expedientes': expedientes})
# =====================================================================
# Matérias Expediente
materias = ExpedienteMateria.objects.filter(
@ -1413,6 +1416,12 @@ class ResumoView(DetailView):
oradores_explicacoes.append(oradores)
context.update({'oradores_explicacoes': oradores_explicacoes})
# =====================================================================
# Ocorrẽncias da Sessão
ocorrencias_sessao = OcorrenciaSessao.objects.filter(sessao_plenaria_id=self.object.id)
context.update({'ocorrencias_da_sessao': ocorrencias_sessao})
# =====================================================================
# Indica a ordem com a qual o template será renderizado
ordenacao = ResumoOrdenacao.objects.first()
@ -1426,7 +1435,8 @@ class ResumoView(DetailView):
'mat_o_d': 'materias_ordem_dia.html',
'mesa_d': 'mesa_diretora.html',
'oradores_exped': 'oradores_expediente.html',
'oradores_expli': 'oradores_explicacoes.html'
'oradores_expli': 'oradores_explicacoes.html',
'ocorr_sessao': 'ocorrencias_da_sessao.html'
}
if ordenacao:
@ -1452,12 +1462,16 @@ class ResumoView(DetailView):
'setimo_ordenacao': dict_ord_template['oradores_exped'],
'oitavo_ordenacao': dict_ord_template['lista_p_o_d'],
'nono_ordenacao': dict_ord_template['mat_o_d'],
'decimo_ordenacao': dict_ord_template['oradores_expli']})
'decimo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_primeiro_ordenacao': dict_ord_template['ocorr_sessao']})
return self.render_to_response(context)
class ResumoAtaView(ResumoView):
template_name = 'sessao/resumo_ata.html'
class ExpedienteView(FormMixin, DetailView):
template_name = 'sessao/expediente.html'
form_class = ExpedienteForm
@ -1537,6 +1551,52 @@ class ExpedienteView(FormMixin, DetailView):
return reverse('sapl.sessao:expediente', kwargs={'pk': pk})
class OcorrenciaSessaoView(FormMixin, DetailView):
template_name = 'sessao/ocorrencia_sessao.html'
form_class = OcorrenciaSessaoForm
model = SessaoPlenaria
def delete(self):
OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
msg = _('Registro deletado com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
def save(self,form):
conteudo = form.cleaned_data['conteudo']
OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
ocorrencia = OcorrenciaSessao()
ocorrencia.sessao_plenaria_id = self.object.id
ocorrencia.conteudo = conteudo
ocorrencia.save()
msg = _('Registro salvo com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
@method_decorator(permission_required('sessao.add_ocorrenciasessao'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = OcorrenciaSessaoForm(request.POST)
if not form.is_valid():
return self.form_invalid(form)
if request.POST.get('delete'):
self.delete()
elif request.POST.get('save'):
self.save(form)
return self.form_valid(form)
def get_success_url(self):
pk = self.kwargs['pk']
return reverse('sapl.sessao:ocorrencia_sessao', kwargs={'pk': pk})
class VotacaoEditView(SessaoPermissionMixin):
'''

6
sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html

@ -0,0 +1,6 @@
<fieldset>
<p align="justify">
<strong>Ocorrências da Sessão: </strong>
{{object.ocorrenciasessao.conteudo|safe}}
</p>
</fieldset>

6
sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html

@ -0,0 +1,6 @@
<fieldset>
<legend>Ocorrências da Sessão</legend>
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);">
<p>{{object.ocorrenciasessao.conteudo|safe}}</p>
</div>
</fieldset>

32
sapl/templates/sessao/ocorrencia_sessao.html

@ -0,0 +1,32 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block actions %}{% endblock %}
{% block title %}<font size="6" face="SourceSansProSemiBold" color="#364347" >Ocorrências da Sessão </font> <b><small><font face="SourceSansProSemiBold" size="5" color="#93a4aa"> ({{ object }}) </font> </small></b>{% endblock %}
{% block detail_content %}
{% if perms|get_add_perm:view %}
<form method="post" accept-charset="ISO-8859-1">
{% csrf_token %}
<fieldset class="form-group">
<textarea rows="5" cols="50" name="conteudo" id="conteudo">{{object.ocorrenciasessao.conteudo}}</textarea>
</fieldset>
<input type="submit" name="save" value="Salvar" class="btn btn-primary"/>
<input type="submit" name="delete" value="Apagar" class="btn btn-danger" />
</form>
{% else %}
{{object.ocorrenciasessao.conteudo|safe}}
{% endif %}
{% endblock detail_content %}
<!-- Texto RICO -->
{% block extra_js %}
{% if perms|get_add_perm:view %}
<script language="JavaScript">
initTinymce(null);
</script>
{% endif %}
{% endblock %}

2
sapl/templates/sessao/resumo.html

@ -50,5 +50,7 @@
{% include 'sessao/blocos_resumo/'|add:decimo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_primeiro_ordenacao %}
<br /><br /><br />
{% endblock detail_content %}

1
sapl/templates/sessao/resumo_ata.html

@ -19,5 +19,6 @@
{% include 'sessao/blocos_ata/'|add:oitavo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:nono_ordenacao %}
{% include 'sessao/blocos_ata/'|add:decimo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:decimo_primeiro_ordenacao %}
{% include 'sessao/blocos_ata/assinaturas.html' %}
{% endblock detail_content %}

2
sapl/templates/sessao/subnav.yaml

@ -10,6 +10,8 @@
url: presenca
- title: {% trans 'Explicações Pessoais' %}
url: orador_list
- title: {% trans 'Ocorrências da Sessão' %}
url: ocorrencia_sessao
- title: {% trans 'Expedientes' %}
children:

Loading…
Cancel
Save