Browse Source

Merge pull request #906 from interlegis/762-votação-eletrônica

Fix #762 votação eletrônica
pull/907/head
Eduardo Edson Batista Cordeiro Alves 8 years ago
committed by GitHub
parent
commit
24f3e40932
  1. 2
      sapl/norma/forms.py
  2. 5
      sapl/painel/urls.py
  3. 107
      sapl/painel/views.py
  4. 30
      sapl/parlamentares/apps.py
  5. 94
      sapl/parlamentares/forms.py
  6. 31
      sapl/parlamentares/migrations/0037_votante.py
  7. 19
      sapl/parlamentares/migrations/0038_auto_20170213_1425.py
  8. 19
      sapl/parlamentares/migrations/0039_remove_votante_ip.py
  9. 17
      sapl/parlamentares/models.py
  10. 5
      sapl/parlamentares/urls.py
  11. 34
      sapl/parlamentares/views.py
  12. 39
      sapl/sessao/migrations/0034_votonominal.py
  13. 23
      sapl/sessao/migrations/0035_auto_20170213_1455.py
  14. 21
      sapl/sessao/models.py
  15. 132
      sapl/sessao/views.py
  16. 3
      sapl/templates/crud/detail.html
  17. 85
      sapl/templates/painel/voto_nominal.html
  18. 5
      sapl/templates/parlamentares/layouts.yaml
  19. 2
      sapl/templates/parlamentares/subnav.yaml
  20. 16
      sapl/templates/parlamentares/votante_list.html
  21. 14
      sapl/templates/sessao/sessaoplenaria_detail.html
  22. 1
      sapl/templates/sessao/subnav.yaml
  23. 20
      sapl/templates/sessao/votacao/nominal.html

2
sapl/norma/forms.py

