diff --git a/docker-compose.yml b/docker-compose.yml
index 12f3c8ff5..cb57ad36e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
- image: interlegis/sapl:3.1.157-RC5
+ image: interlegis/sapl:3.1.158
# build: .
restart: always
environment:
diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py
index f3f2294ee..671e5bcf1 100644
--- a/sapl/compilacao/views.py
+++ b/sapl/compilacao/views.py
@@ -2147,8 +2147,11 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
return self.json_add_next(context, local_add='json_add_in')
def json_add_next(
- self,
- context, local_add='json_add_next', create_auto_inserts=True):
+ self,
+ context, local_add='json_add_next',
+ create_auto_inserts=True,
+ registro_inclusao=False
+ ):
try:
@@ -2249,7 +2252,9 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
dp.rotulo = dp.rotulo_padrao()
dp.ordem = ordem
- dp.incrementar_irmaos(variacao, [local_add, ], force=False)
+
+ if not registro_inclusao:
+ dp.incrementar_irmaos(variacao, [local_add, ], force=False)
dp.publicacao = pub_last
dp.save()
@@ -2380,9 +2385,10 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
filho.save()
''' Renumerar dispositivos de
- contagem continua, caso a inserção seja uma articulação'''
+ contagem continua, caso a inserção seja uma articulação.
+ Desde que não seja um registro de inclusão através de compilação'''
- if dp.nivel == 0:
+ if dp.nivel == 0 and not registro_inclusao:
proxima_articulacao = dp.select_next_root()
@@ -2522,7 +2528,8 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
data = self.json_add_next(context,
local_add=local_add,
- create_auto_inserts=True)
+ create_auto_inserts=True,
+ registro_inclusao=True)
if data and data['pk']:
@@ -2554,6 +2561,11 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
else:
data.update({'pk': bloco_alteracao.pk,
'pai': [bloco_alteracao.pk, ]})
+ self.set_message(
+ data, 'danger',
+ _('Não é possível incluir seu Registro de Inclusão, '
+ 'verifique a opção escolhida e as variações possíveis!'),
+ time=10000)
return data
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index 6ad0fa11c..8955ebc31 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -285,7 +285,7 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
materia = super(MateriaLegislativaForm, self).save(commit)
materia.save()
-
+
if self.cleaned_data['autor']:
autoria = Autoria()
autoria.primeiro_autor = primeiro_autor
@@ -1168,7 +1168,7 @@ class DespachoInicialForm(ModelForm):
class AutoriaForm(ModelForm):
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
- required=False,
+ required=True,
queryset=TipoAutor.objects.all(),
empty_label=_('Selecione'),)
@@ -1180,6 +1180,12 @@ class AutoriaForm(ModelForm):
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
+ self.fields['primeiro_autor'].required = True
+
+ if 'initial' in kwargs and 'materia' in kwargs['initial']:
+ materia = kwargs['initial']['materia']
+ self.fields['primeiro_autor'].initial = Autoria.objects.filter(materia=materia).count() == 0
+
row1 = to_row([('tipo_autor', 4),
('autor', 4),
('primeiro_autor', 4)])
@@ -1220,7 +1226,7 @@ class AutoriaMultiCreateForm(Form):
logger = logging.getLogger(__name__)
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
- required=False,
+ required=True,
queryset=TipoAutor.objects.all(),
empty_label=_('Selecione'),)
@@ -1230,7 +1236,7 @@ class AutoriaMultiCreateForm(Form):
autor = ModelMultipleChoiceField(
queryset=Autor.objects.all(),
label=_('Possiveis Autores'),
- required=False,
+ required=True,
widget=CheckboxSelectMultiple)
autores = ModelMultipleChoiceField(
@@ -1238,10 +1244,19 @@ class AutoriaMultiCreateForm(Form):
required=False,
widget=HiddenInput)
+ primeiro_autor = forms.ChoiceField(
+ required=True,
+ choices=YES_NO_CHOICES,
+ label="Primeiro Autor?"
+ )
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- row1 = to_row([('tipo_autor', 12), ])
+ if 'initial' in kwargs and 'autores' in kwargs['initial']:
+ self.fields['primeiro_autor'].initial = kwargs['initial']['autores'].count() == 0
+
+ row1 = to_row([('tipo_autor', 10), ('primeiro_autor', 2)])
row2 = to_row([('autor', 12), ])
diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py
index e12b03dff..dabf29bed 100644
--- a/sapl/materia/tests/test_materia.py
+++ b/sapl/materia/tests/test_materia.py
@@ -243,6 +243,7 @@ def test_autoria_submit(admin_client):
reverse('sapl.materia:autoria_create',
kwargs={'pk': materia_principal.pk}),
{'autor': autor.pk,
+ 'tipo_autor': tipo_autor.pk,
'primeiro_autor': True,
'materia_id': materia_principal.pk, },
follow=True)
diff --git a/sapl/materia/tests/test_materia_form.py b/sapl/materia/tests/test_materia_form.py
index e29d89815..215f114a2 100644
--- a/sapl/materia/tests/test_materia_form.py
+++ b/sapl/materia/tests/test_materia_form.py
@@ -129,9 +129,11 @@ def test_valida_campos_obrigatorios_autoria_form():
errors = form.errors
- assert errors['autor'] == [_('Este campo é obrigatório.')]
+ assert len(errors) == 3
- assert len(errors) == 1
+ assert errors['tipo_autor'] == [_('Este campo é obrigatório.')]
+ assert errors['autor'] == [_('Este campo é obrigatório.')]
+ assert errors['primeiro_autor'] == [_('Este campo é obrigatório.')]
@pytest.mark.django_db(transaction=False)
@@ -142,9 +144,12 @@ def test_valida_campos_obrigatorios_autoria_multicreate_form():
errors = form.errors
- assert errors['__all__'] == [_('Ao menos um autor deve ser selecionado para inclusão')]
+ assert len(errors) == 4
- assert len(errors) == 1
+ assert errors['__all__'] == [_('Ao menos um autor deve ser selecionado para inclusão')]
+ assert errors['tipo_autor'] == [_('Este campo é obrigatório.')]
+ assert errors['autor'] == [_('Este campo é obrigatório.')]
+ assert errors['primeiro_autor'] == [_('Este campo é obrigatório.')]
@pytest.mark.django_db(transaction=False)
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index f5d80ce11..739f4c486 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -1224,7 +1224,7 @@ class TramitacaoCrud(MasterDetailCrud):
# não pode ser modificado
if not primeira_tramitacao:
context['form'].fields[
- 'unidade_tramitacao_local'].widget.attrs['disabled'] = True
+ 'unidade_tramitacao_local'].widget.attrs['readonly'] = True
return context
@@ -1432,6 +1432,7 @@ class AutoriaCrud(MasterDetailCrud):
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
initial['data_relativa'] = materia.data_apresentacao
initial['autor'] = []
+ initial['materia'] = materia
return initial
class UpdateView(LocalBaseMixin, MasterDetailCrud.UpdateView):
@@ -1441,6 +1442,7 @@ class AutoriaCrud(MasterDetailCrud):
initial.update({
'data_relativa': self.object.materia.data_apresentacao,
'tipo_autor': self.object.autor.tipo.id,
+ 'materia': self.object.materia
})
return initial
@@ -1480,8 +1482,9 @@ class AutoriaMultiCreateView(PermissionRequiredForAppCrudMixin, FormView):
def form_valid(self, form):
autores_selecionados = form.cleaned_data['autor']
+ primeiro_autor = form.cleaned_data['primeiro_autor']
for autor in autores_selecionados:
- Autoria.objects.create(materia=self.materia, autor=autor)
+ Autoria.objects.create(materia=self.materia, autor=autor, primeiro_autor=primeiro_autor)
return FormView.form_valid(self, form)
@@ -1616,14 +1619,13 @@ class MateriaLegislativaCrud(Crud):
form_class = MateriaLegislativaForm
- def form_valid(self, form):
- self.object = form.instance
+ def get_initial(self):
+ initial = super(CreateView, self).get_initial()
- self.object.user = self.request.user
- self.object.ip = get_client_ip(self.request)
- self.object.save()
+ initial['user'] = self.request.user
+ initial['ip'] = get_client_ip(self.request)
- return super().form_valid(form)
+ return initial
@property
def cancel_url(self):
@@ -1679,7 +1681,7 @@ class MateriaLegislativaCrud(Crud):
class DetailView(Crud.DetailView):
layout_key = 'MateriaLegislativaDetail'
- template_name = "materia/materia_detail.html"
+ template_name = "materia/materialegislativa_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
diff --git a/sapl/parlamentares/migrations/0030_auto_20190613_1133.py b/sapl/parlamentares/migrations/0030_auto_20190613_1133.py
new file mode 100644
index 000000000..3856a0de1
--- /dev/null
+++ b/sapl/parlamentares/migrations/0030_auto_20190613_1133.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.21 on 2019-06-13 14:33
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('parlamentares', '0029_auto_20190517_1531'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='partido',
+ options={'ordering': ['sigla', 'nome'], 'verbose_name': 'Partido', 'verbose_name_plural': 'Partidos'},
+ ),
+ ]
diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py
index d50600eba..9f4cc4138 100644
--- a/sapl/parlamentares/models.py
+++ b/sapl/parlamentares/models.py
@@ -122,6 +122,7 @@ class Partido(models.Model):
class Meta:
verbose_name = _('Partido')
verbose_name_plural = _('Partidos')
+ ordering = ['sigla', 'nome']
def __str__(self):
return _('%(sigla)s - %(nome)s') % {
diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py
index 71d45b7d7..f56409c0a 100644
--- a/sapl/protocoloadm/forms.py
+++ b/sapl/protocoloadm/forms.py
@@ -1331,7 +1331,7 @@ def filtra_tramitacao_adm_status(status):
lista = pega_ultima_tramitacao_adm()
return TramitacaoAdministrativo.objects.filter(
id__in=lista,
- status=status).distinct().values_list('materia_id', flat=True)
+ status=status).distinct().values_list('documento_id', flat=True)
def filtra_tramitacao_adm_destino(destino):
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
index 89de69c72..32f6748ad 100755
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -1160,7 +1160,7 @@ class TramitacaoAdmCrud(MasterDetailCrud):
# não pode ser modificado
if not primeira_tramitacao:
context['form'].fields[
- 'unidade_tramitacao_local'].widget.attrs['disabled'] = True
+ 'unidade_tramitacao_local'].widget.attrs['readonly'] = True
return context
def form_valid(self, form):
@@ -1455,7 +1455,7 @@ class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
filterset_class = PrimeiraTramitacaoEmLoteAdmFilterSet
template_name = 'protocoloadm/em_lote/tramitacaoadm.html'
- permission_required = ('materia.add_tramitacao', )
+ permission_required = ('protocoloadm.add_tramitacaoadministrativo', )
primeira_tramitacao = True
diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
index 4b1d62719..805731a70 100644
--- a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
+++ b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
@@ -203,13 +203,14 @@ def expedientes(lst_expedientes):
tmp += '\t\t\t \n'
tmp += '\t\t\n'
for expediente in lst_expedientes:
- tmp += '\t\t' + '
' + \
- expediente['nom_expediente'] + ': \n' + \
- '' + \
- expediente['txt_expediente'] + '\n'
- tmp += '\t\t\n'
- tmp += '\t\t\t \n'
- tmp += '\t\t\n'
+ if expediente['txt_expediente']:
+ tmp += '\t\t' + '
' + \
+ expediente['nom_expediente'] + ': \n' + \
+ '' + \
+ expediente['txt_expediente'] + '\n'
+ tmp += '\t\t\n'
+ tmp += '\t\t\t \n'
+ tmp += '\t\t\n'
return tmp
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
index c09d2f220..9b3fc1f90 100644
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -1,6 +1,5 @@
from datetime import datetime
-from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout
from django import forms
from django.contrib.contenttypes.models import ContentType
@@ -13,6 +12,7 @@ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor, TipoAutor
+from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.crispy_layout_mixin import form_actions, to_row, SaplFormLayout
from sapl.materia.forms import MateriaLegislativaFilterSet
from sapl.materia.models import (MateriaLegislativa, StatusTramitacao,
@@ -60,21 +60,11 @@ class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm):
"para a Legislatura, Sessão Legislativa e Tipo informados. "
"Favor escolher um número distinto.")
- sessoes = SessaoPlenaria.objects.filter(numero=num,
- sessao_legislativa=sl,
- legislatura=leg,
- tipo=tipo,
- data_inicio__year=abertura.year).\
- values_list('id', flat=True)
-
- qtd_sessoes = len(sessoes)
+ qs = tipo.queryset_tipo_numeracao(leg, sl, abertura)
+ qs &= Q(numero=num)
- if qtd_sessoes > 0:
- if instance.pk: # update
- if instance.pk not in sessoes or qtd_sessoes > 1:
- raise error
- else: # create
- raise error
+ if SessaoPlenaria.objects.filter(qs).exclude(pk=instance.pk).exists():
+ raise error
# Condições da verificação
abertura_entre_leg = leg.data_inicio <= abertura <= leg.data_fim
@@ -474,6 +464,9 @@ class VotacaoForm(forms.Form):
abstencoes = forms.IntegerField(label='Abstenções')
total_presentes = forms.IntegerField(
required=False, widget=forms.HiddenInput())
+ total_votantes = forms.IntegerField(
+ required=False, widget=forms.HiddenInput()
+ )
voto_presidente = forms.IntegerField(
label='A totalização inclui o voto do Presidente?')
total_votos = forms.IntegerField(required=False, label='total')
@@ -489,15 +482,16 @@ class VotacaoForm(forms.Form):
votos_nao = cleaned_data['votos_nao']
abstencoes = cleaned_data['abstencoes']
qtde_presentes = cleaned_data['total_presentes']
+ qtde_votantes = cleaned_data['total_votantes']
qtde_votos = votos_sim + votos_nao + abstencoes
voto_presidente = cleaned_data['voto_presidente']
- if qtde_presentes and not voto_presidente:
- qtde_presentes -= 1
+ if qtde_votantes and not voto_presidente:
+ qtde_votantes -= 1
- if qtde_presentes and qtde_votos != qtde_presentes:
+ if qtde_votantes and qtde_votos != qtde_votantes:
raise ValidationError(
- 'O total de votos não corresponde com a quantidade de presentes!')
+ 'O total de votos não corresponde com a quantidade de votantes!')
return cleaned_data
@@ -640,7 +634,7 @@ class OradorForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = \
- Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
+ Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
def clean(self):
super(OradorForm, self).clean()
@@ -662,8 +656,8 @@ class OradorForm(ModelForm):
"Já existe orador nesta posição de ordem de pronunciamento"
))
-
return self.cleaned_data
+
class Meta:
model = Orador
exclude = ['sessao_plenaria']
@@ -672,8 +666,12 @@ class OradorForm(ModelForm):
class OradorExpedienteForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+ id_sessao = int(self.initial['id_sessao'])
+ sessao = SessaoPlenaria.objects.get(id=id_sessao)
+ legislatura_vigente = sessao.legislatura
self.fields['parlamentar'].queryset = \
- Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
+ Parlamentar.objects.filter(mandato__legislatura=legislatura_vigente,
+ ativo=True).order_by('nome_parlamentar')
def clean(self):
super(OradorExpedienteForm, self).clean()
@@ -703,8 +701,12 @@ class OradorExpedienteForm(ModelForm):
class OradorOrdemDiaForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+ id_sessao = int(self.initial['id_sessao'])
+ sessao = SessaoPlenaria.objects.get(id=id_sessao)
+ legislatura_vigente = sessao.legislatura
self.fields['parlamentar'].queryset = \
- Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
+ Parlamentar.objects.filter(mandato__legislatura=legislatura_vigente,
+ ativo=True).order_by('nome_parlamentar')
def clean(self):
super(OradorOrdemDiaForm, self).clean()
diff --git a/sapl/sessao/migrations/0041_auto_20190610_1300.py b/sapl/sessao/migrations/0041_auto_20190610_1300.py
new file mode 100644
index 000000000..da25e64b3
--- /dev/null
+++ b/sapl/sessao/migrations/0041_auto_20190610_1300.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-06-10 16:00
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0040_auto_20190523_1130'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='tiposessaoplenaria',
+ name='tipo_numeracao',
+ field=models.PositiveIntegerField(choices=[(1, 'Quinzenal'), (2, 'Mensal'), (10, 'Anual'), (11, 'Sessão Legislativa'), (
+ 12, 'Legislatura'), (99, 'Numeração Única')], default=11, verbose_name='Tipo de Numeração'),
+ ),
+ migrations.AlterField(
+ model_name='tiposessaoplenaria',
+ name='nome',
+ field=models.CharField(
+ max_length=30, verbose_name='Descrição do Tipo'),
+ ),
+ ]
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index 53721499b..8ab65ebfd 100644
--- a/sapl/sessao/models.py
+++ b/sapl/sessao/models.py
@@ -2,7 +2,8 @@ from operator import xor
from django.core.exceptions import ValidationError
from django.db import models
-from django.utils import timezone
+from django.db.models import Q
+from django.utils import timezone, formats
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
@@ -73,10 +74,24 @@ class Bancada(models.Model):
@reversion.register()
class TipoSessaoPlenaria(models.Model):
- nome = models.CharField(max_length=30, verbose_name=_('Tipo'))
+
+ TIPO_NUMERACAO_CHOICES = Choices(
+ (1, 'quizenal', 'Quinzenal'),
+ (2, 'mensal', 'Mensal'),
+ (10, 'anual', 'Anual'),
+ (11, 'sessao_legislativa', 'Sessão Legislativa'),
+ (12, 'legislatura', 'Legislatura'),
+ (99, 'unica', 'Numeração Única'),
+ )
+
+ nome = models.CharField(max_length=30, verbose_name=_('Descrição do Tipo'))
quorum_minimo = models.PositiveIntegerField(
verbose_name=_('Quórum mínimo'))
+ tipo_numeracao = models.PositiveIntegerField(
+ verbose_name=_('Tipo de Numeração'),
+ choices=TIPO_NUMERACAO_CHOICES, default=11)
+
class Meta:
verbose_name = _('Tipo de Sessão Plenária')
verbose_name_plural = _('Tipos de Sessão Plenária')
@@ -85,6 +100,29 @@ class TipoSessaoPlenaria(models.Model):
def __str__(self):
return self.nome
+ def queryset_tipo_numeracao(self, legislatura, sessao_legislativa, data):
+
+ qs = Q(tipo=self)
+ tnc = self.TIPO_NUMERACAO_CHOICES
+
+ if self.tipo_numeracao == tnc.unica:
+ pass
+ elif self.tipo_numeracao == tnc.legislatura:
+ qs &= Q(legislatura=legislatura)
+ elif self.tipo_numeracao == tnc.sessao_legislativa:
+ qs &= Q(sessao_legislativa=sessao_legislativa)
+ elif self.tipo_numeracao == tnc.anual:
+ qs &= Q(data_inicio__year=data.year)
+ elif self.tipo_numeracao in (tnc.mensal, tnc.quizenal):
+ qs &= Q(data_inicio__year=data.year, data_inicio__month=data.month)
+
+ if self.tipo_numeracao == tnc.quizenal:
+ if data.day <= 15:
+ qs &= Q(data_inicio__day__lte=15)
+ else:
+ qs &= Q(data_inicio__day__gt=15)
+ return qs
+
def get_sessao_media_path(instance, subpath, filename):
return './sapl/sessao/%s/%s/%s' % (instance.numero, subpath, filename)
@@ -176,7 +214,34 @@ class SessaoPlenaria(models.Model):
verbose_name_plural = _('Sessões Plenárias')
def __str__(self):
- return _('%(numero)sª Sessão %(tipo_nome)s'
+
+ tnc = self.tipo.TIPO_NUMERACAO_CHOICES
+
+ base = '{}ª {}'.format(self.numero, self.tipo.nome)
+
+ if self.tipo.tipo_numeracao == tnc.quizenal:
+ base += ' da {}ª Quinzena'.format(
+ 1 if self.data_inicio.day > 15 else 2)
+
+ if self.tipo.tipo_numeracao <= tnc.mensal:
+ base += ' do mês de {}'.format(
+ formats.date_format(self.data_inicio, 'F')
+ )
+
+ if self.tipo.tipo_numeracao <= tnc.anual:
+ base += ' de {}'.format(self.data_inicio.year)
+
+ if self.tipo.tipo_numeracao <= tnc.sessao_legislativa:
+ base += ' da {}ª Sessão Legislativa'.format(
+ self.sessao_legislativa.numero)
+
+ if self.tipo.tipo_numeracao <= tnc.legislatura:
+ base += ' da {}ª Legislatura'.format(
+ self.legislatura.numero)
+
+ return base
+
+ """return _('%(numero)sª Sessão %(tipo_nome)s'
' da %(sessao_legislativa_numero)sª Sessão Legislativa'
' da %(legislatura_id)sª Legislatura') % {
@@ -185,6 +250,7 @@ class SessaoPlenaria(models.Model):
'sessao_legislativa_numero': self.sessao_legislativa.numero,
# XXX check if it shouldn't be legislatura.numero
'legislatura_id': self.legislatura.numero}
+ """
def delete(self, using=None, keep_parents=False):
if self.upload_pauta:
diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py
index d5d709967..c570dfde8 100644
--- a/sapl/sessao/urls.py
+++ b/sapl/sessao/urls.py
@@ -2,7 +2,7 @@ from django.conf.urls import include, url
from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
AdicionarVariasMateriasOrdemDia, BancadaCrud,
- CargoBancadaCrud, ExpedienteMateriaCrud,
+ CargoBancadaCrud, ExpedienteMateriaCrud,
ExpedienteView, JustificativaAusenciaCrud,
OcorrenciaSessaoView, MateriaOrdemDiaCrud, OradorOrdemDiaCrud,
MesaView, OradorCrud,
@@ -25,7 +25,7 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
VotacaoNominalView, VotacaoView, abrir_votacao,
atualizar_mesa, insere_parlamentar_composicao,
mudar_ordem_materia_sessao, recuperar_materia,
- recuperar_numero_sessao,
+ recuperar_numero_sessao_view,
remove_parlamentar_composicao,
reordernar_materias_expediente,
reordernar_materias_ordem,
@@ -65,7 +65,7 @@ urlpatterns = [
url(r'^sessao/recuperar-materia/', recuperar_materia),
url(r'^sessao/recuperar-numero-sessao/',
- recuperar_numero_sessao,
+ recuperar_numero_sessao_view,
name='recuperar_numero_sessao_view'
),
url(r'^sessao/sessao-legislativa-legislatura-ajax/',
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
index 93dd7fd9e..295f22543 100755
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -53,7 +53,6 @@ from .models import (Bancada, CargoBancada, CargoMesa,
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
-TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
TipoJustificativaCrud = CrudAux.build(TipoJustificativa, 'tipo_justificativa')
CargoBancadaCrud = CrudAux.build(CargoBancada, '')
TipoResultadoVotacaoCrud = CrudAux.build(
@@ -93,6 +92,7 @@ def reordernar_materias_ordem(request, pk):
return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
+
def renumerar_materias_ordem(request, pk):
ordens = OrdemDia.objects.filter(sessao_plenaria_id=pk)
@@ -103,6 +103,7 @@ def renumerar_materias_ordem(request, pk):
return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
+
def renumerar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(sessao_plenaria_id=pk)
@@ -113,6 +114,7 @@ def renumerar_materias_expediente(request, pk):
return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
+
def verifica_presenca(request, model, spk):
logger = logging.getLogger(__name__)
if not model.objects.filter(sessao_plenaria_id=spk).exists():
@@ -464,6 +466,23 @@ def get_presencas_generic(model, sessao, legislatura):
yield (m.parlamentar, False)
+class TipoExpedienteCrud(CrudAux):
+ model = TipoExpediente
+
+ class DeleteView(CrudAux.DeleteView):
+
+ def delete(self, *args, **kwargs):
+ self.object = self.get_object()
+
+ # Se todas as referências a este tipo forem de conteúdo vazio,
+ # significa que pode ser apagado
+ if self.object.expedientesessao_set.filter(conteudo='').count() == \
+ self.object.expedientesessao_set.all().count():
+ self.object.expedientesessao_set.all().delete()
+
+ return CrudAux.DeleteView.delete(self, *args, **kwargs)
+
+
class MateriaOrdemDiaCrud(MasterDetailCrud):
model = OrdemDia
parent_field = 'sessao_plenaria'
@@ -595,7 +614,6 @@ class OradorCrud(MasterDetailCrud):
class ListView(MasterDetailCrud.ListView):
ordering = ['numero_ordem', 'parlamentar']
-
class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm
@@ -607,7 +625,6 @@ class OradorCrud(MasterDetailCrud):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
-
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
@@ -615,7 +632,7 @@ class OradorCrud(MasterDetailCrud):
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
- initial.update({'numero':self.object.numero_ordem})
+ initial.update({'numero': self.object.numero_ordem})
return initial
@@ -677,11 +694,24 @@ class BancadaCrud(CrudAux):
return reverse('sapl.sessao:bancada_list')
-def recuperar_numero_sessao(request):
+def recuperar_numero_sessao_view(request):
try:
+ tipo = TipoSessaoPlenaria.objects.get(pk=request.GET.get('tipo', '0'))
+ sl = request.GET.get('sessao_legislativa', '0')
+ l = request.GET.get('legislatura', '0')
+ data = request.GET.get('data_inicio', timezone.now())
+
+ if isinstance(data, str):
+ if data:
+ data = timezone.datetime.strptime(data, '%d/%m/%Y').date()
+ else:
+ data = timezone.now().date()
+
sessao = SessaoPlenaria.objects.filter(
- tipo__pk=request.GET['tipo'],
- sessao_legislativa=request.GET['sessao_legislativa']).last()
+ tipo.queryset_tipo_numeracao(
+ l, sl, data
+ )).last()
+
except ObjectDoesNotExist:
numero = 1
else:
@@ -1066,7 +1096,6 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView):
return self.get(self, request, args, kwargs)
-
class MesaView(FormMixin, DetailView):
template_name = 'sessao/mesa.html'
form_class = MesaForm
@@ -1341,7 +1370,7 @@ def get_identificação_basica(sessao_plenaria):
_('Encerramento: %(encerramento)s %(hora_fim)s') % {
'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim}
],
- 'sessaoplenaria': sessao_plenaria})
+ 'sessaoplenaria': sessao_plenaria})
def get_conteudo_multimidia(sessao_plenaria):
@@ -1360,7 +1389,8 @@ def get_conteudo_multimidia(sessao_plenaria):
def get_mesa_diretora(sessao_plenaria):
- mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria).order_by('cargo_id')
+ mesa = IntegranteMesa.objects.filter(
+ sessao_plenaria=sessao_plenaria).order_by('cargo_id')
integrantes = [{'parlamentar': m.parlamentar,
'cargo': m.cargo} for m in mesa]
return {'mesa': integrantes}
@@ -1369,8 +1399,8 @@ def get_mesa_diretora(sessao_plenaria):
def get_presenca_sessao(sessao_plenaria):
parlamentares_sessao = [p.parlamentar for p in SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=sessao_plenaria.id
- ).order_by('parlamentar__nome_parlamentar')]
+ sessao_plenaria_id=sessao_plenaria.id
+ ).order_by('parlamentar__nome_parlamentar')]
ausentes_sessao = JustificativaAusencia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
@@ -1404,7 +1434,8 @@ def get_materias_expediente(sessao_plenaria):
numero = m.numero_ordem
tramitacao = ''
- tramitacoes = Tramitacao.objects.filter(materia=m.materia).order_by('-pk')
+ tramitacoes = Tramitacao.objects.filter(
+ materia=m.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
@@ -1466,8 +1497,8 @@ def get_oradores_expediente(sessao_plenaria):
def get_presenca_ordem_do_dia(sessao_plenaria):
parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=sessao_plenaria.id
- ).order_by('parlamentar__nome_parlamentar')]
+ sessao_plenaria_id=sessao_plenaria.id
+ ).order_by('parlamentar__nome_parlamentar')]
return {'presenca_ordem': parlamentares_ordem}
@@ -1480,13 +1511,14 @@ def get_assinaturas(sessao_plenaria):
'')]
parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=sessao_plenaria.id
- ).order_by('parlamentar__nome_parlamentar')]
+ sessao_plenaria_id=sessao_plenaria.id
+ ).order_by('parlamentar__nome_parlamentar')]
parlamentares_mesa = [m['parlamentar'] for m in mesa_dia]
# filtra parlamentares retirando os que sao da mesa
- parlamentares_ordem = [p for p in parlamentares_ordem if p not in parlamentares_mesa]
+ parlamentares_ordem = [
+ p for p in parlamentares_ordem if p not in parlamentares_mesa]
context = {}
config_assinatura_ata = AppsAppConfig.attr('assinatura_ata')
@@ -1517,7 +1549,8 @@ def get_materias_ordem_do_dia(sessao_plenaria):
numero = o.numero_ordem
tramitacao = ''
- tramitacoes = Tramitacao.objects.filter(materia=o.materia).order_by('-pk')
+ tramitacoes = Tramitacao.objects.filter(
+ materia=o.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
@@ -1600,7 +1633,7 @@ def get_oradores_ordemdia(sessao_plenaria):
observacao = orador.observacao
parlamentar = Parlamentar.objects.get(
id=orador.parlamentar_id
- )
+ )
o = {
'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
@@ -1610,9 +1643,9 @@ def get_oradores_ordemdia(sessao_plenaria):
oradores.append(o)
context = {'oradores_ordemdia': oradores}
- return context
+ return context
+
-
def get_oradores_explicações_pessoais(sessao_plenaria):
oradores_explicacoes = []
for orador in Orador.objects.filter(
@@ -1729,7 +1762,7 @@ class ResumoView(DetailView):
# =====================================================================
# Oradores Ordem do Dia
context.update(get_oradores_ordemdia(self.object))
- # =====================================================================
+ # =====================================================================
# Oradores nas Explicações Pessoais
context.update(get_oradores_explicações_pessoais(self.object))
# =====================================================================
@@ -2051,13 +2084,24 @@ class VotacaoView(SessaoPermissionMixin):
ordem_id = kwargs['oid']
ordem = OrdemDia.objects.get(id=ordem_id)
- qtde_presentes = PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=self.object.id).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in PresencaOrdemDia.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
materia = {'materia': ordem.materia, 'ementa': ordem.materia.ementa}
context.update({'votacao_titulo': titulo,
'materia': materia,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
return self.render_to_response(context)
@@ -2077,13 +2121,24 @@ class VotacaoView(SessaoPermissionMixin):
ordem_id = kwargs['oid']
ordem = OrdemDia.objects.get(id=ordem_id)
- qtde_presentes = PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=self.object.id).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in PresencaOrdemDia.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
materia = {'materia': ordem.materia, 'ementa': ordem.materia.ementa}
context.update({'votacao_titulo': titulo,
'materia': materia,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
context.update({'form': form})
# ====================================================
@@ -2096,21 +2151,19 @@ class VotacaoView(SessaoPermissionMixin):
materia_id = kwargs['mid']
ordem_id = kwargs['oid']
- qtde_presentes = PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=self.object.id).count()
qtde_votos = (int(request.POST['votos_sim']) +
int(request.POST['votos_nao']) +
int(request.POST['abstencoes']))
if (int(request.POST['voto_presidente']) == 0):
- qtde_presentes -= 1
+ qtde_ativos -= 1
- if (qtde_votos > qtde_presentes or qtde_votos < qtde_presentes):
+ if qtde_votos != qtde_ativos:
msg = _(
- 'O total de votos não corresponde com a quantidade de presentes!')
+ 'O total de votos não corresponde com a quantidade de votantes!')
messages.add_message(request, messages.ERROR, msg)
return self.render_to_response(context)
- elif (qtde_presentes == qtde_votos):
+ else:
try:
votacao = RegistroVotacao()
votacao.numero_votos_sim = int(request.POST['votos_sim'])
@@ -2755,14 +2808,25 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
expediente_id = kwargs['oid']
expediente = ExpedienteMateria.objects.get(id=expediente_id)
- qtde_presentes = SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=self.object.id).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in SessaoPlenariaPresenca.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presentes_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presentes_ativos)
materia = {'materia': expediente.materia,
'ementa': expediente.materia.ementa}
context.update({'votacao_titulo': titulo,
'materia': materia,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
return self.render_to_response(context)
@@ -2782,14 +2846,25 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
expediente_id = kwargs['oid']
expediente = ExpedienteMateria.objects.get(id=expediente_id)
- qtde_presentes = SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=self.object.id).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in SessaoPlenariaPresenca.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presentes_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presentes_ativos)
materia = {'materia': expediente.materia,
'ementa': expediente.materia.ementa}
context.update({'votacao_titulo': titulo,
'materia': materia,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
context.update({'form': form})
# ====================================================
@@ -2802,17 +2877,17 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
materia_id = kwargs['mid']
expediente_id = kwargs['oid']
- qtde_presentes = SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=self.object.id).count()
qtde_votos = (int(request.POST['votos_sim']) +
int(request.POST['votos_nao']) +
int(request.POST['abstencoes']))
if (int(request.POST['voto_presidente']) == 0):
- qtde_presentes -= 1
+ qtde_ativos -= 1
- if qtde_votos != qtde_presentes:
- form._errors["total_votos"] = ErrorList([u""])
+ if qtde_votos != qtde_ativos:
+ msg = _(
+ 'O total de votos não corresponde com a quantidade de votantes!')
+ messages.add_message(request, messages.ERROR, msg)
return self.render_to_response(context)
else:
try:
@@ -3561,17 +3636,41 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
if request.POST['origem'] == 'ordem':
ordens = OrdemDia.objects.filter(
id__in=request.POST.getlist('marcadas_1'))
- qtde_presentes = PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=self.kwargs['pk']).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in PresencaOrdemDia.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
+
context.update({'ordens': ordens,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
else:
expedientes = ExpedienteMateria.objects.filter(
id__in=request.POST.getlist('marcadas_1'))
- qtde_presentes = SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=self.kwargs['pk']).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in SessaoPlenariaPresenca.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
+
context.update({'expedientes': expedientes,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
if 'salvar-votacao' in request.POST:
form = VotacaoForm(request.POST)
@@ -3696,17 +3795,41 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
if self.request.POST['origem'] == 'ordem':
ordens = OrdemDia.objects.filter(
id__in=self.request.POST.getlist('ordens'))
- qtde_presentes = PresencaOrdemDia.objects.filter(
- sessao_plenaria_id=self.kwargs['pk']).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in PresencaOrdemDia.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
+
context.update({'ordens': ordens,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
elif self.request.POST['origem'] == 'expediente':
expedientes = ExpedienteMateria.objects.filter(
id__in=self.request.POST.getlist('expedientes'))
- qtde_presentes = SessaoPlenariaPresenca.objects.filter(
- sessao_plenaria_id=self.kwargs['pk']).count()
+
+ presentes_id = [
+ presente.parlamentar.id for presente in SessaoPlenariaPresenca.objects.filter(
+ sessao_plenaria_id=self.kwargs['pk']
+ )
+ ]
+ qtde_presentes = len(presentes_id)
+
+ presenca_ativos = Parlamentar.objects.filter(
+ id__in=presentes_id, ativo=True
+ )
+ qtde_ativos = len(presenca_ativos)
+
context.update({'expedientes': expedientes,
- 'total_presentes': qtde_presentes})
+ 'total_presentes': qtde_presentes,
+ 'total_votantes': qtde_ativos})
context.update({'resultado_votacao': TipoResultadoVotacao.objects.all(),
'form': form,
diff --git a/sapl/settings.py b/sapl/settings.py
index d5d98c968..1167d33f3 100644
--- a/sapl/settings.py
+++ b/sapl/settings.py
@@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next='
-SAPL_VERSION = '3.1.157-RC5'
+SAPL_VERSION = '3.1.158'
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index 71a4fc4ee..0df0d6dee 100644
--- a/sapl/templates/base.html
+++ b/sapl/templates/base.html
@@ -179,7 +179,7 @@
Desenvolvido pelo Interlegis em software livre e aberto.
- Release: 3.1.157-RC5
+ Release: 3.1.158
@@ -232,11 +232,9 @@
{% block webpack_loader_chunks_js %}
{% endblock webpack_loader_chunks_js %}
- {% block extra_js %}{% endblock %}
+ {% block extra_js %}{% endblock extra_js %}
{% endblock foot_js %}
-