Browse Source

Fix #2506 aprimorar extrato titulos e nome (#2539)

* Gerar e aprimorar pdf de extrato

Colocando nome completo nos extratos e acresentando cargos nas assinaturas.
Fix #2514
Fix #2506

Refatorando classe ResumoView (extraindo metodos)

Adicionando testes a refatoração feita na classe ResumoView

Iniciando a geração do pdf de extrato da reunião

Aprimorando relatorio do extrato da reunião;
Fix #2514

Colocando numero de votos

Arrumando header e tabelas do relatorio de extrato

Colocando rodape no documento de extrato

Melhorando formatação da documentação de extrato de reunião

Melhorando assinaturas e removendo codigo morto

Adicionando nome de parlaentares nos votos nominais Fix #2514 Fix #2502 Fix #2506

* Melhorando visualização do documento de extrato da reunião

* Gerar e aprimorar pdf de extrato

Colocando nome completo nos extratos e acresentando cargos nas assinaturas.
Fix #2514
Fix #2506

Refatorando classe ResumoView (extraindo metodos)

Adicionando testes a refatoração feita na classe ResumoView

Iniciando a geração do pdf de extrato da reunião

Aprimorando relatorio do extrato da reunião;
Fix #2514

Colocando numero de votos

Arrumando header e tabelas do relatorio de extrato

Colocando rodape no documento de extrato

Melhorando formatação da documentação de extrato de reunião

Melhorando assinaturas e removendo codigo morto

Adicionando nome de parlaentares nos votos nominais Fix #2514 Fix #2502 Fix #2506

* Melhorando visualização do documento de extrato da reunião

* Arruma assinatura presentes

* Colocando pagina de assinaturas em uma folha separado
pull/2636/head
Ulysses Lara 6 years ago
committed by Edward
parent
commit
6abe23936d
  1. 5
      sapl/relatorios/urls.py
  2. 73
      sapl/relatorios/views.py
  3. 103
      sapl/sessao/tests/test_sessao_view.py
  4. 524
      sapl/sessao/views.py
  5. 62
      sapl/static/sapl/css/header-relatorio.css
  6. 56
      sapl/static/sapl/css/relatorio.css
  7. 31
      sapl/templates/relatorios/header_ata.html
  8. 101
      sapl/templates/relatorios/relatorio_ata.html
  9. 12
      sapl/templates/sessao/blocos_ata/assinaturas.html
  10. 4
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  11. 2
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  12. 52
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  13. 2
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  14. 2
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  15. 2
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  16. 12
      sapl/templates/sessao/resumo_ata.html

5
sapl/relatorios/urls.py

@ -5,7 +5,8 @@ from .views import (relatorio_capa_processo,
relatorio_documento_administrativo, relatorio_espelho, relatorio_documento_administrativo, relatorio_espelho,
relatorio_etiqueta_protocolo, relatorio_materia, relatorio_etiqueta_protocolo, relatorio_materia,
relatorio_ordem_dia, relatorio_pauta_sessao, relatorio_ordem_dia, relatorio_pauta_sessao,
relatorio_protocolo, relatorio_sessao_plenaria) relatorio_protocolo, relatorio_sessao_plenaria,
resumo_ata_pdf)
app_name = AppConfig.name app_name = AppConfig.name
@ -28,4 +29,6 @@ urlpatterns = [
relatorio_etiqueta_protocolo, name='relatorio_etiqueta_protocolo'), relatorio_etiqueta_protocolo, name='relatorio_etiqueta_protocolo'),
url(r'^relatorios/pauta-sessao/(?P<pk>\d+)/$', url(r'^relatorios/pauta-sessao/(?P<pk>\d+)/$',
relatorio_pauta_sessao, name='relatorio_pauta_sessao'), relatorio_pauta_sessao, name='relatorio_pauta_sessao'),
url(r'^relatorios/(?P<pk>\d+)/resumo_ata$',
resumo_ata_pdf, name='resumo_ata_pdf'),
] ]

73
sapl/relatorios/views.py

