Browse Source

Implementa Relatório de Votações Nominais

pull/3783/head
root 1 week ago
parent
commit
317e60e5c7
  1. 67
      sapl/relatorios/forms.py
  2. 5
      sapl/relatorios/urls.py
  3. 78
      sapl/relatorios/views.py
  4. 15
      sapl/sessao/models.py
  5. 59
      sapl/templates/materia/materialegislativa_filter.html
  6. 79
      sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html
  7. 49
      sapl/templates/relatorios/relatorio_votacao_nominal.html
  8. 7
      sapl/templates/relatorios/relatorios_list.html
  9. 122
      sapl/utils.py

67
sapl/relatorios/forms.py

@ -3,6 +3,7 @@ from crispy_forms.bootstrap import (FormActions)
from crispy_forms.layout import (HTML, Button, Fieldset, from crispy_forms.layout import (HTML, Button, Fieldset,
Layout, Submit) Layout, Submit)
from django import forms from django import forms
from django.forms import ModelChoiceField
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.audiencia.models import AudienciaPublica from sapl.audiencia.models import AudienciaPublica
@ -10,10 +11,10 @@ from sapl.base.models import Autor
from sapl.comissoes.models import Reuniao from sapl.comissoes.models import Reuniao
from sapl.crispy_layout_mixin import SaplFormHelper, to_row, form_actions from sapl.crispy_layout_mixin import SaplFormHelper, to_row, form_actions
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, MateriaEmTramitacao, UnidadeTramitacao, \ from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, MateriaEmTramitacao, UnidadeTramitacao, \
StatusTramitacao StatusTramitacao, TipoMateriaLegislativa
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica
from sapl.protocoloadm.models import DocumentoAdministrativo from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria, VotoParlamentar
from sapl.utils import FilterOverridesMetaMixin, choice_anos_com_normas, qs_override_django_filter, \ from sapl.utils import FilterOverridesMetaMixin, choice_anos_com_normas, qs_override_django_filter, \
choice_anos_com_materias, choice_tipos_normas, autor_label, autor_modal choice_anos_com_materias, choice_tipos_normas, autor_label, autor_modal
@ -68,6 +69,68 @@ class RelatorioDocumentosAcessoriosFilterSet(django_filters.FilterSet):
) )
class RelatorioVotacoesNominaisFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioVotacoesNominaisFilterSet, self).qs
return parent.distinct().order_by('-votacao_id', 'parlamentar')
class Meta(FilterOverridesMetaMixin):
model = VotoParlamentar
fields = ['data_hora']
def __init__(self, *args, **kwargs):
super(
RelatorioVotacoesNominaisFilterSet, self
).__init__(*args, **kwargs)
self.filters['data_hora'].label = 'Período (Data Inicial - Data Final)'
tipo_materia = '''<div class="col-md-6"><div id="div_id_tipo_materia" class="form-group"><label for="id_tipo_materia" class="col-form-label ">
Tipo de Matéria Legislativa
</label><div class=""><select name="tipo_materia" class="select form-control" id="id_tipo_materia"><option value="" selected="">---------</option>'''
for tipo in TipoMateriaLegislativa.objects.all():
tipo_materia += '<option value="' + str(tipo.id) + '">' + tipo.descricao + '</option>'
tipo_materia += '</select></div></div></div>'
numero = '''<div id="div_id_numero" class="col-md-3"><label for="id_numero" class="col-form-label ">Número</label>
<div class=""><input type="number" name="numero" step="any" class="numberinput form-control" id="id_numero"></div></div>'''
ano = '''<div id="div_id_ano" class="col-md-3"><label for="id_ano" class="col-form-label ">Ano da Matéria</label>
<div class=""><select name="ano" class="select form-control" id="id_ano"><option value="" selected="">---------</option>'''
for ano_materia in choice_anos_com_materias():
ano += '<option value="' + str(ano_materia[0]) + '">' + str(ano_materia[1]) + '</option>'
ano += '</select></div></div>'
row0= HTML('<div class="row">' + tipo_materia + numero + ano + '</div>')
row1 = to_row([('data_hora', 12)])
buttons = FormActions(
*[
HTML('''
<div class="form-check">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div>
''')
],
Submit('pesquisar', _('Pesquisar'), css_class='float-right',
onclick='return true;'),
css_class='form-group row justify-content-between',
)
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa'),
row0, row1,
buttons)
)
class RelatorioAtasFilterSet(django_filters.FilterSet): class RelatorioAtasFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin): class Meta(FilterOverridesMetaMixin):
model = SessaoPlenaria model = SessaoPlenaria

