diff --git a/sapl/relatorios/forms.py b/sapl/relatorios/forms.py
index 59eb2d741..cfbf369c1 100644
--- a/sapl/relatorios/forms.py
+++ b/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("""
+
+
+ Gerar relatório PDF
+
+ """)
+ ],
+ 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
diff --git a/sapl/relatorios/urls.py b/sapl/relatorios/urls.py
index b27bfc55a..235becfab 100644
--- a/sapl/relatorios/urls.py
+++ b/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'),
-]
\ No newline at end of file
+]
+
diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py
index 99a299abb..b96557e16 100755
--- a/sapl/relatorios/views.py
+++ b/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
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index 55fe581a1..613068afe 100644
--- a/sapl/sessao/models.py
+++ b/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.
diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html
index 0c5064806..f74c5d5ab 100644
--- a/sapl/templates/materia/materialegislativa_filter.html
+++ b/sapl/templates/materia/materialegislativa_filter.html
@@ -108,19 +108,47 @@
Resultado: {{m|resultado_votacao}}
{% endif %}
{% if m.registrovotacao_set.exists %}
+
{% endif %}
{% if m.tramitacao_set.first.data_tramitacao %}
Data da última Tramitação: {{m.tramitacao_set.first.data_tramitacao}}
@@ -215,6 +243,11 @@
{% block extra_js %}
{% endblock extra_js %}
diff --git a/sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html b/sapl/templates/relatorios/RelatorioVotacoesNominais_filter.html
new file mode 100644
index 000000000..72d6f0212
--- /dev/null
+++ b/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 %}
+
+ {% with 'sapl.relatorios:relatorio_votacoes_nominais' as url_reverse %}
+ {% include "crud/format_options.html" %}
+ {% endwith %}
+
+
+
+
+ PARÂMETROS DE PESQUISA
+ {% if tipo_materia %}
+ Tipo de Matéria: {{ tipo_materia }}
+ {% endif %}
+ {% if numero %}
+ Número: {{ numero }}
+ {% endif %}
+ {% if ano %}
+ Ano: {{ ano }}
+ {% endif %}
+ Período: {{ periodo }}
+
+ {% if object_list %}
+
+ {% if qtde_votacoes > 1 %}
+ Foram encontradas {{qtde_votacoes}} votações.
+ {% elif qtde_votacoes == 1 %}
+ Foi encontrada {{qtde_votacoes}} votação.
+ {% endif %}
+
+
+
+
+ Dados da Votação / Matéria
+ Parlamentar - Voto
+
+
+
+ {% for rv in object_list %}
+
+
+ {% if rv.ordem %}
+ {{ rv.ordem.materia }} - {{ rv.ordem.materia.ementa }}
+ Momento da Votação: Ordem do Dia -
+ {{ rv.ordem.sessao_plenaria }}
+ Data da Votação: {{ rv.data_hora|date:"d/m/Y" }}
+ Resultado: {{ rv.ordem.resultado }}
+ {% else %}
+ {{ rv.expediente.materia }} - {{ rv.expediente.materia.ementa }}
+ Momento da Votação: Expediente -
+ {{ rv.expediente.sessao_plenaria }}
+ Data da Votação: {{ rv.data_hora|date:"d/m/Y" }}
+ Resultado: {{ rv.expediente.resultado }}
+ {% endif %}
+
+
+ {% for voto in rv.votoparlamentar_set.all|dictsort:"parlamentar.nome_parlamentar" %}
+
+ {{ voto.parlamentar }} - {{ voto.voto }}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+ {% else %}
+ Nenhuma votação encontrada com esses parâmetros.
+ {% endif %}
+ {% endif %}
+ {% if filter_url %}
+ {% include "paginacao.html" %}
+ {% endif %}
+{% endblock base_content %}
diff --git a/sapl/templates/relatorios/relatorio_votacao_nominal.html b/sapl/templates/relatorios/relatorio_votacao_nominal.html
new file mode 100644
index 000000000..72773a4e8
--- /dev/null
+++ b/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 %}
+ Votações Nominais
+
+ PARÂMETROS DE PESQUISA:
+ {% if tipo_materia %}
+ Tipo de matéria: {{ tipo_materia }}
+ {% endif %}
+ {% if numero %}
+ Número: {{ numero }}
+ {% endif %}
+ {% if ano %}
+ Ano: {{ ano }}
+ {% endif %}
+ Período: {{ periodo }}
+
+
+ {% if object_list %}
+ {% if qtde_votacoes > 1 %}
+ Foram encontradas {{qtde_votacoes}} votações.
+ {% elif qtde_votacoes == 1 %}
+ Foi encontrada {{qtde_votacoes}} votação.
+ {% endif %}
+
+ {% for rv in object_list %}
+
+ {% if rv.ordem %}
+ Matéria: {{ rv.ordem.materia }} - {{ rv.ordem.materia.ementa }}
+ Momento da Votação: Ordem do Dia - {{ rv.ordem.sessao_plenaria }}
+ Data da Votação: {{ rv.data_hora|date:"d/m/Y" }}
+ Resultado: {{ rv.ordem.resultado }}
+ {% else %}
+ Matéria: {{ rv.expediente.materia }} - {{ rv.expediente.materia.ementa }}
+ Momento da Votação: Expediente - {{ rv.expediente.sessao_plenaria }}
+ Data da Votação: {{ rv.data_hora|date:"d/m/Y" }}
+ Resultado: {{ rv.expediente.resultado }}
+ {% endif %}
+
+
+ {% for voto in rv.votoparlamentar_set.all|dictsort:"parlamentar.nome_parlamentar" %}
+ {{ voto.parlamentar }} - {{ voto.voto }}
+ {% endfor %}
+
+ {% endfor %}
+ {% else %}
+ Nenhuma votação encontrada com esses parâmetros.
+ {% endif %}
+
+{% endblock content %}
diff --git a/sapl/templates/relatorios/relatorios_list.html b/sapl/templates/relatorios/relatorios_list.html
index 38346fa21..eec0843d0 100644
--- a/sapl/templates/relatorios/relatorios_list.html
+++ b/sapl/templates/relatorios/relatorios_list.html
@@ -127,6 +127,13 @@
Listagem e totalização de normas por autor, com filtros para tipo e período.
{% endif %}
+ {% url 'sapl.relatorios:relatorio_votacoes_nominais' as relatorio_votacoes_nominais %}
+ {% if request|is_report_visible:relatorio_votacoes_nominais %}
+
+ Votações Nominais
+ Votações Nominais em Expedientes e Ordens do Dia por data.
+
+ {% endif %}