@ -2,12 +2,15 @@ from datetime import datetime as dt
import html import html
import logging import logging
import re import re
import tempfile
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from sapl.settings import MEDIA_URL
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao, from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao,
@ -24,12 +27,20 @@ from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
from sapl.settings import STATIC_ROOT from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data
from sapl.sessao.views import (get_identificação_basica, get_mesa_diretora,
get_presenca_sessao,get_expedientes,
get_materias_expediente,get_oradores_expediente,
get_presenca_ordem_do_dia,get_materias_ordem_do_dia,
get_oradores_explicações_pessoais, get_ocorrencias_da_sessão)
from .templates import (pdf_capa_processo_gerar, from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_gerar, pdf_documento_administrativo_gerar, pdf_espelho_gerar,
pdf_etiqueta_protocolo_gerar, pdf_materia_gerar, pdf_etiqueta_protocolo_gerar, pdf_materia_gerar,
pdf_ordem_dia_gerar, pdf_pauta_sessao_gerar, pdf_ordem_dia_gerar, pdf_pauta_sessao_gerar,
pdf_protocolo_gerar, pdf_sessao_plenaria_gerar) pdf_protocolo_gerar, pdf_sessao_plenaria_gerar)
from weasyprint import HTML, CSS
def get_kwargs_params(request, fields): def get_kwargs_params(request, fields):
kwargs = {} kwargs = {}
@ -1199,3 +1210,65 @@ def get_pauta_sessao(sessao, casa):
return (lst_expediente_materia, return (lst_expediente_materia,
lst_votacao, lst_votacao,
inf_basicas_dic) inf_basicas_dic)
def make_pdf(base_url,main_template,header_template,main_css='',header_css=''):
html = HTML(base_url=base_url, string=main_template)
main_doc = html.render(stylesheets=[])
def get_page_body(boxes):
for box in boxes:
if box.element_tag == 'body':
return box
return get_page_body(box.all_children())
# Template of header
html = HTML(base_url=base_url,string=header_template)
header = html.render(stylesheets=[CSS(string='@page {size:A4; margin:1cm;}')])
header_page = header.pages[0]
header_body = get_page_body(header_page._page_box.all_children())
header_body = header_body.copy_with_children(header_body.all_children())
for page in main_doc.pages:
page_body = get_page_body(page._page_box.all_children())
page_body.children += header_body.all_children()
pdf_file = main_doc.write_pdf()
return pdf_file
def resumo_ata_pdf(request,pk):
base_url = request.build_absolute_uri()
casa = CasaLegislativa.objects.first()
rodape = ' '.join(get_rodape(casa))
sessao_plenaria = SessaoPlenaria.objects.get(pk=pk)
context = {}
context.update(get_identificação_basica(sessao_plenaria))
context.update(get_mesa_diretora(sessao_plenaria))
context.update(get_presenca_sessao(sessao_plenaria))
context.update(get_expedientes(sessao_plenaria))
context.update(get_materias_expediente(sessao_plenaria))
context.update(get_oradores_expediente(sessao_plenaria))
context.update(get_presenca_ordem_do_dia(sessao_plenaria))
context.update(get_materias_ordem_do_dia(sessao_plenaria))
context.update(get_oradores_explicações_pessoais(sessao_plenaria))
context.update(get_ocorrencias_da_sessão(sessao_plenaria))
context.update({'object':sessao_plenaria})
context.update({'data': dt.today().strftime('%d/%m/%Y')})
context.update({'rodape':rodape})
header_context = {"casa":casa, 'logotipo':casa.logotipo, 'MEDIA_URL': MEDIA_URL}
html_template = render_to_string('relatorios/relatorio_ata.html',context)
html_header = render_to_string('relatorios/header_ata.html', header_context)
pdf_file = make_pdf(base_url=base_url,main_template=html_template,header_template=html_header)
response = HttpResponse(content_type='application/pdf;')
response['Content-Disposition'] = 'inline; filename=relatorio.pdf'
response['Content-Transfer-Encoding'] = 'binary'
response.write(pdf_file)
return response

103
sapl/sessao/tests/test_sessao_view.py

@ -4,7 +4,21 @@ from django.utils.translation import ugettext_lazy as _
from model_mommy import mommy from model_mommy import mommy
from sapl.parlamentares.models import Legislatura, SessaoLegislativa from sapl.parlamentares.models import Legislatura, SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria, TipoSessaoPlenaria from sapl.sessao.models import (SessaoPlenaria, TipoSessaoPlenaria,
IntegranteMesa, SessaoPlenariaPresenca,
JustificativaAusencia, ExpedienteSessao,
TipoExpediente, ExpedienteMateria,
Orador, OcorrenciaSessao)
from sapl.parlamentares.models import Parlamentar, CargoMesa, Filiacao
from sapl.sessao.views import (get_identificação_basica, get_conteudo_multimidia,
get_mesa_diretora, get_presenca_sessao,
get_expedientes, get_materias_expediente,
get_oradores_expediente, get_presenca_ordem_do_dia,
get_materias_ordem_do_dia, get_oradores_explicações_pessoais,
get_ocorrencias_da_sessão
)
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@ -47,3 +61,90 @@ def test_incluir_sessao_errors(admin_client):
[_('Este campo é obrigatório.')]) [_('Este campo é obrigatório.')])
assert (response.context_data['form'].errors['hora_inicio'] == assert (response.context_data['form'].errors['hora_inicio'] ==
[_('Este campo é obrigatório.')]) [_('Este campo é obrigatório.')])
@pytest.mark.django_db(transaction=False)
class TestResumoView():
def setup(self):
self.sessao_plenaria = mommy.make(SessaoPlenaria)
self.parlamentar = mommy.make(Parlamentar)
self.cargo_mesa = mommy.make(CargoMesa)
self.integrante_mesa = IntegranteMesa(sessao_plenaria=self.sessao_plenaria,
parlamentar=self.parlamentar,
cargo=self.cargo_mesa)
self.integrante_mesa.save()
def test_get_identificação_basica(self):
id_basica = get_identificação_basica(self.sessao_plenaria)
info_basica = id_basica['basica']
assert info_basica[0] == 'Tipo de Sessão: ' + str(self.sessao_plenaria.tipo)
data_inicio = self.sessao_plenaria.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
assert info_basica[1] == 'Abertura: ' + abertura +' - '+ self.sessao_plenaria.hora_inicio
data_fim = self.sessao_plenaria.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
assert info_basica[2] == 'Encerramento: ' + encerramento +' '+ self.sessao_plenaria.hora_fim
def test_get_conteudo_multimidia(self):
multimidia = get_conteudo_multimidia(self.sessao_plenaria)
url_audio = _('Audio: Indisponível')
multimidia_video = _('Video: Indisponível')
if self.sessao_plenaria.url_audio:
url_audio = _('Audio: ') + str(sessao_plenaria.url_audio)
if self.sessao_plenaria.url_video:
multimidia_video = _('Video: ') + str(sessao_plenaria.url_video)
assert multimidia == {'multimidia_audio':url_audio,
'multimidia_video':multimidia_video}
def test_get_mesa_diretora(self):
mesa = get_mesa_diretora(self.sessao_plenaria)
assert mesa == {'mesa':[{
'cargo': self.cargo_mesa,
'parlamentar': self.parlamentar
}]}
def test_get_presenca_sessao(self):
justificativa = mommy.make(JustificativaAusencia,sessao_plenaria=self.sessao_plenaria)
presenca = mommy.make(SessaoPlenariaPresenca,sessao_plenaria=self.sessao_plenaria)
resposta_presenca = get_presenca_sessao(self.sessao_plenaria)
assert resposta_presenca['presenca_sessao'] == [presenca.parlamentar]
assert resposta_presenca['justificativa_ausencia'][0] == justificativa
def test_get_expedientes(self):
tipo_expediente = mommy.make(TipoExpediente)
expediente = mommy.make(ExpedienteSessao,sessao_plenaria=self.sessao_plenaria,tipo=tipo_expediente)
resposta_expediente = get_expedientes(self.sessao_plenaria)
assert resposta_expediente['expedientes'] == [{
'conteudo': expediente.conteudo,
'tipo': tipo_expediente
}]
def test_get_materias_expediente(self):
pass
def test_get_oradores_explicações_pessoais(self):
parlamentar = mommy.make(Parlamentar)
partido_sigla = mommy.make(Filiacao, parlamentar=parlamentar)
orador = mommy.make(Orador,sessao_plenaria=self.sessao_plenaria,parlamentar=parlamentar)
resultado_get_oradores = get_oradores_explicações_pessoais(self.sessao_plenaria)
assert resultado_get_oradores['oradores_explicacoes'] == [{
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': partido_sigla.partido.sigla
}]
def test_get_ocorrencias_da_sessão(self):
ocorrencia = mommy.make(OcorrenciaSessao, sessao_plenaria=self.sessao_plenaria)
resultado_get_ocorrencia = get_ocorrencias_da_sessão(self.sessao_plenaria)
assert resultado_get_ocorrencia['ocorrencias_da_sessao'][0] == ocorrencia