5
sapl/relatorios/urls.py

@ -11,7 +11,7 @@ from .views import (relatorio_capa_processo,
RelatorioMateriasTramitacaoView, RelatorioMateriaAnoAssuntoView, RelatorioHistoricoTramitacaoView, RelatorioMateriasTramitacaoView, RelatorioMateriaAnoAssuntoView, RelatorioHistoricoTramitacaoView,
RelatorioDataFimPrazoTramitacaoView, RelatorioPresencaSessaoView, RelatorioAtasView, RelatorioDataFimPrazoTramitacaoView, RelatorioPresencaSessaoView, RelatorioAtasView,
RelatorioReuniaoView, RelatorioAudienciaView, RelatorioHistoricoTramitacaoAdmView, RelatorioReuniaoView, RelatorioAudienciaView, RelatorioHistoricoTramitacaoAdmView,
RelatorioDocumentosAcessoriosView, RelatorioNormasPorAutorView) RelatorioDocumentosAcessoriosView, RelatorioNormasPorAutorView, RelatorioVotacoesNominaisView)
from ..base.views import EstatisticasAcessoNormas from ..base.views import EstatisticasAcessoNormas
app_name = AppConfig.name app_name = AppConfig.name
@ -95,6 +95,9 @@ urlpatterns = [
url(r'^sistema/relatorios/documentos_acessorios$', url(r'^sistema/relatorios/documentos_acessorios$',
RelatorioDocumentosAcessoriosView.as_view(), RelatorioDocumentosAcessoriosView.as_view(),
name='relatorio_documentos_acessorios'), name='relatorio_documentos_acessorios'),
url(r'^sistema/relatorios/votacoes_nominais$',
RelatorioVotacoesNominaisView.as_view(),
name='relatorio_votacoes_nominais'),
url(r'^sistema/relatorios/normas-por-autor$', url(r'^sistema/relatorios/normas-por-autor$',
RelatorioNormasPorAutorView.as_view(), name='normas_por_autor'), RelatorioNormasPorAutorView.as_view(), name='normas_por_autor'),
] ]

78
sapl/relatorios/views.py