@ -17,9 +17,11 @@ from sapl.utils import RANGE_ANOS, RangeWidgetOverride
from .models import (AssuntoNorma, NormaJuridica, NormaRelacionada, from .models import (AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica) TipoNormaJuridica)
def ANO_CHOICES(): def ANO_CHOICES():
return [('', '---------')] + RANGE_ANOS return [('', '---------')] + RANGE_ANOS
def get_esferas(): def get_esferas():
return [('E', 'Estadual'), return [('E', 'Estadual'),
('F', 'Federal'), ('F', 'Federal'),

5
sapl/painel/urls.py

@ -3,7 +3,7 @@ from django.conf.urls import url
from .apps import AppConfig from .apps import AppConfig
from .views import (controlador_painel, cronometro_painel, get_dados_painel, from .views import (controlador_painel, cronometro_painel, get_dados_painel,
painel_mensagem_view, painel_parlamentar_view, painel_view, painel_mensagem_view, painel_parlamentar_view, painel_view,
painel_votacao_view) painel_votacao_view, votante_view)
app_name = AppConfig.name app_name = AppConfig.name
@ -19,4 +19,7 @@ urlpatterns = [
url(r'^painel/votacao$', painel_votacao_view, name='painel_votacao'), url(r'^painel/votacao$', painel_votacao_view, name='painel_votacao'),
url(r'^painel/cronometro$', cronometro_painel, name='cronometro_painel'), url(r'^painel/cronometro$', cronometro_painel, name='cronometro_painel'),
# url(r'^painel/cronometro$', include(CronometroPainelCrud.get_urls())), # url(r'^painel/cronometro$', include(CronometroPainelCrud.get_urls())),
url(r'^voto-individual/(?P<pk>\d+)$', votante_view,
name="voto_individual"),
] ]

107
sapl/painel/views.py

@ -1,4 +1,7 @@
from django.http.response import HttpResponseRedirect
from django.core.urlresolvers import reverse
from datetime import date from datetime import date
from sapl.utils import get_client_ip
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -9,10 +12,11 @@ from django.utils.translation import ugettext_lazy as _
from sapl.crud.base import Crud from sapl.crud.base import Crud
from sapl.painel.apps import AppConfig from sapl.painel.apps import AppConfig
from sapl.painel.models import Painel from sapl.painel.models import Painel
from sapl.parlamentares.models import Filiacao from sapl.parlamentares.models import Filiacao, Votante
from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia, from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia,
RegistroVotacao, SessaoPlenaria, RegistroVotacao, SessaoPlenaria,
SessaoPlenariaPresenca, VotoParlamentar) SessaoPlenariaPresenca, VotoNominal,
VotoParlamentar)
from .models import Cronometro from .models import Cronometro
@ -25,6 +29,105 @@ def check_permission(user):
return user.has_module_perms(AppConfig.label) return user.has_module_perms(AppConfig.label)
def votante_view(request, pk):
context = {'head_title': str(_('Votação Individual')), 'sessao_id': pk}
# Pega sessão
sessao = SessaoPlenaria.objects.get(pk=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 = None
if ordem_dia:
materia = ordem_dia.materia
if ordem_dia.tipo_votacao == 2:
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 == 2:
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.'})
# 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.'})
# Recupera o voto do parlamentar logado
try:
voto = VotoNominal.objects.get(
sessao=sessao,
parlamentar=parlamentar,
materia=materia)
except ObjectDoesNotExist:
context.update({'voto_parlamentar': 'Voto não computado.'})
else:
context.update({'voto_parlamentar': voto.voto})
# Salva o voto
if request.method == 'POST':
try:
voto = VotoNominal.objects.get(
sessao=sessao,
parlamentar=parlamentar,
materia=materia)
except ObjectDoesNotExist:
voto = VotoNominal.objects.create(
sessao=sessao,
parlamentar=parlamentar,
materia=materia,
voto=request.POST['voto'],
ip=get_client_ip(request),
user=request.user)
else:
voto.voto = request.POST['voto']
voto.ip = get_client_ip(request)
voto.save()
return HttpResponseRedirect(
reverse('sapl.painel:voto_individual', kwargs={'pk': pk}))
return render(request, 'painel/voto_nominal.html', context)
@user_passes_test(check_permission) @user_passes_test(check_permission)
def controlador_painel(request): def controlador_painel(request):

30
sapl/parlamentares/apps.py

@ -1,8 +1,38 @@
from django import apps from django import apps
from django.db.models.signals import post_migrate
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
def criar_grupo(permission):
from django.contrib.auth.models import Group
g = Group.objects.get_or_create(name='Votante')
g[0].permissions.add(permission)
def criar_permissao(sender, **kwargs):
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
try:
content_type = ContentType.objects.get(
app_label='parlamentares',
model='Votante')
except ObjectDoesNotExist:
content_type = ContentType.objects.create(
app_label='parlamentares',
model='Votante')
p = Permission.objects.get_or_create(
name='Can Vote', codename='can_vote', content_type=content_type)
criar_grupo(p[0])
class AppConfig(apps.AppConfig): class AppConfig(apps.AppConfig):
name = 'sapl.parlamentares' name = 'sapl.parlamentares'
label = 'parlamentares' label = 'parlamentares'
verbose_name = _('Parlamentares') verbose_name = _('Parlamentares')
def ready(self):
post_migrate.connect(criar_permissao, sender=self)

94
sapl/parlamentares/forms.py

@ -1,6 +1,10 @@
from datetime import date, timedelta from datetime import date, timedelta
from django.contrib.auth.models import Group
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Fieldset, Layout
from django import forms from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import transaction from django.db import transaction
from django.db.models import Q from django.db.models import Q
@ -8,8 +12,10 @@ from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms.widgets import ClearableFileInput from floppyforms.widgets import ClearableFileInput
from sapl.crispy_layout_mixin import form_actions, to_row
from .models import (ComposicaoColigacao, Filiacao, Frente, Legislatura, from .models import (ComposicaoColigacao, Filiacao, Frente, Legislatura,
Mandato, Parlamentar) Mandato, Parlamentar, Votante)
class ImageThumbnailFileInput(ClearableFileInput): class ImageThumbnailFileInput(ClearableFileInput):
@ -231,3 +237,89 @@ class FrenteForm(ModelForm):
class Meta: class Meta:
model = Frente model = Frente
fields = '__all__' fields = '__all__'
class VotanteForm(ModelForm):
senha = forms.CharField(
max_length=20,
label=_('Senha'),
required=True,
widget=forms.PasswordInput())
senha_confirma = forms.CharField(
max_length=20,
label=_('Confirmar Senha'),
required=True,
widget=forms.PasswordInput())
username = forms.CharField(
label=_('Usuário'),
required=True,
max_length=30)
email = forms.EmailField(
required=True,
label=_('Email'))
email_confirma = forms.EmailField(
required=True,
label=_('Confirmar Email'))
class Meta:
model = Votante
fields = ['username', 'senha', 'senha_confirma', 'email',
'email_confirma']
def __init__(self, *args, **kwargs):
row1 = to_row([('username', 4), ('senha', 4), ('senha_confirma', 4)])
row2 = to_row([('email', 6), ('email_confirma', 6)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Votante'),
row1, row2, form_actions(save_label='Salvar'))
)
super(VotanteForm, self).__init__(*args, **kwargs)
def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2:
raise ValidationError(msg)
return True
def clean(self):
cd = self.cleaned_data
if ('senha' not in cd or 'senha_confirma' not in cd or
not cd['senha'] or not cd['senha_confirma']):
raise ValidationError(_(
'A senha e sua confirmação devem ser informadas.'))
msg = _('As senhas não conferem.')
self.valida_igualdade(cd['senha'], cd['senha_confirma'], msg)
if ('email' not in cd or 'email_confirma' not in cd or
not cd['email'] or not cd['email_confirma']):
raise ValidationError(_(
'O email e sua confirmação devem ser informados.'))
msg = _('Os emails não conferem.')
self.valida_igualdade(cd['email'], cd['email_confirma'], msg)
return self.cleaned_data
@transaction.atomic
def save(self, commit=False):
votante = super(VotanteForm, self).save(commit)
# Cria user
u = User.objects.create(
username=self.cleaned_data['username'],
email=self.cleaned_data['email'])
u.set_password(self.cleaned_data['senha'])
u.save()
# Adiciona user ao grupo
g = Group.objects.filter(name='Votante')[0]
u.groups.add(g)
votante.user = u
votante.save()
return votante

31
sapl/parlamentares/migrations/0037_votante.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-02-09 15:18
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('parlamentares', '0036_partido_logo_partido'),
]
operations = [
migrations.CreateModel(
name='Votante',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('data', models.DateTimeField(auto_now_add=True, max_length=30, null=True, verbose_name='Data')),
('ip', models.CharField(blank=True, max_length=30, null=True, verbose_name='IP')),
('parlamentar', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parlamentar', to='parlamentares.Parlamentar', verbose_name='Parlamentar')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'verbose_name': 'Votantes',
},
),
]

