Browse Source

Ajustes solicitados - Relatório de Votações Nominais (#3785)

* Implementa Relatório de Votações Nominais

* Alterações solicitadas - Relatório de Votações Nominais

* Apply suggestions from code review

Todas as sugestões de alteração acatadas.

Co-authored-by: Edward <9326037+edwardoliveira@users.noreply.github.com>

* Update views.py

Conforme observação sobre o retorno da QuerySet, escolha da opção 2 - colocar o qs dentro dos if's. Também houve a alteração na view, utilizando diretamente a classe genérica MultiFormatOutputMixin. Com a refatoração efetuada, não foi necessário definir uma especificação da mesma.

---------

Co-authored-by: root <root@info38.camaranh>
Co-authored-by: Edward <9326037+edwardoliveira@users.noreply.github.com>
pull/3790/head
cristian-longhi 2 months ago
committed by GitHub
parent
commit
6c4dbd1a5e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 71
      sapl/relatorios/forms.py
  2. 8
      sapl/relatorios/urls.py
  3. 78
      sapl/relatorios/views.py
  4. 13
      sapl/sessao/models.py
  5. 56
      sapl/templates/materia/materialegislativa_filter.html
  6. 82
      sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html
  7. 53
      sapl/templates/relatorios/relatorio_votacao_nominal.html
  8. 7
      sapl/templates/relatorios/relatorios_list.html

71
sapl/relatorios/forms.py

@ -3,17 +3,19 @@ from crispy_forms.bootstrap import (FormActions)
from crispy_forms.layout import (HTML, Button, Fieldset,
Layout, Submit)
from django import forms
from django.forms import ModelChoiceField
from django.utils.translation import ugettext_lazy as _
from django.db.models import Q
from sapl.audiencia.models import AudienciaPublica
from sapl.base.models import Autor
from sapl.comissoes.models import Reuniao
from sapl.crispy_layout_mixin import SaplFormHelper, to_row, form_actions
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, MateriaEmTramitacao, UnidadeTramitacao, \
StatusTramitacao
StatusTramitacao, TipoMateriaLegislativa
from sapl.norma.models import NormaJuridica
from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import SessaoPlenaria
from sapl.sessao.models import SessaoPlenaria, VotoParlamentar, RegistroVotacao
from sapl.utils import FilterOverridesMetaMixin, choice_anos_com_normas, qs_override_django_filter, \
choice_anos_com_materias, choice_tipos_normas, autor_label, autor_modal
@ -68,6 +70,71 @@ class RelatorioDocumentosAcessoriosFilterSet(django_filters.FilterSet):
)
class RelatorioVotacoesNominaisFilterSet(django_filters.FilterSet):
tipo_id = django_filters.ModelChoiceFilter(
queryset=TipoMateriaLegislativa.objects.all(),
method='ordem_or_expediente',
label='Tipo de Matéria',
empty_label="---------"
)
numero = django_filters.NumberFilter(
widget=forms.NumberInput(attrs={'class': 'form-control', 'step': 'any'}),
method='ordem_or_expediente',
label='Número'
)
ano = django_filters.ChoiceFilter(
choices=list(choice_anos_com_materias()),
widget=forms.Select(attrs={'class': 'form-control'}),
method='ordem_or_expediente',
label='Ano da Matéria'
)
def ordem_or_expediente(self, queryset, name, value):
if value is None:
return queryset
value = getattr(value, "pk", value)
ordem_q = f"ordem__materia__{name}"
expediente_q = f"expediente__materia__{name}"
return queryset.filter(Q(**{ordem_q: val})|Q(**{expediente_q: val}))
return queryset
class Meta(FilterOverridesMetaMixin):
model = RegistroVotacao
fields = ['data_hora']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filters['data_hora'].label = 'Período (Data Inicial - Data Final)'
row0= to_row([('tipo_id', 6), ('numero', 3), ('ano', 3)])
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 Meta(FilterOverridesMetaMixin):
model = SessaoPlenaria

8
sapl/relatorios/urls.py