@ -31,7 +31,8 @@ from sapl.relatorios.forms import RelatorioNormasPorAutorFilterSet, RelatorioHis
RelatorioNormasVigenciaFilterSet, RelatorioNormasMesFilterSet, RelatorioMateriasPorAutorFilterSet, \ RelatorioNormasVigenciaFilterSet, RelatorioNormasMesFilterSet, RelatorioMateriasPorAutorFilterSet, \
RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasTramitacaoFilterSet, RelatorioAudienciaFilterSet, \ RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasTramitacaoFilterSet, RelatorioAudienciaFilterSet, \
RelatorioReuniaoFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet, RelatorioHistoricoTramitacaoFilterSet, \ RelatorioReuniaoFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet, RelatorioHistoricoTramitacaoFilterSet, \
RelatorioPresencaSessaoFilterSet, RelatorioAtasFilterSet, RelatorioDocumentosAcessoriosFilterSet RelatorioPresencaSessaoFilterSet, RelatorioAtasFilterSet, RelatorioDocumentosAcessoriosFilterSet, \
RelatorioVotacoesNominaisFilterSet
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao, from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, JustificativaAusencia, IntegranteMesa, JustificativaAusencia,
Orador, OradorExpediente, Orador, OradorExpediente,
@ -50,7 +51,7 @@ from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora,
from sapl.settings import MEDIA_URL from sapl.settings import MEDIA_URL
from sapl.settings import STATIC_ROOT from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode, show_results_filter_set, \ from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode, show_results_filter_set, \
num_materias_por_tipo, parlamentares_ativos num_materias_por_tipo, parlamentares_ativos, VotacoesMultiFormatOutputMixin
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,
@ -1560,6 +1561,10 @@ def relatorio_documento_acessorio(obj, request, context):
return cria_relatorio(request, context, 'relatorios/relatorio_documento_acessorio.html') return cria_relatorio(request, context, 'relatorios/relatorio_documento_acessorio.html')
def relatorio_votacao_nominal(obj, request, context):
return cria_relatorio(request, context, 'relatorios/relatorio_votacao_nominal.html')
def relatorio_normas_por_autor(obj, request, context): def relatorio_normas_por_autor(obj, request, context):
return cria_relatorio(request, context, 'relatorios/relatorio_normas_por_autor.html') return cria_relatorio(request, context, 'relatorios/relatorio_normas_por_autor.html')
@ -1880,6 +1885,75 @@ class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
return context return context
class RelatorioVotacoesNominaisView(RelatorioMixin, VotacoesMultiFormatOutputMixin, FilterView):
model = VotoParlamentar
filterset_class = RelatorioVotacoesNominaisFilterSet
template_name = 'relatorios/RelatorioVotacoesNominais_filter.html'
relatorio = relatorio_votacao_nominal
fields_base_report = [
'votacao_id', 'votacao', 'parlamentar__nome_parlamentar', 'voto'
]
fields_report = {
'csv': fields_base_report,
'xlsx': fields_base_report,
'json': fields_base_report,
}
def get_context_data(self, **kwargs):
context = super(
RelatorioVotacoesNominaisView, self
).get_context_data(**kwargs)
context['title'] = _('Votações Nominais')
if not self.filterset.form.is_valid():
return context
query_dict = self.request.GET.copy()
context['filter_url'] = ('&' + query_dict.urlencode()) if len(query_dict) > 0 else ''
context['show_results'] = show_results_filter_set(query_dict)
data_inicial = self.request.GET['data_hora_0']
data_final = self.request.GET['data_hora_1']
if not data_inicial:
data_inicial = "Data Inicial não definida"
if not data_final:
data_final = "Data Final não definida"
context['periodo'] = (
data_inicial + ' - ' + data_final
)
if self.request.GET['tipo_materia'] or self.request.GET['numero'] or self.request.GET['ano']:
object_list = context['object_list']
if self.request.GET['tipo_materia']:
tipo_id = self.request.GET['tipo_materia']
context['tipo_materia'] = TipoMateriaLegislativa.objects.get(id=tipo_id)
object_list = object_list.filter(
Q(ordem__materia__tipo_id=tipo_id) |
Q(expediente__materia__tipo_id=tipo_id))
if self.request.GET['numero']:
numero = self.request.GET['numero']
context['numero'] = numero
object_list = object_list.filter(
Q(ordem__materia__numero=numero) |
Q(expediente__materia__numero=numero))
if self.request.GET['ano']:
ano = self.request.GET['ano']
context['ano'] = ano
object_list = object_list.filter(
Q(ordem__materia__ano=ano) |
Q(expediente__materia__ano=ano))
context['object_list'] = object_list
if not 'format' in query_dict:
context['qtde_votacoes'] = context['object_list'].distinct('votacao_id').count()
return context
class RelatorioAtasView(RelatorioMixin, FilterView): class RelatorioAtasView(RelatorioMixin, FilterView):
model = SessaoPlenaria model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet filterset_class = RelatorioAtasFilterSet

15
sapl/sessao/models.py