19
sapl/parlamentares/migrations/0038_auto_20170213_1425.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-02-13 14:25
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0037_votante'),
]
operations = [
migrations.AlterModelOptions(
name='votante',
options={'verbose_name': 'Usuários'},
),
]

19
sapl/parlamentares/migrations/0039_remove_votante_ip.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-02-13 14:26
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0038_auto_20170213_1425'),
]
operations = [
migrations.RemoveField(
model_name='votante',
name='ip',
),
]

17
sapl/parlamentares/models.py

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
@ -495,3 +496,19 @@ class Frente(models.Model):
def __str__(self): def __str__(self):
return self.nome return self.nome
class Votante(models.Model):
parlamentar = models.ForeignKey(
Parlamentar, verbose_name=_('Parlamentar'), related_name='parlamentar')
user = models.ForeignKey(User, verbose_name=_('User'), related_name='user')
data = models.DateTimeField(
verbose_name=_('Data'), auto_now_add=True,
max_length=30, null=True, blank=True)
class Meta:
verbose_name = _('Usuário')
verbose_name_plural = _('Usuários')
def __str__(self):
return self.user.username

5
sapl/parlamentares/urls.py

@ -11,7 +11,7 @@ from sapl.parlamentares.views import (CargoMesaCrud, ColigacaoCrud,
RelatoriaParlamentarCrud, RelatoriaParlamentarCrud,
SessaoLegislativaCrud, SessaoLegislativaCrud,
TipoAfastamentoCrud, TipoDependenteCrud, TipoAfastamentoCrud, TipoDependenteCrud,
TipoMilitarCrud) TipoMilitarCrud, VotanteView)
from .apps import AppConfig from .apps import AppConfig
@ -23,7 +23,8 @@ urlpatterns = [
FiliacaoCrud.get_urls() + MandatoCrud.get_urls() + FiliacaoCrud.get_urls() + MandatoCrud.get_urls() +
ParticipacaoParlamentarCrud.get_urls() + ParticipacaoParlamentarCrud.get_urls() +
ProposicaoParlamentarCrud.get_urls() + ProposicaoParlamentarCrud.get_urls() +
RelatoriaParlamentarCrud.get_urls() + FrenteList.get_urls() RelatoriaParlamentarCrud.get_urls() + FrenteList.get_urls() +
VotanteView.get_urls()
)), )),
url(r'^sistema/coligacao/', url(r'^sistema/coligacao/',

34
sapl/parlamentares/views.py

@ -4,6 +4,7 @@ from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.datastructures import MultiValueDictKeyError from django.utils.datastructures import MultiValueDictKeyError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView from django.views.generic import FormView
from django.http.response import HttpResponseRedirect
from sapl.comissoes.models import Participacao from sapl.comissoes.models import Participacao
from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux, from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux,
@ -11,13 +12,14 @@ from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud) MasterDetailCrud)
from sapl.materia.models import Proposicao, Relatoria from sapl.materia.models import Proposicao, Relatoria
from sapl.parlamentares.apps import AppConfig from sapl.parlamentares.apps import AppConfig
from sapl.utils import get_client_ip
from .forms import (FiliacaoForm, LegislaturaCreateForm, LegislaturaUpdateForm, from .forms import (FiliacaoForm, LegislaturaCreateForm, LegislaturaUpdateForm,
ParlamentarCreateForm, ParlamentarForm) ParlamentarCreateForm, ParlamentarForm, VotanteForm)
from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa, from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
Dependente, Filiacao, Frente, Legislatura, Mandato, Dependente, Filiacao, Frente, Legislatura, Mandato,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa, NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente) SituacaoMilitar, TipoAfastamento, TipoDependente, Votante)
CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa') CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
PartidoCrud = CrudAux.build(Partido, 'partidos') PartidoCrud = CrudAux.build(Partido, 'partidos')
@ -34,6 +36,34 @@ DependenteCrud = MasterDetailCrud.build(
Dependente, 'parlamentar', 'dependente') Dependente, 'parlamentar', 'dependente')
class VotanteView(MasterDetailCrud):
model = Votante
parent_field = 'parlamentar'
UpdateView = None
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['user']
class CreateView(MasterDetailCrud.CreateView):
form_class = VotanteForm
layout_key = None
class DetailView(MasterDetailCrud.DetailView):
def detail_create_url(self):
return None
class DeleteView(MasterDetailCrud.DeleteView):
def delete(self, *args, **kwargs):
obj = self.get_object()
if obj.user:
obj.user.delete()
return HttpResponseRedirect(
reverse('sapl.parlamentares:votante_list',
kwargs={'pk': obj.parlamentar.pk}))
class FrenteList(MasterDetailCrud): class FrenteList(MasterDetailCrud):
model = Frente model = Frente
is_m2m = True is_m2m = True