@ -11,7 +11,7 @@ from .views import (relatorio_capa_processo,
RelatorioMateriasTramitacaoView, RelatorioMateriaAnoAssuntoView, RelatorioHistoricoTramitacaoView,
RelatorioDataFimPrazoTramitacaoView, RelatorioPresencaSessaoView, RelatorioAtasView,
RelatorioReuniaoView, RelatorioAudienciaView, RelatorioHistoricoTramitacaoAdmView,
RelatorioDocumentosAcessoriosView, RelatorioNormasPorAutorView)
RelatorioDocumentosAcessoriosView, RelatorioNormasPorAutorView, RelatorioVotacoesNominaisView)
from ..base.views import EstatisticasAcessoNormas
app_name = AppConfig.name
@ -95,6 +95,10 @@ urlpatterns = [
url(r'^sistema/relatorios/documentos_acessorios$',
RelatorioDocumentosAcessoriosView.as_view(),
name='relatorio_documentos_acessorios'),
url(r'^sistema/relatorios/votacoes_nominais$',
RelatorioVotacoesNominaisView.as_view(),
name='relatorio_votacoes_nominais'),
url(r'^sistema/relatorios/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, \
RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasTramitacaoFilterSet, RelatorioAudienciaFilterSet, \
RelatorioReuniaoFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet, RelatorioHistoricoTramitacaoFilterSet, \
RelatorioPresencaSessaoFilterSet, RelatorioAtasFilterSet, RelatorioDocumentosAcessoriosFilterSet
RelatorioPresencaSessaoFilterSet, RelatorioAtasFilterSet, RelatorioDocumentosAcessoriosFilterSet, \
RelatorioVotacoesNominaisFilterSet
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, JustificativaAusencia,
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 STATIC_ROOT
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, MultiFormatOutputMixin
from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_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')
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):
return cria_relatorio(request, context, 'relatorios/relatorio_normas_por_autor.html')
@ -1880,6 +1885,75 @@ class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
return context
class RelatorioVotacoesNominaisView(RelatorioMixin, MultiFormatOutputMixin, FilterView):
model = VotoParlamentar
filterset_class = RelatorioVotacoesNominaisFilterSet
template_name = 'relatorios/RelatorioVotacoesNominais_filter.html'
relatorio = relatorio_votacao_nominal
paginate_by = 20
export_fields = [
'votacao_id', 'votacao', 'parlamentar__nome_parlamentar', 'voto'
]
def get_queryset(self):
query_params = Q(ordem__tipo_votacao=2)|Q(expediente__tipo_votacao=2)
if 'format' in self.request.GET:
order_fields = ['-votacao_id', 'parlamentar']
qs = VotoParlamentar.objects.filter(query_params).order_by(*order_fields)
else:
order_fields = ['-id']
qs = RegistroVotacao.objects.filter(query_params).order_by(*order_fields)
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = _('Votações Nominais')
if not self.filterset.form.is_valid():
return context
query_dict = self.request.GET.copy()
if 'page' in query_dict:
del query_dict['page']
context['filter_url'] = f"&{query_dict.urlencode()}" if query_dict else ''
context['show_results'] = show_results_filter_set(query_dict)
data_inicial = self.request.GET.get('data_hora_0', '')
data_final = self.request.GET.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'] = f"{data_inicial} - {data_final}"
tipo_id = self.request.GET.get('tipo_id')
numero = self.request.GET.get('numero')
ano = self.request.GET.get('ano')
if tipo_id:
context['tipo_materia'] = TipoMateriaLegislativa.objects.get(id=tipo_id)
if numero:
context['numero'] = int(numero)
if ano:
context['ano'] = ano
if 'relatorio' not in self.request.GET:
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context['qtde_votacoes'] = paginator.count
else:
self.paginate_by = None
context['qtde_votacoes'] = len(context['object_list'])
return context
class RelatorioAtasView(RelatorioMixin, FilterView):
model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet

13
sapl/sessao/models.py

@ -641,11 +641,14 @@ class RegistroVotacao(models.Model):
ordering = ('id',)
def __str__(self):
return _('Ordem: %(ordem)s - Votação: %(votacao)s - '
'Matéria: %(materia)s') % {
'ordem': self.ordem,
'votacao': self.tipo_resultado_votacao,
'materia': self.materia}
if self.ordem:
return _('Ordem: %(ordem)s - Votação: %(votacao)s') % {
'ordem': self.ordem,
'votacao': self.tipo_resultado_votacao}
else:
return _('Expediente: %(expediente)s - Votação: %(votacao)s') % {
'expediente': self.expediente,
'votacao': self.tipo_resultado_votacao}
def clean(self):
"""Exatamente um dos campos ordem ou expediente deve estar preenchido.

56
sapl/templates/materia/materialegislativa_filter.html

@ -108,19 +108,47 @@
<strong>Resultado:</strong> &nbsp;{{m|resultado_votacao}}</br>
{% endif %}
{% if m.registrovotacao_set.exists %}
<div class="row">
<div class="col-md-auto">
<strong>Data Votação:</strong>
</div>
<div class="col">
{% for rv in m.registrovotacao_set.all %}
{% if rv.ordem %}
<a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">
{{ rv.ordem.sessao_plenaria.data_inicio }}
</a>
<a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">{{ rv.ordem.sessao_plenaria.data_inicio }}</a>
{% if rv.ordem.tipo_votacao == 2 %}
- <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|dictsort:"parlamentar.nome_parlamentar" %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% elif rv.expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">
{{ rv.expediente.sessao_plenaria.data_inicio }}
</a>
<a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">{{ rv.expediente.sessao_plenaria.data_inicio }}</a>
{% if rv.expediente.tipo_votacao == 2 %}
- <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|dictsort:"parlamentar.nome_parlamentar" %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endif %}
</br>
{% endfor %}
</div>
</div>
{% endif %}
{% if m.tramitacao_set.first.data_tramitacao %}
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.first.data_tramitacao}}</br>
@ -215,6 +243,11 @@
{% block extra_js %}
<script type="text/javascript" >
$( document ).ready(function() {
$('.link_votacao_nominal').on('click', function(event) {
event.preventDefault();
});
});
function pesquisaAvancada(){
$('.pesquisa_avancada').toggle();
@ -226,6 +259,17 @@
$(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>
{% endblock extra_js %}

82
sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html

@ -0,0 +1,82 @@
{% 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 rv in object_list %}
<tr>
<td class="materia">
{% if rv.ordem %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' rv.ordem.materia_id %}">{{ rv.ordem.materia }}</a></b> - {{ rv.ordem.materia.ementa }}<br />
<b>Momento da Votação: </b><a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">Ordem do Dia</a> -
<a href="{% url 'sapl.sessao:sessaoplenaria_detail' rv.ordem.sessao_plenaria_id %}">{{ rv.ordem.sessao_plenaria }}</a><br />
<b>Data da Votação: </b>{{ rv.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ rv.ordem.resultado }}
{% else %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' rv.expediente.materia_id %}">{{ rv.expediente.materia }}</a></b> - {{ rv.expediente.materia.ementa }}<br />
<b>Momento da Votação: </b><a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">Expediente</a> -
<a href="{% url 'sapl.sessao:sessaoplenaria_detail' rv.expediente.sessao_plenaria_id %}">{{ rv.expediente.sessao_plenaria }}</a><br />
<b>Data da Votação: </b>{{ rv.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ rv.expediente.resultado }}
{% endif %}
</td>
<td class="votos">
{% for voto in rv.votoparlamentar_set.all|dictsort:"parlamentar.nome_parlamentar" %}
<span style="white-space: nowrap;">
{{ voto.parlamentar }} - <b>{{ voto.voto }}</b>
</span><br />
{% endfor %}
</td>
</tr>
{% 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 %}
{% if filter_url %}
{% include "paginacao.html" %}
{% endif %}
{% endblock base_content %}

53
sapl/templates/relatorios/relatorio_votacao_nominal.html

@ -0,0 +1,53 @@
{% 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 %}
{% if numero %}
Número: {{ numero }}<br />
{% endif %}
{% if ano %}
Ano: {{ ano }}<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 rv in object_list %}
<div style="border-top: 1px solid black;margin-top:0.3cm;font-size:small">
{% if rv.ordem %}
<b>Matéria: {{ rv.ordem.materia }}</b> - {{ rv.ordem.materia.ementa }}<br />
<b>Momento da Votação: </b>Ordem do Dia - {{ rv.ordem.sessao_plenaria }}<br />
<b>Data da Votação: </b>{{ rv.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ rv.ordem.resultado }}<br /><br />
{% else %}
<b>Matéria: {{ rv.expediente.materia }}</b> - {{ rv.expediente.materia.ementa }}<br />
<b>Momento da Votação: </b>Expediente - {{ rv.expediente.sessao_plenaria }}<br />
<b>Data da Votação: </b>{{ rv.data_hora|date:"d/m/Y" }}<br />
<b>Resultado: </b>{{ rv.expediente.resultado }}<br /><br />
{% endif %}
</div>
<ul style="columns: 2; list-style-type: none;font-size:small">
{% for voto in rv.votoparlamentar_set.all|dictsort:"parlamentar.nome_parlamentar" %}
<li>{{ voto.parlamentar }} - <b>{{ voto.voto }}</b></li>
{% endfor %}
</ul>
{% endfor %}
{% 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>
</tr>
{% 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>
</table>
</fieldset>

Loading…
Cancel
Save