@ -641,11 +641,14 @@ class RegistroVotacao(models.Model):
ordering = ('id',) ordering = ('id',)
def __str__(self): def __str__(self):
return _('Ordem: %(ordem)s - Votação: %(votacao)s - ' if self.ordem:
'Matéria: %(materia)s') % { return _('Ordem: %(ordem)s - Votação: %(votacao)s') % {
'ordem': self.ordem, 'ordem': self.ordem,
'votacao': self.tipo_resultado_votacao, 'votacao': self.tipo_resultado_votacao}
'materia': self.materia} else:
return _('Expediente: %(expediente)s - Votação: %(votacao)s') % {
'expediente': self.expediente,
'votacao': self.tipo_resultado_votacao}
def clean(self): def clean(self):
"""Exatamente um dos campos ordem ou expediente deve estar preenchido. """Exatamente um dos campos ordem ou expediente deve estar preenchido.
@ -696,7 +699,7 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
class Meta: class Meta:
verbose_name = _('Registro de Votação de Parlamentar') verbose_name = _('Registro de Votação de Parlamentar')
verbose_name_plural = _('Registros de Votações de Parlamentares') verbose_name_plural = _('Registros de Votações de Parlamentares')
ordering = ('id',) ordering = ('parlamentar',)
def __str__(self): def __str__(self):
return _('Votação: %(votacao)s - Parlamentar: %(parlamentar)s') % { return _('Votação: %(votacao)s - Parlamentar: %(parlamentar)s') % {

59
sapl/templates/materia/materialegislativa_filter.html

@ -108,19 +108,47 @@
<strong>Resultado:</strong> &nbsp;{{m|resultado_votacao}}</br> <strong>Resultado:</strong> &nbsp;{{m|resultado_votacao}}</br>
{% endif %} {% endif %}
{% if m.registrovotacao_set.exists %} {% if m.registrovotacao_set.exists %}
<div class="row">
<div class="col-md-auto">
<strong>Data Votação:</strong> <strong>Data Votação:</strong>
</div>
<div class="col">
{% for rv in m.registrovotacao_set.all %} {% for rv in m.registrovotacao_set.all %}
{% if rv.ordem %} {% if rv.ordem %}
<a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}"> <a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">{{ rv.ordem.sessao_plenaria.data_inicio }}</a>
{{ rv.ordem.sessao_plenaria.data_inicio }} {% if rv.ordem.get_tipo_votacao_display == 'Nominal' %}
</a> - <a id="link_votacao_nominal_{{ rv.id }}" class="link_votacao_nominal" href="#" onclick="votacaoNominal({{ rv.id }})">
Votação Nominal >>>
</a>
<div id="div_{{ rv.id }}" style="display:none">
<b>{{ rv.ordem.resultado }}</b><br />
<ul id="ul_{{ rv.id }}"style="columns: 2; list-style-type: none;">
{% for voto in rv.ordem.votoparlamentar_set.all %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% elif rv.expediente %} {% elif rv.expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}"> <a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">{{ rv.expediente.sessao_plenaria.data_inicio }}</a>
{{ rv.expediente.sessao_plenaria.data_inicio }} {% if rv.expediente.get_tipo_votacao_display == 'Nominal' %}
</a> - <a id="link_votacao_nominal_{{ rv.id }}" class="link_votacao_nominal" href="#" onclick="votacaoNominal({{ rv.id }})">
Votação Nominal >>>
</a>
<div id="div_{{ rv.id }}" style="display:none">
<b>{{ rv.expediente.resultado }}</b><br />
<ul id="ul_{{ rv.id }}"style="columns: 2; list-style-type: none;">
{% for voto in rv.expediente.votoparlamentar_set.all %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endif %} {% endif %}
</br> </br>
{% endfor %} {% endfor %}
</div>
</div>
{% endif %} {% endif %}
{% if m.tramitacao_set.first.data_tramitacao %} {% if m.tramitacao_set.first.data_tramitacao %}
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.first.data_tramitacao}}</br> <strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.first.data_tramitacao}}</br>
@ -215,6 +243,14 @@
{% block extra_js %} {% block extra_js %}
<script type="text/javascript" > <script type="text/javascript" >
$( document ).ready(function() {
const links_votacao = document.querySelectorAll('.link_votacao_nominal');
links_votacao.forEach(link => {
link.addEventListener('click', function(event) {
event.preventDefault();
});
});
});
function pesquisaAvancada(){ function pesquisaAvancada(){
$('.pesquisa_avancada').toggle(); $('.pesquisa_avancada').toggle();
@ -226,6 +262,17 @@
$(id_btn).val($(id_btn).val().replace('<<<', '>>>')) $(id_btn).val($(id_btn).val().replace('<<<', '>>>'))
} }
}; };
function votacaoNominal(id){
$('#div_' + id).toggle();
var id_link = "#link_votacao_nominal_" + id;
if ($(id_link).text().indexOf('>>>') > -1){
$(id_link).text($(id_link).text().replace('>>>', '<<<'))
}else{
$(id_link).text($(id_link).text().replace('<<<', '>>>'))
}
};
</script> </script>
{% endblock extra_js %} {% endblock extra_js %}

79
sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html