39
sapl/sessao/migrations/0034_votonominal.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-02-13 14:37
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('materia', '0075_auto_20170203_1019'),
('parlamentares', '0039_remove_votante_ip'),
('sessao', '0033_merge'),
]
operations = [
migrations.CreateModel(
name='VotoNominal',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('voto', models.CharField(max_length=10, verbose_name='Voto')),
('ip', models.CharField(max_length=30, verbose_name='IP')),
('data_hora', models.DateTimeField(auto_now_add=True, verbose_name='Data/Hora')),
('expediente', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.ExpedienteMateria')),
('materia', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa')),
('ordem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.OrdemDia')),
('parlamentar', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Parlamentar')),
('sessao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sessao.SessaoPlenaria')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Registro do Voto do Parlamentar',
'verbose_name_plural': 'Registros dos Votos dos Parlamentares',
},
),
]

23
sapl/sessao/migrations/0035_auto_20170213_1455.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2017-02-13 14:55
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('sessao', '0034_votonominal'),
]
operations = [
migrations.RemoveField(
model_name='votonominal',
name='expediente',
),
migrations.RemoveField(
model_name='votonominal',
name='ordem',
),
]

21
sapl/sessao/models.py

@ -1,3 +1,4 @@
from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
@ -375,6 +376,26 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
'votacao': self.votacao, 'parlamentar': self.parlamentar} 'votacao': self.votacao, 'parlamentar': self.parlamentar}
class VotoNominal(models.Model):
parlamentar = models.ForeignKey(Parlamentar)
voto = models.CharField(verbose_name=_('Voto'), max_length=10)
sessao = models.ForeignKey(SessaoPlenaria)
materia = models.ForeignKey(MateriaLegislativa)
user = models.ForeignKey(User)
ip = models.CharField(verbose_name=_('IP'), max_length=30)
data_hora = models.DateTimeField(
verbose_name=_('Data/Hora'), auto_now_add=True)
class Meta:
verbose_name = _('Registro do Voto do Parlamentar')
verbose_name_plural = _('Registros dos Votos dos Parlamentares')
def __str__(self):
return self.Parlamentar, self.voto
class SessaoPlenariaPresenca(models.Model): class SessaoPlenariaPresenca(models.Model):
sessao_plenaria = models.ForeignKey(SessaoPlenaria) sessao_plenaria = models.ForeignKey(SessaoPlenaria)
parlamentar = models.ForeignKey(Parlamentar) parlamentar = models.ForeignKey(Parlamentar)

132
sapl/sessao/views.py