524
sapl/sessao/views.py

@ -1294,137 +1294,290 @@ def get_turno(turno):
else: else:
return '' return ''
def get_identificação_basica(sessao_plenaria):
# =====================================================================
# Identificação Básica
data_inicio = sessao_plenaria.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
data_fim = sessao_plenaria.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
return({'basica': [
_('Tipo de Sessão: %(tipo)s') % {'tipo': sessao_plenaria.tipo},
_('Abertura: %(abertura)s - %(hora_inicio)s') % {
'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio},
_('Encerramento: %(encerramento)s %(hora_fim)s') % {
'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim}
]})
def get_conteudo_multimidia(sessao_plenaria):
context = {}
if sessao_plenaria.url_audio:
context['multimidia_audio'] = _('Audio: ') + str(sessao_plenaria.url_audio)
else:
context['multimidia_audio'] = _('Audio: Indisponível')
if sessao_plenaria.url_video:
context['multimidia_video'] = _('Video: ') + str(sessao_plenaria.url_video)
else:
context['multimidia_video'] = _('Video: Indisponível')
return context
class ResumoView(DetailView): def get_mesa_diretora(sessao_plenaria):
template_name = 'sessao/resumo.html' mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria)
model = SessaoPlenaria integrantes = []
logger = logging.getLogger(__name__) for m in mesa:
parlamentar = Parlamentar.objects.get(
def get(self, request, *args, **kwargs): id=m.parlamentar_id)
self.object = self.get_object() cargo = CargoMesa.objects.get(
context = self.get_context_data(object=self.object) id=m.cargo_id)
integrante = {'parlamentar': parlamentar, 'cargo': cargo}
# ===================================================================== integrantes.append(integrante)
# Identificação Básica return ({'mesa': ordenar_integrantes_por_cargo(integrantes)})
data_inicio = self.object.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else '' def get_presenca_sessao(sessao_plenaria):
presencas = SessaoPlenariaPresenca.objects.filter(
data_fim = self.object.data_fim sessao_plenaria_id=sessao_plenaria.id
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else '' ).order_by('parlamentar__nome_parlamentar')
parlamentares_sessao = [p.parlamentar for p in presencas]
ausentes_sessao = JustificativaAusencia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')
return ({'presenca_sessao': parlamentares_sessao,
'justificativa_ausencia': ausentes_sessao})
def get_expedientes(sessao_plenaria):
expediente = ExpedienteSessao.objects.filter(
sessao_plenaria_id=sessao_plenaria.id).order_by('tipo__nome')
expedientes = []
for e in expediente:
tipo = TipoExpediente.objects.get(id=e.tipo_id)
conteudo = e.conteudo
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
return ({'expedientes': expedientes})
def get_materias_expediente(sessao_plenaria):
materias = ExpedienteMateria.objects.filter(
sessao_plenaria_id=sessao_plenaria.id)
materias_expediente = []
for m in materias:
ementa = m.materia.ementa
titulo = m.materia
numero = m.numero_ordem
tramitacao = m.materia.tramitacao_set.last()
turno = None
context.update({'basica': [ if tramitacao:
_('Tipo de Sessão: %(tipo)s') % {'tipo': self.object.tipo}, turno = get_turno(tramitacao.turno)
_('Abertura: %(abertura)s - %(hora_inicio)s') % {
'abertura': abertura, 'hora_inicio': self.object.hora_inicio}, rv = m.registrovotacao_set.first()
_('Encerramento: %(encerramento)s %(hora_fim)s') % { rp = m.retiradapauta_set.filter(materia=m.materia).first()
'encerramento': encerramento, 'hora_fim': self.object.hora_fim} if rv:
]}) resultado = rv.tipo_resultado_votacao.nome
# ===================================================================== resultado_observacao = rv.observacao
# Conteúdo Multimídia elif rp:
if self.object.url_audio: resultado = rp.tipo_de_retirada.descricao
context.update({'multimidia_audio': resultado_observacao = rp.observacao
_('Audio: ') + str(self.object.url_audio)})
else:
context.update({'multimidia_audio': _('Audio: Indisponível')})
if self.object.url_video:
context.update({'multimidia_video':
_('Video: ') + str(self.object.url_video)})
else: else:
context.update({'multimidia_video': _('Video: Indisponível')}) resultado = _('Matéria não votada')
resultado_observacao = _(' ')
# =====================================================================
# Mesa Diretora autoria = Autoria.objects.filter(materia_id=m.materia_id)
mesa = IntegranteMesa.objects.filter( autor = [str(x.autor) for x in autoria]
sessao_plenaria=self.object)
mat = {'ementa': ementa,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': m.materia.numero_protocolo,
'numero_processo': m.materia.numeracao_set.last(),
'observacao': m.observacao
}
materias_expediente.append(mat)
context = {'materia_expediente': materias_expediente}
return context
integrantes = [] def get_oradores_expediente(sessao_plenaria):
for m in mesa: oradores = []
parlamentar = Parlamentar.objects.get( for orador in OradorExpediente.objects.filter(
id=m.parlamentar_id) sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'):
cargo = CargoMesa.objects.get( numero_ordem = orador.numero_ordem
id=m.cargo_id) url_discurso = orador.url_discurso
integrante = {'parlamentar': parlamentar, 'cargo': cargo} observacao = orador.observacao
integrantes.append(integrante) parlamentar = Parlamentar.objects.get(
id=orador.parlamentar_id)
ora = {'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
'parlamentar': parlamentar,
'observacao': observacao
}
oradores.append(ora)
context = {'oradores': oradores}
return context
context.update({'mesa': ordenar_integrantes_por_cargo(integrantes)}) def get_presenca_ordem_do_dia(sessao_plenaria):
mesa_aux = get_mesa_diretora(sessao_plenaria)
presencas = PresencaOrdemDia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')
# ===================================================================== parlamentares_mesa_dia = [m for m in mesa_aux['mesa']]
# Presença Sessão
presencas = SessaoPlenariaPresenca.objects.filter( presidente_dia = ''
sessao_plenaria_id=self.object.id for m in mesa_aux['mesa']:
).order_by('parlamentar__nome_parlamentar') if m['cargo'].descricao == 'Presidente':
presidente_dia = [m['parlamentar']]
break
parlamentares_sessao = [p.parlamentar for p in presencas] parlamentares_ordem = [p.parlamentar for p in presencas]
ausentes_sessao = JustificativaAusencia.objects.filter( cont = 0
sessao_plenaria_id=self.object.id for index, parlamentar in enumerate(parlamentares_ordem):
).order_by('parlamentar__nome_parlamentar') try:
if parlamentar == parlamentares_mesa_dia[cont]["parlamentar"]:
del(parlamentares_ordem[index])
cont += 1
except IndexError:
pass
context.update({'presenca_sessao': parlamentares_sessao, context ={}
'justificativa_ausencia': ausentes_sessao}) context.update({'presenca_ordem': parlamentares_ordem})
# ===================================================================== config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
# Expedientes if config_assinatura_ata == 'T' and parlamentares_ordem:
expediente = ExpedienteSessao.objects.filter( context.update(
sessao_plenaria_id=self.object.id).order_by('tipo__nome') {'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
context.update({'assinatura_mesa':parlamentares_mesa_dia,'assinatura_presentes': parlamentares_ordem})
elif config_assinatura_ata == 'M' and parlamentares_mesa_dia:
context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_presentes': parlamentares_mesa_dia})
elif config_assinatura_ata == 'P' and presidente_dia:
context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'})
context.update({'assinatura_presentes': presidente_dia})
expedientes = [] return context
for e in expediente:
tipo = TipoExpediente.objects.get(id=e.tipo_id)
conteudo = e.conteudo
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
context.update({'expedientes': expedientes})
# ===================================================================== def get_materias_ordem_do_dia(sessao_plenaria):
# Matérias Expediente ordem = OrdemDia.objects.filter(sessao_plenaria_id=sessao_plenaria.id)
materias = ExpedienteMateria.objects.filter( materias_ordem = []
sessao_plenaria_id=self.object.id) for o in ordem:
ementa = o.materia.ementa
ementa_observacao = o.observacao
titulo = o.materia
numero = o.numero_ordem
tramitacao = o.materia.tramitacao_set.last()
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
materias_expediente = [] # Verificar resultado
for m in materias: rv = o.registrovotacao_set.filter(materia=o.materia).first()
rp = o.retiradapauta_set.filter(materia=o.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
ementa = m.materia.ementa elif rp:
titulo = m.materia resultado = rp.tipo_de_retirada.descricao
numero = m.numero_ordem resultado_observacao = rp.observacao
tramitacao = m.materia.tramitacao_set.last()
turno = None
if tramitacao: else:
turno = get_turno(tramitacao.turno) resultado = _('Matéria não votada')
resultado_observacao = _(' ')
voto_sim = ""
voto_nao = ""
voto_abstencoes = ""
voto_nominal = []
if o.tipo_votacao == 2:
votos = VotoParlamentar.objects.filter(ordem=o.id)
for voto in votos:
aux_voto = (voto.parlamentar.nome_completo, voto.voto)
voto_nominal.append(aux_voto)
try:
voto = RegistroVotacao.objects.filter(ordem=o.id).last()
voto_sim = voto.numero_votos_sim
voto_nao = voto.numero_votos_nao
voto_abstencoes = voto.numero_abstencoes
except AttributeError:
voto_sim = " Não Informado"
voto_nao = " Não Informado"
voto_abstencoes = " Não Informado"
autoria = Autoria.objects.filter(
materia_id=o.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'ementa_observacao': ementa_observacao,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': o.materia.numero_protocolo,
'numero_processo': o.materia.numeracao_set.last(),
'tipo_votacao': o.TIPO_VOTACAO_CHOICES[o.tipo_votacao],
'voto_sim':voto_sim,
'voto_nao':voto_nao,
'voto_abstencoes':voto_abstencoes,
'voto_nominal': voto_nominal,
}
materias_ordem.append(mat)
context = {'materias_ordem': materias_ordem}
return context
rv = m.registrovotacao_set.first() def get_oradores_explicações_pessoais(sessao_plenaria):
rp = m.retiradapauta_set.filter(materia=m.materia).first() oradores_explicacoes = []
if rv: for orador in Orador.objects.filter(
resultado = rv.tipo_resultado_votacao.nome sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'):
resultado_observacao = rv.observacao for parlamentar in Parlamentar.objects.filter(
elif rp: id=orador.parlamentar.id):
resultado = rp.tipo_de_retirada.descricao partido_sigla = Filiacao.objects.filter(
resultado_observacao = rp.observacao parlamentar=parlamentar).last()
if not partido_sigla:
sigla = ''
else: else:
resultado = _('Matéria não votada') sigla = partido_sigla.partido.sigla
resultado_observacao = _(' ') oradores = {
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': sigla
}
oradores_explicacoes.append(oradores)
context = {'oradores_explicacoes': oradores_explicacoes}
return context
autoria = Autoria.objects.filter(materia_id=m.materia_id) def get_ocorrencias_da_sessão(sessao_plenaria):
autor = [str(x.autor) for x in autoria] ocorrencias_sessao = OcorrenciaSessao.objects.filter(
sessao_plenaria_id=sessao_plenaria.id)
context = {'ocorrencias_da_sessao': ocorrencias_sessao}
return context
mat = {'ementa': ementa,
'titulo': titulo, class ResumoView(DetailView):
'numero': numero, template_name = 'sessao/resumo.html'
'turno': turno, model = SessaoPlenaria
'resultado': resultado, logger = logging.getLogger(__name__)
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': m.materia.numero_protocolo,
'numero_processo': m.materia.numeracao_set.last(),
'observacao': m.observacao
}
materias_expediente.append(mat)
context.update({'materia_expediente': materias_expediente}) def get_context(self,*args, **kwargs):
self.object = self.get_object()
# Votos de Votação Nominal de Matérias Expediente context = self.get_context_data(object=self.object)
# Votos de Votação Nominal de Matérias Expediente
materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter( materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter(
sessao_plenaria_id=self.object.id, sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia') tipo_votacao=2).order_by('-materia')
@ -1446,107 +1599,34 @@ class ResumoView(DetailView):
votacoes.append(dados_votacao) votacoes.append(dados_votacao)
context.update({'votos_nominais_materia_expediente': votacoes}) context.update({'votos_nominais_materia_expediente': votacoes})
# =====================================================================
# Identificação Básica
context.update(get_identificação_basica(self.object))
# =====================================================================
# Conteúdo Multimídia
context.update(get_conteudo_multimidia(self.object))
# =====================================================================
# Mesa Diretora
context.update(get_mesa_diretora(self.object))
# =====================================================================
# Presença Sessão
context.update(get_presenca_sessao(self.object))
# =====================================================================
# Expedientes
context.update(get_expedientes(self.object))
# =====================================================================
# Matérias Expediente
context.update(get_materias_expediente(self.object))
# ===================================================================== # =====================================================================
# Oradores Expediente # Oradores Expediente
oradores = [] context.update(get_oradores_expediente(self.object))
for orador in OradorExpediente.objects.filter(
sessao_plenaria_id=self.object.id).order_by('numero_ordem'):
numero_ordem = orador.numero_ordem
url_discurso = orador.url_discurso
observacao = orador.observacao
parlamentar = Parlamentar.objects.get(
id=orador.parlamentar_id)
ora = {'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
'parlamentar': parlamentar,
'observacao': observacao
}
oradores.append(ora)
context.update({'oradores': oradores})
# ===================================================================== # =====================================================================
# Presença Ordem do Dia # Presença Ordem do Dia
presencas = PresencaOrdemDia.objects.filter( context.update(get_presenca_ordem_do_dia(self.object))
sessao_plenaria_id=self.object.id
).order_by('parlamentar__nome_parlamentar')
parlamentares_mesa_dia = [m['parlamentar'] for m in context['mesa']]
# composicao_mesa = ComposicaoMesa.objects.filter(sessao_legislativa=sessao)
presidente_dia = ''
for m in context['mesa']:
if m['cargo'].descricao == 'Presidente':
presidente_dia = [m['parlamentar']]
break
parlamentares_ordem = [p.parlamentar for p in presencas]
context.update({'presenca_ordem': parlamentares_ordem})
config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
if config_assinatura_ata == 'T' and parlamentares_ordem:
context.update(
{'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
context.update({'assinatura_presentes': parlamentares_ordem})
elif config_assinatura_ata == 'M' and parlamentares_mesa_dia:
context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_presentes': parlamentares_mesa_dia})
elif config_assinatura_ata == 'P' and presidente_dia:
context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'})
context.update({'assinatura_presentes': presidente_dia})
# ===================================================================== # =====================================================================
# Matérias Ordem do Dia # Matérias Ordem do Dia
ordem = OrdemDia.objects.filter( # Votos de Votação Nominal de Matérias Ordem do Dia
sessao_plenaria_id=self.object.id)
materias_ordem = []
for o in ordem:
ementa = o.materia.ementa
ementa_observacao = o.observacao
titulo = o.materia
numero = o.numero_ordem
tramitacao = o.materia.tramitacao_set.last()
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
# Verificar resultado
rv = o.registrovotacao_set.filter(materia=o.materia).first()
rp = o.retiradapauta_set.filter(materia=o.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
elif rp:
resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ')
autoria = Autoria.objects.filter(
materia_id=o.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'ementa_observacao': ementa_observacao,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': o.materia.numero_protocolo,
'numero_processo': o.materia.numeracao_set.last()
}
materias_ordem.append(mat)
context.update({'materias_ordem': materias_ordem})
# Votos de Votação Nominal de Matérias Ordem do Dia
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter( materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id, sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia') tipo_votacao=2).order_by('-materia')
@ -1569,34 +1649,13 @@ class ResumoView(DetailView):
context.update({'votos_nominais_materia_ordem_dia': votacoes_od}) context.update({'votos_nominais_materia_ordem_dia': votacoes_od})
context.update(get_materias_ordem_do_dia(self.object))
# ===================================================================== # =====================================================================
# Oradores nas Explicações Pessoais # Oradores nas Explicações Pessoais
oradores_explicacoes = [] context.update(get_oradores_explicações_pessoais(self.object))
for orador in Orador.objects.filter(
sessao_plenaria_id=self.object.id).order_by('numero_ordem'):
for parlamentar in Parlamentar.objects.filter(
id=orador.parlamentar.id):
partido_sigla = Filiacao.objects.filter(
parlamentar=parlamentar).last()
if not partido_sigla:
sigla = ''
else:
sigla = partido_sigla.partido.sigla
oradores = {
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': sigla
}
oradores_explicacoes.append(oradores)
context.update({'oradores_explicacoes': oradores_explicacoes})
# ===================================================================== # =====================================================================
# Ocorrẽncias da Sessão # Ocorrẽncias da Sessão
ocorrencias_sessao = OcorrenciaSessao.objects.filter( context.update(get_ocorrencias_da_sessão(self.object))
sessao_plenaria_id=self.object.id)
context.update({'ocorrencias_da_sessao': ocorrencias_sessao})
# ===================================================================== # =====================================================================
# Indica a ordem com a qual o template será renderizado # Indica a ordem com a qual o template será renderizado
ordenacao = ResumoOrdenacao.objects.first() ordenacao = ResumoOrdenacao.objects.first()
@ -1667,9 +1726,14 @@ class ResumoView(DetailView):
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao'] 'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
}) })
return context
def get(self, request, *args, **kwargs):
context = self.get_context()
return self.render_to_response(context) return self.render_to_response(context)
class ResumoAtaView(ResumoView): class ResumoAtaView(ResumoView):
template_name = 'sessao/resumo_ata.html' template_name = 'sessao/resumo_ata.html'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

62
sapl/static/sapl/css/header-relatorio.css

@ -0,0 +1,62 @@
html body p {
border-top: 1px solid black;
text-align: center;
font-size: 11pt;
padding: 5px;
margin-top: -15px;
}
html body section {
box-sizing: border-box;
}
html body section dl {
display: flex;
flex-wrap: wrap;
rows: 2;
columns: 2;
}
html body section dt{
width: 50px;
}
html body section dd {
max-width:550px;
text-align: center;
}
html body section dd ul li {
list-style-type: none;
margin-left: 90px;
margin-bottom: -15px;
}
h2 {
font-size: 14pt;
}
h3 {
font-size: 10pt;
color: #6e6e6e;
}
ul {
padding: 0;
list-style: none;
margin-top:10px;
}
html body section dt img {
max-width:80px;
margin-left: 20px;
margin-left: 50px;
}
h3 {
font-size: 10pt;
color: #6e6e6e;
}
ul {
padding: 0;
list-style: none;
margin-top:10px;
}
html body section dt img {
max-width:80px;
margin-left: 20px;
}

56
sapl/static/sapl/css/relatorio.css

@ -0,0 +1,56 @@
@page{
margin-top: 4.5cm;
size: A4 portrait;
}
h2.gray-title{
color: gray;
font-size: 14pt;
break-after: avoid-page;
page-break-after: avoid;
}
h3 {
font-size: 10pt;
break-after: avoid-page;
page-break-after: avoid;
}
p {
font-size: 10pt;
text-align: justify;
text-justify: inter-word;
}
fieldset {
border: 0;
}
html body section {
box-sizing: border-box;
}
html body section dl {
display: flex;
flex-wrap: wrap;
columns: 5;
}
html body section dt{
width: 50px;
}
html body section dd {
text-align: center;
}
html body section dd ul li {
list-style-type: none;
margin-left: 50px;
}
fieldset {
page-break-after: avoid;
margin:5px;
padding:0px;
}

31
sapl/templates/relatorios/header_ata.html

@ -0,0 +1,31 @@
{% load common_tags %}
{% load render_bundle from webpack_loader %}
{% load webpack_static from webpack_loader %}
{% load static %}
<!DOCTYPE html>
<meta charset="utf-8">
</meta>
<html lang="pt-br">
<head>
<link rel="stylesheet" href="{% static 'sapl/css/header-relatorio.css'%}">
</head>
<body>
<section id="informations">
<dl>
<dt class="image-header">
<img src="{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% webpack_static 'img/logo.png' %}{% endif %}">
</dt>
<dd class="title">
<ul>
<li style="margin-top:10px"><h2>{{casa}}</h2></li>
<li><h3>Sistema de Apoio ao Processo Legislativo</h3></li>
</ul>
</dd>
</dl>
</section>
<p></p>
</body>
</html>

101
sapl/templates/relatorios/relatorio_ata.html

@ -0,0 +1,101 @@
{% load common_tags %}
{% load static %}
<head>
<style>
@page{
@bottom-right {
content: "Página" counter(page);
height: 3cm;
font-size: 8pt;
}
@bottom-center {
border-top: 1px solid black;
font-size: 8pt;
height: 1cm;
content: "{{rodape|safe}}";
font-style:italic;
}
@bottom-left {
content: "{{data}}";
height: 3cm;
font-size: 8pt;
}
@top-center {
content: string(title);
}
header {
width: 0;
height: 0;
visibility: hidden;
string-set: title content();
}
}
</style>
<link rel="stylesheet" href="{% static '/sapl/css/relatorio.css'%}">
</head>
<body>
<h3 style="text-align:center;">Extrato Reunião</h3>
{% include 'sessao/blocos_ata/identificacao_basica.html' %}
{% include 'sessao/blocos_ata/mesa_diretora.html' %}
{% include 'sessao/blocos_ata/lista_presenca.html' %}
{% include 'sessao/blocos_ata/expedientes.html' %}
{% include 'sessao/blocos_ata/materias_expediente.html' %}
{% include 'sessao/blocos_ata/oradores_expediente.html' %}
{% include 'sessao/blocos_ata/lista_presenca_ordem_dia.html' %}
{% include 'sessao/blocos_ata/materias_ordem_dia.html' %}
{% include 'sessao/blocos_ata/oradores_explicacoes.html' %}
{% if assinatura_mesa or assinatura_presentes %}
<div style="page-break-before: always;padding:5px;margin-top:80px;border-top: 1px solid black;">
<legend >{{texto_assinatura}}</legend>
<table style="margin-top:80px">
<colgroup>
<col>
</colgroup>
<tbody>
{% for p in assinatura_mesa %}
{% if forloop.counter0|divisibleby:2 %}
<tr style="margin-top:0px">
<td>
<div style="float: left; position: relative; top: -80px; left: 8px; width: 120px">____________________ </br>
<p style="font-size:8pt"><b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br>
</div>
{% else %}
<div style="float: left; position: relative; top: -80px; left: 142px; width: 120px; margin-right:-220px;">____________________ </br>
<p style="font-size:8pt"><b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
{% for p in assinatura_presentes %}
{% if forloop.counter0|divisibleby:2 %}
<tr style="margin-top:0px">
<td>
<div style="float: left; position: relative;top: -80px; left: 8px; width: 120px;">_____________________</br>
<p style="font-size:8pt">{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br>
</div>
{% else %}
<div style="float: left; position: relative; top: -80px;left: 142px; width: 120px; margin-right:-220px;">_____________________ </br>
<p style="font-size:8pt">{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% endif%}
</div>
</body>

12
sapl/templates/sessao/blocos_ata/assinaturas.html

@ -1,13 +1,17 @@
{% load common_tags %} {% load common_tags %}
<fieldset>
</p>
</p>
<legend>{{texto_assinatura}}</legend> <legend>{{texto_assinatura}}</legend>
<div class="row"> <div class="row">
</br></br> </br></br>
{% for p in assinatura_mesa %}
<div class="col-md-6">___________________________________________ </br>
<b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}
</br></br></br>
</div>
{% endfor %}
{% for p in assinatura_presentes %} {% for p in assinatura_presentes %}
<div class="col-md-6">___________________________________________ </br> <div class="col-md-6">___________________________________________ </br>
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
</br></br></br> </br></br></br>
</div> </div>
{% endfor %} {% endfor %}

4
sapl/templates/sessao/blocos_ata/lista_presenca.html

@ -5,7 +5,7 @@
{% if presenca_sessao %} {% if presenca_sessao %}
<strong>Lista de Presença na Sessão: </strong> <strong>Lista de Presença na Sessão: </strong>
{% for p in presenca_sessao %} {% for p in presenca_sessao %}
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>
@ -13,7 +13,7 @@
{% if justificativa_ausencia %} {% if justificativa_ausencia %}
<strong>Justificativas de Ausências na Sessão: </strong> <strong>Justificativas de Ausências na Sessão: </strong>
{% for j in justificativa_ausencia %} {% for j in justificativa_ausencia %}
{{j.parlamentar}} / {{ j.tipo_ausencia }} ; {{j.parlamentar.nome_completo}} / {{ j.tipo_ausencia }} ;
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

2
sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html

@ -5,7 +5,7 @@
{% if presenca_ordem %} {% if presenca_ordem %}
<strong>Lista de Presença na Ordem do Dia: </strong> <strong>Lista de Presença na Ordem do Dia: </strong>
{% for p in presenca_ordem %} {% for p in presenca_ordem %}
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

52
sapl/templates/sessao/blocos_ata/materias_ordem_dia.html

@ -1,24 +1,34 @@
<fieldset> <fieldset>
</br>
<p align="justify"> <strong>Matérias da Ordem do Dia: </strong>
{% if materias_ordem %} </br></br>
<strong>Matérias da Ordem do Dia: </strong> {% for m in materias_ordem %}
{% for m in materias_ordem %} <fieldset style="border-top: 1px solid black;">
<b>{{m.numero}} - {{m.titulo}} </b> <b>{{m.numero}} - {{m.titulo}} </b></br>
{% if m.turno %} <b>Turno:</b>{{m.turno}}</br>
Turno:{{m.turno}} <b>Autor: </b>{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}
{% if m.numero_protocolo %}
<b>Número de Protocolo:</b> {{ m.numero_protocolo }}
{% endif %}
{% if m.numero_processo %}
<b>Processo:</b> {{ m.numero_processo }}
{% endif %}
<p><b>Descrição:</b> {{m.ementa|safe}}</p>
<b>Resultado:</b> {{m.resultado}} {{m.resultado_observacao}}
<dl>
<p><b>Tipo:</b> {{m.tipo_votacao}}</p>
<dt>Sim:{{m.voto_sim}}</dt>
<dt>Não:{{m.voto_nao}}</dd>
<dt>Abstenções:{{m.voto_abstencoes}}</dt>
</dl>
{% if m.voto_nominal%}
<b>Votos Nominais</b>
<ul>
{% for voto in m.voto_nominal %}
<li>{{voto.0}} - {{voto.1}}</li>
{% endfor %}
</ul>
{% endif %} {% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} </fieldset>
{% if m.numero_protocolo %} {% endfor %}
Número de Protocolo: {{ m.numero_protocolo }}
{% endif %}
{% if m.numero_processo %}
Processo: {{ m.numero_processo }}
{% endif %}
{{m.ementa|safe}}
{{m.resultado}} {{m.resultado_observacao}}
{% endfor %}
{% endif %}
</p>
</fieldset> </fieldset>

2
sapl/templates/sessao/blocos_ata/mesa_diretora.html

@ -4,7 +4,7 @@
<strong>Mesa Diretora: </strong> <strong>Mesa Diretora: </strong>
{% for m in mesa %} {% for m in mesa %}
{{m.cargo}}: {{m.cargo}}:
{{m.parlamentar.nome_parlamentar}} / {{ m.parlamentar.filiacao_atual }} ; {{m.parlamentar.nome_completo}} / {{ m.parlamentar.filiacao_atual }} ;
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

2
sapl/templates/sessao/blocos_ata/oradores_expediente.html

@ -3,7 +3,7 @@
{% if oradores %} {% if oradores %}
<strong>Oradores do Expediente: </strong> <strong>Oradores do Expediente: </strong>
{% for o in oradores %} {% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div> <div><b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}}</div>
<div>{{o.url_discurso}}</div> <div>{{o.url_discurso}}</div>
<div>{{o.observacao}}</div> <div>{{o.observacao}}</div>
</br> </br>

2
sapl/templates/sessao/blocos_ata/oradores_explicacoes.html

@ -3,7 +3,7 @@
{% if oradores_explicacoes %} {% if oradores_explicacoes %}
<strong>Oradores das Explicações Pessoais: </strong> <strong>Oradores das Explicações Pessoais: </strong>
{% for o in oradores_explicacoes %} {% for o in oradores_explicacoes %}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }} ; <b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }} ;
{{o.url_discurso}} {{o.url_discurso}}
{% endfor %} {% endfor %}
{% endif %} {% endif %}

12
sapl/templates/sessao/resumo_ata.html

@ -6,7 +6,17 @@
<h1 class="page-header"> <h1 class="page-header">
Extrato Eletrônico da {{sessaoplenaria}} Extrato Eletrônico da {{sessaoplenaria}}
</h1> </h1>
{% endblock %}
<div>
<p align="right">
<strong>
<a href="{% url 'sapl.relatorios:resumo_ata_pdf' sessaoplenaria.pk %}">
Impressão PDF
</a>
</strong>
</p>
</div>
{% endblock title %}
{% block detail_content %} {% block detail_content %}
{% include 'sessao/blocos_ata/'|add:primeiro_ordenacao %} {% include 'sessao/blocos_ata/'|add:primeiro_ordenacao %}

Loading…
Cancel
Save