@ -0,0 +1,79 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block base_content %}
{% if not show_results %}
{% crispy filter.form %}
{% else %}
<div class="float-left">
{% with 'sapl.relatorios:relatorio_votacoes_nominais' as url_reverse %}
{% include "crud/format_options.html" %}
{% endwith %}
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.relatorios:relatorio_votacoes_nominais' %}" class="btn btn-outline-primary">{% trans 'Fazer uma nova pesquisa' %}</a>
</div>
<br /><br />
<b>PARÂMETROS DE PESQUISA<br /></b>
{% if tipo_materia %}
&emsp;Tipo de Matéria: {{ tipo_materia }}<br />
{% endif %}
{% if numero %}
&emsp;Número: {{ numero }}<br />
{% endif %}
{% if ano %}
&emsp;Ano: {{ ano }}<br />
{% endif %}
&emsp;Período: {{ periodo }}<br /><br />
{% if object_list %}
{% if qtde_votacoes > 1 %}
<h3>Foram encontradas {{qtde_votacoes}} votações.</h3></br>
{% elif qtde_votacoes == 1 %}
<h3>Foi encontrada {{qtde_votacoes}} votação.</h3></br>
{% endif %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr>
<th>Dados da Votação / Matéria</th>
<th>Parlamentar - Voto</th>
</tr>
</thead> <tbody>
{% for voto in object_list %}
{% ifchanged voto.votacao_id %}
{% if not forloop.first %}
</td></tr>
{% endif %}
<tr><td class="materia" {% comment %}style="max-width: 50%"{% endcomment %}>
{% if voto.ordem %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' voto.ordem.materia_id %}">{{ voto.ordem.materia }}</a></b> - {{ voto.ordem.materia.ementa }}<br />
<b>Momento da Votação: </b><a href="{% url 'sapl.sessao:ordemdia_list' voto.ordem.sessao_plenaria_id %}">Ordem do Dia</a> -
<a href="{% url 'sapl.sessao:sessaoplenaria_detail' voto.ordem.sessao_plenaria_id %}">{{ voto.ordem.sessao_plenaria }}</a><br />
<b>Data da Votação: </b>{{ voto.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ voto.ordem.resultado }}
{% else %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' voto.expediente.materia_id %}">{{ voto.expediente.materia }}</a></b> - {{ voto.expediente.materia.ementa }}<br />
<b>Momento da Votação: </b><a href="{% url 'sapl.sessao:expedientemateria_list' voto.expediente.sessao_plenaria_id %}">Expediente</a> -
<a href="{% url 'sapl.sessao:sessaoplenaria_detail' voto.expediente.sessao_plenaria_id %}">{{ voto.expediente.sessao_plenaria }}</a><br />
<b>Data da Votação: </b>{{ voto.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ voto.expediente.resultado }}
{% endif %}
</td><td class="votos" {% comment %}style="width: 50%"{% endcomment %}>
{% endifchanged %}
<span style="white-space: nowrap;">
{{ voto.parlamentar }} - <b>{{ voto.voto }}</b>
</span><br />
{% endfor %}
</tbody>
</table>
{% else %}
<tr><td><h3 style="text-align: left;">Nenhuma votação encontrada com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
{% endif %}
{% include "paginacao.html" %}
{% endblock base_content %}

49
sapl/templates/relatorios/relatorio_votacao_nominal.html

@ -0,0 +1,49 @@
{% extends "relatorios/base_relatorio.html" %}
{% load i18n %}
{% load common_tags %}
{% load static %}
{% block content %}
<h2>Votações Nominais</h2>
<span style="font-size:x-small">
<b>PARÂMETROS DE PESQUISA:<br /></b>
{% if tipo_materia %}
Tipo de matéria: {{ tipo_materia }}<br />
{% endif %}
Período: {{ periodo }}<br />
</span>
{% if object_list %}
{% if qtde_votacoes > 1 %}
<h3>Foram encontradas {{qtde_votacoes}} votações.</h3>
{% elif qtde_votacoes == 1 %}
<h3>Foi encontrada {{qtde_votacoes}} votação.</h3>
{% endif %}
{% for voto in object_list %}
{% ifchanged voto.votacao_id %}
{% if not forloop.first %}</ul>{% endif %}
<div style="border-top: 1px solid black;margin-top:0.3cm;font-size:small">
{% if voto.ordem %}
<b>Matéria: {{ voto.ordem.materia }}</b> - {{ voto.ordem.materia.ementa }}<br />
<b>Momento da Votação: </b>Ordem do Dia - {{ voto.ordem.sessao_plenaria }}<br />
<b>Data da Votação: </b>{{ voto.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ voto.ordem.resultado }}<br /><br />
{% else %}
<b>Matéria: {{ voto.expediente.materia }}</b> - {{ voto.expediente.materia.ementa }}<br />
<b>Momento da Votação: </b>Expediente - {{ voto.expediente.sessao_plenaria }}<br />
<b>Data da Votação: </b>{{ voto.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ voto.expediente.resultado }}<br /><br />
{% endif %}
</div>
<ul style="columns: 2; list-style-type: none;font-size:small">
{% endifchanged %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
{% else %}
<tr><td><h3 style="text-align: left;">Nenhuma votação encontrada com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
{% endblock content %}

7
sapl/templates/relatorios/relatorios_list.html

@ -127,6 +127,13 @@
<td> Listagem e totalização de normas por autor, com filtros para tipo e período.</td> <td> Listagem e totalização de normas por autor, com filtros para tipo e período.</td>
</tr> </tr>
{% endif %} {% endif %}
{% url 'sapl.relatorios:relatorio_votacoes_nominais' as relatorio_votacoes_nominais %}
{% if request|is_report_visible:relatorio_votacoes_nominais %}
<tr>
<td><a href="{{ relatorio_votacoes_nominais }}"> Votações Nominais</a></td>
<td> Votações Nominais em Expedientes e Ordens do Dia por data. </td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</fieldset> </fieldset>

122
sapl/utils.py

@ -1707,3 +1707,125 @@ class PautaMultiFormatOutputMixin(MultiFormatOutputMixin):
output.close() output.close()
return response return response
class VotacoesMultiFormatOutputMixin(MultiFormatOutputMixin):
def render_to_csv(self, context):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = f'attachment; filename="sapl_{self.request.resolver_match.url_name}.csv"'
response['Cache-Control'] = 'no-cache'
response['Pragma'] = 'no-cache'
response['Expires'] = 0
writer = csv.writer(response, delimiter=";",
quoting=csv.QUOTE_NONNUMERIC)
object_list = context['object_list']
data = [[list(self._headers(self.fields_report['csv']))], ]
for obj in object_list:
wr = list(self._write_row(obj, self.fields_report['csv']))
if wr[0] != data[-1][0][0]:
data.append([wr])
else:
data[-1].append(wr)
for mri, multirows in enumerate(data):
if len(multirows) == 1:
writer.writerow(multirows[0])
else:
for v in multirows:
writer.writerow(v)
return response
def render_to_xlsx(self, context):
object_list = context['object_list']
data = [[list(self._headers(self.fields_report['xlsx']))], ]
row = 0
for obj in object_list:
wr = list(self._write_row(obj, self.fields_report['xlsx']))
if wr[0] != data[-1][0][0]:
data.append([wr])
else:
data[-1].append(wr)
output = io.BytesIO()
wb = Workbook(output, {'in_memory': True})
ws = wb.add_worksheet()
for mri, multirows in enumerate(data):
if len(multirows) == 1:
for rc, cell in enumerate(multirows[0]):
ws.write(row, rc, cell)
row += 1
else:
for v in multirows:
for rc, cell in enumerate(v):
try:
ws.write(row, rc, cell)
except TypeError:
ws.write(row, rc, str(cell))
row += 1
ws.autofit()
wb.close()
output.seek(0)
response = HttpResponse(output.read(
), content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
response['Content-Disposition'] = f'attachment; filename="sapl_{self.request.resolver_match.url_name}.xlsx"'
response['Cache-Control'] = 'no-cache'
response['Pragma'] = 'no-cache'
response['Expires'] = 0
output.close()
return response
def render_to_json(self, context):
object_list = context['object_list']
data = []
for obj in object_list:
wr = list(self._write_row(obj, self.fields_report['json']))
wr[1] = str(wr[1])
if not data:
data.append([wr])
continue
if wr[0] != data[-1][0][0]:
data.append([wr])
else:
data[-1].append(wr)
fields_report = list(map(lambda i, j: (i, j), self.fields_report['json'], self._headers(self.fields_report['json'])))
fields_report[2] = ('parlamentar_voto', 'Voto por Parlamentar')
fields_report_data = []
for f in fields_report:
fields_report_data.append(f[0])
for mri, multirows in enumerate(data):
parlamentar_voto = []
for ri, cols in enumerate(multirows):
parlamentar_voto.append([cols[2], cols[3]])
data[mri] = dict(
map(lambda i, j: (i, j), fields_report_data, [multirows[0][0], multirows[0][1], parlamentar_voto]))
json_metadata = {
'headers': dict(fields_report[:-1]),
'results': data
}
response = JsonResponse(json_metadata)
response['Content-Disposition'] = f'attachment; filename="sapl_{self.request.resolver_match.url_name}.json"'
response['Cache-Control'] = 'no-cache'
response['Pragma'] = 'no-cache'
response['Expires'] = 0
return response

Loading…
Cancel
Save