From 4217b9f66a8816d8347bc798d3cab26f26a18b60 Mon Sep 17 00:00:00 2001 From: Eduardo Calil Date: Mon, 12 Jun 2017 16:16:06 -0300 Subject: [PATCH] Fix #1183 votacao nominal intuitiva (#1188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Inicia a logica * Adaptação da lógica da votação interativa * Faz mudanças sugeridas no code review * Ajusta separador de msg_abertas. Ajusta separador de msg_abertas. * Ajusta listagem de votações abertas Ajusta listagem de votações abertas --- sapl/painel/urls.py | 2 +- sapl/painel/views.py | 205 +++++++++++------- sapl/sessao/views.py | 71 +++--- sapl/templates/base.html | 5 + sapl/templates/painel/voto_nominal.html | 18 +- .../sessao/sessaoplenaria_detail.html | 14 -- 6 files changed, 176 insertions(+), 139 deletions(-) delete mode 100644 sapl/templates/sessao/sessaoplenaria_detail.html diff --git a/sapl/painel/urls.py b/sapl/painel/urls.py index b617d8fec..f0054bd3c 100644 --- a/sapl/painel/urls.py +++ b/sapl/painel/urls.py @@ -20,6 +20,6 @@ urlpatterns = [ url(r'^painel/cronometro$', cronometro_painel, name='cronometro_painel'), # url(r'^painel/cronometro$', include(CronometroPainelCrud.get_urls())), - url(r'^voto-individual/(?P\d+)$', votante_view, + url(r'^voto-individual/$', votante_view, name="voto_individual"), ] diff --git a/sapl/painel/views.py b/sapl/painel/views.py index df30ada41..23bd757ed 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -1,7 +1,9 @@ from datetime import date +from django.contrib import messages from django.contrib.auth.decorators import user_passes_test -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned +from django.db.models import Q from django.core.urlresolvers import reverse from django.http import HttpResponse, JsonResponse from django.http.response import Http404, HttpResponseRedirect @@ -30,92 +32,143 @@ def check_permission(user): return user.has_module_perms(AppConfig.label) -def votante_view(request, pk): - if not Votante.objects.filter(user=request.user).exists(): - raise Http404('Você não tem permissão para votar') - - context = {'head_title': str(_('Votação Individual')), 'sessao_id': pk} - - # Pega sessão +def votacao_aberta(request): + votacoes_abertas = SessaoPlenaria.objects.filter( + Q(ordemdia__votacao_aberta=True) | + Q(expedientemateria__votacao_aberta=True)).distinct() + + if len(votacoes_abertas) > 1: + msg_abertas = [] + for v in votacoes_abertas: + msg_abertas.append('''
  • %s
  • ''' % ( + reverse('sapl.sessao:sessaoplenaria_detail', + kwargs={'pk': v.id}), + v.__str__())) + + msg = _('Existe mais de uma votações aberta. Elas se encontram ' + 'nas seguintes Sessões: ' + ', '.join(msg_abertas) + '. ' + 'Para votar, peça para que o Operador feche-as.') + messages.add_message(request, messages.INFO, msg) + return None, msg + + elif len(votacoes_abertas) == 1: + ordens = OrdemDia.objects.filter( + sessao_plenaria=votacoes_abertas.first(), + votacao_aberta=True) + expedientes = ExpedienteMateria.objects.filter( + sessao_plenaria=votacoes_abertas.first(), + votacao_aberta=True) + + numero_materias_abertas = len(ordens) + len(expedientes) + if numero_materias_abertas > 1: + msg = _('Existe mais de uma votação aberta na Sessão: ' + + ('''
  • %s
  • ''' % ( + reverse('sapl.sessao:sessaoplenaria_detail', + kwargs={'pk': votacoes_abertas.first().id}), + votacoes_abertas.first().__str__())) + + 'Para votar, peça para que o Operador as feche.') + messages.add_message(request, messages.INFO, msg) + return None, msg + + return votacoes_abertas.first(), None + + +def votante_view(request): + # Pega o votante relacionado ao usuário try: - sessao = SessaoPlenaria.objects.get(pk=pk) + votante = Votante.objects.get(user=request.user) except ObjectDoesNotExist: raise Http404() - context.update({'sessao': sessao, - 'data': sessao.data_inicio, - 'hora': sessao.hora_inicio}) - - # Inicializa presentes - presentes = [] - - # Verifica votação aberta - # Se aberta, verifica se é nominal. ID nominal == 2 - ordem_dia = get_materia_aberta(pk) - expediente = get_materia_expediente_aberta(pk) - materia = None - - if ordem_dia: - materia = ordem_dia.materia - if ordem_dia.tipo_votacao == VOTACAO_NOMINAL: - context.update({'materia': materia, 'ementa': materia.ementa}) - presentes = PresencaOrdemDia.objects.filter(sessao_plenaria_id=pk) - else: - context.update( - {'materia': 'A matéria aberta não é votação nominal.'}) - elif expediente: - materia = expediente.materia - if expediente.tipo_votacao == VOTACAO_NOMINAL: - context.update({'materia': materia, 'ementa': materia.ementa}) - presentes = SessaoPlenariaPresenca.objects.filter( - sessao_plenaria_id=pk) - else: - context.update( - {'materia': 'A matéria aberta não é votação nominal.'}) - else: - context.update( - {'materia': 'Nenhuma matéria com votação nominal aberta.'}) + context = {'head_title': str(_('Votação Individual'))} # Verifica se usuário possui permissão para votar if 'parlamentares.can_vote' in request.user.get_all_permissions(): context.update({'permissao': True}) - else: - context.update({'permissao': False}) - # Verifica se usuário está presente na sessão - try: - votante = Votante.objects.get(user=request.user) - except ObjectDoesNotExist: - context.update({'error_message': - 'Erro ao recuperar parlamentar ligado ao usuário'}) - else: - parlamentar = votante.parlamentar - context.update({'presente': False}) - if len(presentes) > 0: - for p in presentes: - if p.parlamentar.id == parlamentar.id: - context.update({'presente': True}) - break - else: - context.update({'error_message': - 'Nenhuma matéria com votação nominal aberta.'}) + # Pega sessão + sessao, msg = votacao_aberta(request) + + if sessao and not msg: + pk = sessao.pk + context.update({'sessao_id': pk}) + context.update({'sessao': sessao, + 'data': sessao.data_inicio, + 'hora': sessao.hora_inicio}) + + # Inicializa presentes + presentes = [] + + # Verifica votação aberta + # Se aberta, verifica se é nominal. ID nominal == 2 + ordem_dia = get_materia_aberta(pk) + expediente = get_materia_expediente_aberta(pk) + + materia_aberta = None + if ordem_dia: + materia_aberta = ordem_dia + presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=pk).values_list( + 'parlamentar_id', flat=True).distinct() + elif expediente: + materia_aberta = expediente + presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=pk).values_list( + 'parlamentar_id', flat=True).distinct() + + if materia_aberta: + if materia_aberta.tipo_votacao == VOTACAO_NOMINAL: + context.update({'materia': materia_aberta.materia, + 'ementa': materia_aberta.materia.ementa}) + + parlamentar = votante.parlamentar + parlamentar_presente = False + if parlamentar.id in presentes: + parlamentar_presente = True + else: + context.update({'error_message': + 'Não há presentes na Sessão com a ' + 'matéria em votação.'}) + + if parlamentar_presente: + voto = [] + if ordem_dia: + voto = VotoParlamentar.objects.filter( + ordem=ordem_dia) + elif expediente: + voto = VotoParlamentar.objects.filter( + expediente=expediente) + + if voto: + try: + voto = voto.get(parlamentar=parlamentar) + context.update({'voto_parlamentar': voto.voto}) + except ObjectDoesNotExist: + context.update( + {'voto_parlamentar': 'Voto não ' + 'computado.'}) + else: + context.update({'error_message': + 'Você não está presente na ' + 'Ordem do Dia/Expediente em votação.'}) + else: + context.update( + {'error_message': 'A matéria aberta não é votação ' + 'nominal.'}) + else: + context.update( + {'error_message': 'Nenhuma matéria aberta.'}) - # Recupera o voto do parlamentar logado - voto = [] - if ordem_dia: - voto = VotoParlamentar.objects.filter( - ordem=ordem_dia) - elif expediente: - voto = VotoParlamentar.objects.filter( - expediente=expediente) + elif not sessao and msg: + return HttpResponseRedirect('/') - if voto: - try: - voto = voto.get(parlamentar=parlamentar) - except ObjectDoesNotExist: - context.update({'voto_parlamentar': 'Voto não computado.'}) else: - context.update({'voto_parlamentar': voto.voto}) + context.update( + {'error_message': 'Nenhuma sessão com matéria aberta.'}) + + else: + context.update({'permissao': False, + 'error_message': 'Usuário sem permissão para votar.'}) # Salva o voto if request.method == 'POST': @@ -156,7 +209,7 @@ def votante_view(request, pk): voto.save() return HttpResponseRedirect( - reverse('sapl.painel:voto_individual', kwargs={'pk': pk})) + reverse('sapl.painel:voto_individual')) return render(request, 'painel/voto_nominal.html', context) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 9beb28ee2..d798a8a38 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -6,6 +6,7 @@ from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.urlresolvers import reverse +from django.db.models import Q from django.forms.utils import ErrorList from django.http import JsonResponse from django.http.response import Http404, HttpResponseRedirect @@ -81,49 +82,44 @@ def reordernar_materias_ordem(request, pk): reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk})) -@permission_required('sessao.change_expedientemateria') -def abrir_votacao_expediente_view(request, pk, spk): - existe_expediente_aberto = ExpedienteMateria.objects.filter( - sessao_plenaria_id=spk, votacao_aberta=True - ).exists() - existe_ordem_aberta = OrdemDia.objects.filter( - sessao_plenaria_id=spk, votacao_aberta=True - ).exists() - - if existe_expediente_aberto or existe_ordem_aberta: - msg = _('Já existe uma matéria com votação aberta. Para abrir ' - 'outra, termine ou feche a votação existente.') +def verifica_votacoes_abertas(request, model, pk): + votacoes_abertas = SessaoPlenaria.objects.filter( + Q(ordemdia__votacao_aberta=True) | + Q(expedientemateria__votacao_aberta=True)).distinct() + + if votacoes_abertas: + msg_abertas = [] + for v in votacoes_abertas: + msg_abertas.append('''
  • %s
  • ''' % ( + reverse('sapl.sessao:sessaoplenaria_detail', + kwargs={'pk': v.id}), + v.__str__())) + + msg = _('Já existem votações abertas nas seguintes Sessões: ' + + ', '.join(msg_abertas) + '. Para abrir ' + 'outra, termine ou feche as votações abertas.') messages.add_message(request, messages.INFO, msg) + else: - expediente = ExpedienteMateria.objects.get(id=pk) - expediente.votacao_aberta = True - expediente.save() + materia_votacao = model.objects.get(id=pk) + materia_votacao.votacao_aberta = True + materia_votacao.save() + + +@permission_required('sessao.change_expedientemateria') +def abrir_votacao_expediente_view(request, pk, spk): + verifica_votacoes_abertas(request, ExpedienteMateria, pk) return HttpResponseRedirect( reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': spk})) @permission_required('sessao.change_ordemdia') def abrir_votacao_ordem_view(request, pk, spk): - existe_ordem_aberta = OrdemDia.objects.filter( - sessao_plenaria_id=spk, votacao_aberta=True - ).exists() - existe_expediente_aberto = ExpedienteMateria.objects.filter( - sessao_plenaria_id=spk, votacao_aberta=True - ).exists() - - if existe_ordem_aberta or existe_expediente_aberto: - msg = _('Já existe uma matéria com votação aberta. Para abrir ' - 'outra, termine ou feche a votação existente.') - messages.add_message(request, messages.INFO, msg) - else: - ordem = OrdemDia.objects.get(id=pk) - ordem.votacao_aberta = True - ordem.save() + verifica_votacoes_abertas(request, OrdemDia, pk) return HttpResponseRedirect( reverse('sapl.sessao:ordemdia_list', kwargs={'pk': spk})) - def put_link_materia(context): for i, row in enumerate(context['rows']): materia = context['object_list'][i].materia @@ -133,6 +129,7 @@ def put_link_materia(context): context['rows'][i][1] = (row[1][0], url_materia) return context + def get_presencas_generic(model, sessao, legislatura): presencas = model.objects.filter( sessao_plenaria=sessao) @@ -1753,6 +1750,18 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): materia_votacao.votacao_aberta = False materia_votacao.save() + # Verifica se existe algum VotoParlamentar sem RegistroVotacao + # Por exemplo, se algum parlamentar votar e sua presença for + # removida da ordem do dia/expediente antes da conclusão da + # votação + if self.ordem: + VotoParlamentar.objects.filter( + ordem=ordem, + votacao__isnull=True).delete() + elif self.expediente: + VotoParlamentar.objects.filter( + expediente=expediente, + votacao__isnull=True).delete() return self.form_valid(form) else: return self.form_invalid(form) diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 647fcdc15..88b877016 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -63,6 +63,11 @@ diff --git a/sapl/templates/painel/voto_nominal.html b/sapl/templates/painel/voto_nominal.html index ca738e20d..fd02b58c7 100644 --- a/sapl/templates/painel/voto_nominal.html +++ b/sapl/templates/painel/voto_nominal.html @@ -21,7 +21,7 @@ } - {% if permissao and presente %} + {% if not error_message %}

    {{sessao}}

    @@ -74,23 +74,7 @@ - {% elif not permissao %} - {% if error_message %} -

    {{error_message}}

    - {% else %} -

    Usuário sem permissão para participar de votações.

    - {% endif %} - {% elif not presente %} - {% if error_message %} -

    {{error_message}}

    {% else %} -

    Usuário não presente na Sessão Plenária.

    - {% endif %} - {% else %} - {% if error_message %}

    {{error_message}}

    - {% else %} -

    Usuário não presente na Sessão Plenária e sem permissão para votações.

    {% endif %} - {% endif %} diff --git a/sapl/templates/sessao/sessaoplenaria_detail.html b/sapl/templates/sessao/sessaoplenaria_detail.html deleted file mode 100644 index bd6c66ab4..000000000 --- a/sapl/templates/sessao/sessaoplenaria_detail.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "crud/detail.html" %} -{% load i18n %} -{% load crispy_forms_tags %} - - -{% block extra_actions %} -{% if 'parlamentares.can_vote' in request.user.get_all_permissions %} - -{% endif %} -{% endblock extra_actions %}