@ -3,7 +3,7 @@ from re import sub
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.http import JsonResponse from django.http import JsonResponse
@ -42,7 +42,8 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
MateriaLegislativa, Orador, OradorExpediente, OrdemDia, MateriaLegislativa, Orador, OradorExpediente, OrdemDia,
PresencaOrdemDia, RegistroVotacao, SessaoPlenaria, PresencaOrdemDia, RegistroVotacao, SessaoPlenaria,
SessaoPlenariaPresenca, TipoExpediente, SessaoPlenariaPresenca, TipoExpediente,
TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar) TipoResultadoVotacao, TipoSessaoPlenaria, VotoNominal,
VotoParlamentar)
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria') TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente') TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
@ -1316,7 +1317,7 @@ class VotacaoNominalView(SessaoPermissionMixin):
'ementa': sub( 'ementa': sub(
'&nbsp;', ' ', strip_tags(ordem.observacao))} '&nbsp;', ' ', strip_tags(ordem.observacao))}
context = {'materia': materia, 'object': self.get_object(), context = {'materia': materia, 'object': self.get_object(),
'parlamentares': self.get_parlamentares(), 'parlamentares': self.get_parlamentares(ordem.materia),
'tipos': self.get_tipos_votacao(), 'tipos': self.get_tipos_votacao(),
'total': total} 'total': total}
@ -1331,6 +1332,21 @@ class VotacaoNominalView(SessaoPermissionMixin):
form = VotacaoNominalForm(request.POST) form = VotacaoNominalForm(request.POST)
if 'cancelar-votacao' in request.POST: if 'cancelar-votacao' in request.POST:
sessao = self.object
materia = ordem.materia
presentes = PresencaOrdemDia.objects.filter(
sessao_plenaria_id=expediente.sessao_plenaria_id)
for p in presentes:
try:
voto = VotoNominal.objects.get(
parlamentar=p.parlamentar,
sessao=self.object.pk,
materia=materia)
except ObjectDoesNotExist:
pass
else:
voto.delete()
ordem.votacao_aberta = False ordem.votacao_aberta = False
ordem.save() ordem.save()
return self.form_valid(form) return self.form_valid(form)
@ -1349,13 +1365,13 @@ class VotacaoNominalView(SessaoPermissionMixin):
voto = v[0] voto = v[0]
parlamentar_id = v[1] parlamentar_id = v[1]
if(voto == 'sim'): if(voto == 'Sim'):
votos_sim += 1 votos_sim += 1
elif(voto == 'nao'): elif(voto == 'o'):
votos_nao += 1 votos_nao += 1
elif(voto == 'abstencao'): elif(voto == 'Abstenção'):
abstencoes += 1 abstencoes += 1
elif(voto == 'nao_votou'): elif(voto == 'Não Votou'):
nao_votou += 1 nao_votou += 1
try: try:
@ -1384,14 +1400,7 @@ class VotacaoNominalView(SessaoPermissionMixin):
parlamentar_id = v[1] parlamentar_id = v[1]
voto_parlamentar = VotoParlamentar() voto_parlamentar = VotoParlamentar()
if voto == 'sim': voto_parlamentar.voto = voto
voto_parlamentar.voto = _('Sim')
elif voto == 'nao':
voto_parlamentar.voto = _('Não')
elif voto == 'abstencao':
voto_parlamentar.voto = _('Abstenção')
elif voto == 'nao_votou':
voto_parlamentar.voto = _('Não Votou')
voto_parlamentar.parlamentar_id = parlamentar_id voto_parlamentar.parlamentar_id = parlamentar_id
voto_parlamentar.votacao_id = votacao.id voto_parlamentar.votacao_id = votacao.id
voto_parlamentar.save() voto_parlamentar.save()
@ -1409,7 +1418,7 @@ class VotacaoNominalView(SessaoPermissionMixin):
else: else:
return self.form_invalid(form) return self.form_invalid(form)
def get_parlamentares(self): def get_parlamentares(self, materia):
self.object = self.get_object() self.object = self.get_object()
presencas = PresencaOrdemDia.objects.filter( presencas = PresencaOrdemDia.objects.filter(
@ -1419,7 +1428,15 @@ class VotacaoNominalView(SessaoPermissionMixin):
for parlamentar in Parlamentar.objects.filter(ativo=True): for parlamentar in Parlamentar.objects.filter(ativo=True):
if parlamentar in presentes: if parlamentar in presentes:
yield parlamentar try:
voto = VotoNominal.objects.get(
parlamentar=parlamentar,
sessao=self.object.pk,
materia=materia)
except ObjectDoesNotExist:
yield [parlamentar, None]
else:
yield [parlamentar, voto.voto]
def get_tipos_votacao(self): def get_tipos_votacao(self):
for tipo in TipoResultadoVotacao.objects.all(): for tipo in TipoResultadoVotacao.objects.all():
@ -1474,6 +1491,21 @@ class VotacaoNominalEditView(SessaoPermissionMixin):
materia_id = kwargs['oid'] materia_id = kwargs['oid']
ordem_id = kwargs['mid'] ordem_id = kwargs['mid']
sessao = self.object
ordem = ExpedienteMateria.objects.get(id=ordem_id)
presentes = PresencaOrdemDia.objects.filter(
sessao_plenaria_id=ordem.sessao_plenaria_id)
for p in presentes:
try:
voto = VotoNominal.objects.get(
parlamentar=p.parlamentar,
sessao=self.object.pk,
materia=materia_id)
except ObjectDoesNotExist:
pass
else:
voto.delete()
if(int(request.POST['anular_votacao']) == 1): if(int(request.POST['anular_votacao']) == 1):
registro = RegistroVotacao.objects.get( registro = RegistroVotacao.objects.get(
materia_id=materia_id, materia_id=materia_id,
@ -1494,8 +1526,6 @@ class VotacaoNominalEditView(SessaoPermissionMixin):
except: except:
pass pass
registro.delete()
return self.form_valid(form) return self.form_valid(form)
def get_tipos_votacao(self): def get_tipos_votacao(self):
@ -1521,7 +1551,7 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
'ementa': sub( 'ementa': sub(
'&nbsp;', ' ', strip_tags(expediente.observacao))} '&nbsp;', ' ', strip_tags(expediente.observacao))}
context = {'materia': materia, 'object': self.get_object(), context = {'materia': materia, 'object': self.get_object(),
'parlamentares': self.get_parlamentares(), 'parlamentares': self.get_parlamentares(expediente.materia),
'tipos': self.get_tipos_votacao(), 'tipos': self.get_tipos_votacao(),
'total': total} 'total': total}
@ -1536,6 +1566,23 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
form = VotacaoNominalForm(request.POST) form = VotacaoNominalForm(request.POST)
if 'cancelar-votacao' in request.POST: if 'cancelar-votacao' in request.POST:
sessao = self.object
expediente_id = kwargs['mid']
expediente = ExpedienteMateria.objects.get(id=expediente_id)
materia = expediente.materia
presentes = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=expediente.sessao_plenaria_id)
for p in presentes:
try:
voto = VotoNominal.objects.get(
parlamentar=p.parlamentar,
sessao=self.object.pk,
materia=materia)
except ObjectDoesNotExist:
pass
else:
voto.delete()
expediente.votacao_aberta = False expediente.votacao_aberta = False
expediente.save() expediente.save()
return self.form_valid(form) return self.form_valid(form)
@ -1554,13 +1601,13 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
voto = v[0] voto = v[0]
parlamentar_id = v[1] parlamentar_id = v[1]
if(voto == 'sim'): if(voto == 'Sim'):
votos_sim += 1 votos_sim += 1
elif(voto == 'nao'): elif(voto == 'o'):
votos_nao += 1 votos_nao += 1
elif(voto == 'abstencao'): elif(voto == 'Abstenção'):
abstencoes += 1 abstencoes += 1
elif(voto == 'nao_votou'): elif(voto == 'Não Votou'):
nao_votou += 1 nao_votou += 1
try: try:
@ -1587,14 +1634,7 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
parlamentar_id = v[1] parlamentar_id = v[1]
voto_parlamentar = VotoParlamentar() voto_parlamentar = VotoParlamentar()
if(voto == 'sim'): voto_parlamentar.voto = voto
voto_parlamentar.voto = _('Sim')
elif(voto == 'nao'):
voto_parlamentar.voto = _('Não')
elif(voto == 'abstencao'):
voto_parlamentar.voto = _('Abstenção')
elif(voto == 'nao_votou'):
voto_parlamentar.voto = _('Não Votou')
voto_parlamentar.parlamentar_id = parlamentar_id voto_parlamentar.parlamentar_id = parlamentar_id
voto_parlamentar.votacao_id = votacao.id voto_parlamentar.votacao_id = votacao.id
voto_parlamentar.save() voto_parlamentar.save()
@ -1612,9 +1652,8 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
else: else:
return self.form_invalid(form) return self.form_invalid(form)
def get_parlamentares(self): def get_parlamentares(self, materia):
self.object = self.get_object() self.object = self.get_object()
presencas = SessaoPlenariaPresenca.objects.filter( presencas = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=self.object.id sessao_plenaria_id=self.object.id
) )
@ -1622,7 +1661,15 @@ class VotacaoNominalExpedienteView(SessaoPermissionMixin):
for parlamentar in Parlamentar.objects.filter(ativo=True): for parlamentar in Parlamentar.objects.filter(ativo=True):
if parlamentar in presentes: if parlamentar in presentes:
yield parlamentar try:
voto = VotoNominal.objects.get(
parlamentar=parlamentar,
sessao=self.object.pk,
materia=materia)
except ObjectDoesNotExist:
yield [parlamentar, None]
else:
yield [parlamentar, voto.voto]
def get_tipos_votacao(self): def get_tipos_votacao(self):
for tipo in TipoResultadoVotacao.objects.all(): for tipo in TipoResultadoVotacao.objects.all():
@ -1676,6 +1723,21 @@ class VotacaoNominalExpedienteEditView(SessaoPermissionMixin):
materia_id = kwargs['oid'] materia_id = kwargs['oid']
expediente_id = kwargs['mid'] expediente_id = kwargs['mid']
sessao = self.object
expediente = ExpedienteMateria.objects.get(id=expediente_id)
presentes = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=expediente.sessao_plenaria_id)
for p in presentes:
try:
voto = VotoNominal.objects.get(
parlamentar=p.parlamentar,
sessao=self.object.pk,
materia=materia_id)
except ObjectDoesNotExist:
pass
else:
voto.delete()
if(int(request.POST['anular_votacao']) == 1): if(int(request.POST['anular_votacao']) == 1):
registro = RegistroVotacao.objects.get( registro = RegistroVotacao.objects.get(
materia_id=materia_id, materia_id=materia_id,

3
sapl/templates/crud/detail.html

@ -32,6 +32,9 @@
{% endif %} {% endif %}
{% endblock sub_actions %} {% endblock sub_actions %}
{% block extra_actions %}
{% endblock extra_actions %}
<div class="editons pull-right"> <div class="editons pull-right">
{% block editions %} {% block editions %}
{% if view.update_url or view.delete_url %} {% if view.update_url or view.delete_url %}

85
sapl/templates/painel/voto_nominal.html

@ -0,0 +1,85 @@
{% load i18n %}
{% load staticfiles sass_tags %}
<!DOCTYPE HTML>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{% sass_src 'bootstrap-sass/assets/stylesheets/_bootstrap.scss' %}" type="text/css">
<title>{% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="{% static 'jquery/dist/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'js/jquery.runner.js' %}"></script>
<style type="text/css">
@media screen {
body {
background: #1c1b1b;
}
ul, li {
list-style-type: none;
}
}
</style>
</head>
{% if permissao and presente %}
<body>
<h1><b><font color="#4FA64D"><p align="center">{{sessao}}</p></font></b></h1>
<table style="width:100%">
<tr>
<th style="text-align:center"><font color="white" size="4">Hora Início: {{hora}}</font></th>
<th style="text-align:center"><font color="white" size="4">Data Início: {{data}}</font></th>
</tr>
</table>
<h1><font color="white"><p align="center"><span id="relogio"></span></p></font></h1>
</br>
</br>
<h2><font color="red"><p align="center" style="font-family:Verdana">Voto: {{voto_parlamentar}}</p></font></h2>
</br>
</br>
<h2><font color="#459170"><p align="center" style="font-family:Verdana">Matéria em Votação</p></font></h2>
<table style="width:75%; border:1px;" align="center">
<tr><th style="text-align:center"><h4><font color="white">{{materia}}</font></th></tr>
<tr><th style="text-align:center"><h4><font color="white">{{ementa}}</font></th></tr>
<tr><th style="text-align:center"><font color="#45919D"><span id="resultado_votacao"></span></font></th></tr>
</table>
<br /><br />
<form method='POST'>
{% csrf_token %}
<table style="width:75%; border:1px;" align="center">
<tr><th style="text-align:center">
<select id="voto" name="voto" style="width:30%;">
<option value="">Selecione</option>
<option value="Sim">Sim</option>
<option value="Não">Não</option>
<option value="Abstenção">Abstenção</option>
</select>
</th></tr>
<tr><th style="text-align:center">
<input type="submit" value="Votar" name="Votar" style="width:10%;"/>
</th></tr>
</table>
</form>
</body>
{% elif not permissao %}
{% if error_message %}
<h2><font color="red"><p align="center" style="font-family:Verdana">{{error_message}}</p></font></h2>
{% else %}
<h2><font color="red"><p align="center" style="font-family:Verdana">Usuário sem permissão para participar de votações.</p></font></h2>
{% endif %}
{% elif not presente %}
{% if error_message %}
<h2><font color="red"><p align="center" style="font-family:Verdana">{{error_message}}</p></font></h2>
{% else %}
<h2><font color="red"><p align="center" style="font-family:Verdana">Usuário não presente na Sessão Plenária.</p></font></h2>
{% endif %}
{% else %}
{% if error_message %}
<h2><font color="red"><p align="center" style="font-family:Verdana">{{error_message}}</p></font></h2>
{% else %}
<h2><font color="red"><p align="center" style="font-family:Verdana">Usuário não presente na Sessão Plenária e sem permissão para votações.</p></font></h2>
{% endif %}
{% endif %}
</html>

5
sapl/templates/parlamentares/layouts.yaml

@ -101,3 +101,8 @@ Frente:
- data_criacao data_extincao - data_criacao data_extincao
- parlamentares - parlamentares
- descricao - descricao
Votante:
{% trans 'Votante' %}:
- parlamentar user
- data

2
sapl/templates/parlamentares/subnav.yaml

@ -16,3 +16,5 @@
url: relatoria_parlamentar_list url: relatoria_parlamentar_list
- title: {% trans 'Frentes' %} - title: {% trans 'Frentes' %}
url: frente_parlamentar_list url: frente_parlamentar_list
- title: {% trans 'Usuário' %}
url: votante_list

16
sapl/templates/parlamentares/votante_list.html

@ -0,0 +1,16 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}
{% if not rows %}
<div class="actions btn-group pull-right btn-group-lg" role="group">
{% if view.create_url %}
<a href="{{ view.create_url }}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>
{% endif %}
{% endblock actions %}

14
sapl/templates/sessao/sessaoplenaria_detail.html

@ -0,0 +1,14 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block extra_actions %}
{% if 'parlamentares.can_vote' in request.user.get_all_permissions %}
<div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.painel:voto_individual' object.pk %}" class="btn btn-default">
Votar Matéria
</a>
</div>
{% endif %}
{% endblock extra_actions %}

1
sapl/templates/sessao/subnav.yaml

@ -30,5 +30,6 @@
- title: {% trans 'Painel Eletrônico' %} - title: {% trans 'Painel Eletrônico' %}
url: painel url: painel
{% if not 'painel_aberto'|get_config_attr %}check_permission: painel.list_painel{%endif%} {% if not 'painel_aberto'|get_config_attr %}check_permission: painel.list_painel{%endif%}
- title: {% trans 'Resumo' %} - title: {% trans 'Resumo' %}
url: resumo url: resumo

20
sapl/templates/sessao/votacao/nominal.html

@ -20,16 +20,22 @@
<a href="{% url 'sapl.sessao:sessaoplenaria_detail' object.pk %}" class="btn btn-warning">Voltar</a> <a href="{% url 'sapl.sessao:sessaoplenaria_detail' object.pk %}" class="btn btn-warning">Voltar</a>
{% else %} {% else %}
<fieldset class="form-group"> <fieldset class="form-group">
<div class="row">
<div class="col-md-12"><input type="button" value="Atualizar Votos" onClick="window.location.href=window.location.href" class="btn btn-primary sm"></div>
</div>
<br />
<legend>Votos</legend> <legend>Votos</legend>
<div class="row"> <div class="row">
{% for parlamentar in parlamentares %} {% for parlamentar in parlamentares %}
<div class="col-md-6">{{parlamentar.nome_parlamentar}}</div> <div class="col-md-6">{{parlamentar.0.nome_parlamentar}}</div>
<div class="col-md-6"> <div class="col-md-6">
<select id="voto_parlamentar" name="voto_parlamentar" class="form-control"> {% if parlamentar.1 %} <input type="hidden" name="voto_parlamentar" value="{{parlamentar.1}}:{{parlamentar.0.id}}" /> {% endif %}
<option value="sim:{{parlamentar.id}}">Sim</option> <select id="voto_parlamentar" name="voto_parlamentar" class="form-control" {% if parlamentar.1 %} disabled {% endif %}>
<option value="nao:{{parlamentar.id}}">Não</option> <option value="Não Votou:{{parlamentar.0.id}}">Não Votou</option>
<option value="abstencao:{{parlamentar.id}}">Abstenção</option> <option value="Sim:{{parlamentar.0.id}}" {% if parlamentar.1 == 'Sim' %} selected {% endif %}>Sim</option>
<option value="nao_votou:{{parlamentar.id}}">Não Votou</option> <option value="Não:{{parlamentar.0.id}}" {% if parlamentar.1 == 'Não' %} selected {% endif %}>Não</option>
<option value="Abstenção:{{parlamentar.0.id}}" {% if parlamentar.1 == 'Abstenção' %} selected {% endif %}>Abstenção</option>
</select> </select>
</div> </div>
{% endfor %} {% endfor %}
@ -56,7 +62,7 @@
</div> </div>
<br /><br /> <br /><br />
<input type="submit" id="salvar-votacao" name="salvar-votacao" value="Salvar" class="btn btn-primary" /> <input type="submit" id="salvar-votacao" name="salvar-votacao" value="Fechar Votação" class="btn btn-primary" />
<input type="submit" id="cancelar-votacao" name="cancelar-votacao" value="Cancelar Votação" class="btn btn-warning" /> <input type="submit" id="cancelar-votacao" name="cancelar-votacao" value="Cancelar Votação" class="btn btn-warning" />
</fieldset> </fieldset>
</form> </form>

Loading…
Cancel
Save