diff --git a/docker-compose.yml b/docker-compose.yml
index cb57ad36e..6c668d80f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,8 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
- image: interlegis/sapl:3.1.158
-# build: .
+ image: interlegis/sapl:3.1.159
restart: always
environment:
ADMIN_PASSWORD: interlegis
@@ -24,27 +23,11 @@ sapl:
EMAIL_HOST_USER: usuariosmtp
EMAIL_SEND_USER: usuariosmtp
EMAIL_HOST_PASSWORD: senhasmtp
-# USE_SOLR: 'True'
-# SOLR_COLLECTION: sapl
-# SOLR_URL: http://saplsolr:8983
TZ: America/Sao_Paulo
volumes:
- sapl_data:/var/interlegis/sapl/data
- sapl_media:/var/interlegis/sapl/media
links:
- sapldb
-# - saplsolr
ports:
- - "80:80"
-
-#saplsolr:
-# image: solr:7.4-alpine
-# restart: always
-# command: bin/solr start -c -f
-# volumes:
-# - solr_data:/opt/solr/server/solr
-# - solr_configsets:/opt/solr/server/solr/configsets
-# ports:
-# - "8983:8983"
-
-
+ - "80:80"
\ No newline at end of file
diff --git a/release.sh b/release.sh
index 833e74cdf..5bfd27fef 100755
--- a/release.sh
+++ b/release.sh
@@ -1,4 +1,4 @@
-#/bin/bash
+#!/bin/bash
##
## Versioning info: [major].[minor].[patch][-RC[num]], example: 3.1.159, 3.1.159-RC1
@@ -72,19 +72,21 @@ function commit_and_push {
git commit -m "Release: $FINAL_VERSION"
git tag $FINAL_VERSION
- echo "sending to github..."
- git push origin
- git push origin $FINAL_VERSION
+ echo "Para enviar pro github execute..."
+ echo "git push origin 3.1.x"
+ echo "git push origin "$FINAL_VERSION
echo "done."
}
case "$1" in
--latest)
+ git fetch
echo $LATEST_VERSION
exit 0
;;
--major)
+ git fetch
set_major_version
echo "generating major release: "$FINAL_VERSION
# git tag $FINAL_VERSION
@@ -93,6 +95,7 @@ case "$1" in
exit 0
;;
--rc)
+ git fetch
set_rc_version
echo "generating release candidate: "$FINAL_VERSION
# git tag $FINAL_VERSION
@@ -100,10 +103,6 @@ case "$1" in
commit_and_push
exit 0
;;
- --undo)
- git tag -d $LATEST_VERSION
- exit 0
- ;;
--top)
git tag | sort --version-sort | tail "-$2"
exit 0
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 05789db35..6000f1575 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -15,6 +15,7 @@ django-extensions==2.1.4
django-image-cropping==1.2
django-webpack-loader==0.6.0
drf-yasg==1.13.0
+ruamel.yaml>=0.15.34,<0.16.0
easy-thumbnails==2.5
python-decouple==3.1
psycopg2-binary==2.7.6.1
diff --git a/sapl/audiencia/forms.py b/sapl/audiencia/forms.py
index 56f4d1285..d62900df6 100755
--- a/sapl/audiencia/forms.py
+++ b/sapl/audiencia/forms.py
@@ -1,6 +1,7 @@
import logging
from django import forms
+from sapl.settings import MAX_DOC_UPLOAD_SIZE
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
@@ -106,8 +107,6 @@ class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
else:
cleaned_data['numero'] = 1
-
-
if self.cleaned_data['hora_inicio'] and self.cleaned_data['hora_fim']:
if (self.cleaned_data['hora_fim'] <
self.cleaned_data['hora_inicio']):
@@ -116,6 +115,22 @@ class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
self.logger.error('Hora de fim anterior à hora de início.')
raise ValidationError(msg)
+ upload_pauta = self.cleaned_data.get('upload_pauta', False)
+ upload_ata = self.cleaned_data.get('upload_ata', False)
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_pauta and upload_pauta.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Pauta da Audiência Pública deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_pauta.size/1024)/1024))
+
+ if upload_ata and upload_ata.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Ata da Audiência Pública deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_ata.size/1024)/1024))
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo da Audiência Pública deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
return cleaned_data
@@ -140,3 +155,17 @@ class AnexoAudienciaPublicaForm(forms.ModelForm):
row1, row2))
super(AnexoAudienciaPublicaForm, self).__init__(
*args, **kwargs)
+
+ def clean(self):
+ super(AnexoAudienciaPublicaForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ arquivo = self.cleaned_data.get('arquivo', False)
+
+ if arquivo and arquivo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (arquivo.size/1024)/1024))
+
+ return self.cleaned_data
diff --git a/sapl/audiencia/tests/test_audiencia.py b/sapl/audiencia/tests/test_audiencia.py
index 5640b3d0d..b7c2e26a8 100644
--- a/sapl/audiencia/tests/test_audiencia.py
+++ b/sapl/audiencia/tests/test_audiencia.py
@@ -1,11 +1,62 @@
import pytest
-from django.utils.translation import ugettext as _
+import datetime
from model_mommy import mommy
+from django.utils.translation import ugettext as _
from sapl.audiencia import forms
-from sapl.audiencia.models import TipoAudienciaPublica
+from sapl.audiencia.models import AnexoAudienciaPublica
+from sapl.audiencia.models import TipoAudienciaPublica, AudienciaPublica
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_audiencia_publica_model():
+ mommy.make(TipoAudienciaPublica,
+ nome='Teste_Nome_Tipo_Audiencia_Publica',
+ tipo='A')
+
+ tipo_audiencia_publica = TipoAudienciaPublica.objects.first()
+ assert tipo_audiencia_publica.nome == 'Teste_Nome_Tipo_Audiencia_Publica'
+ assert tipo_audiencia_publica.tipo == 'A'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_audiencia_publica_model():
+ mommy.make(AudienciaPublica,
+ numero=1,
+ nome='Teste_Nome_Audiencia_Publica',
+ tema='Teste_Tema_Audiencia_Publica',
+ data='2016-03-21',
+ hora_inicio='16:03')
+
+ audiencia_publica = AudienciaPublica.objects.first()
+
+ data = '2016-03-21'
+ teste_data = datetime.datetime.strptime(data, "%Y-%m-%d").date()
+
+ assert audiencia_publica.numero == 1
+ assert audiencia_publica.nome == 'Teste_Nome_Audiencia_Publica'
+ assert audiencia_publica.tema == 'Teste_Tema_Audiencia_Publica'
+ assert audiencia_publica.data == teste_data
+ assert audiencia_publica.hora_inicio == '16:03'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_anexo_audiencia_publica_model():
+ audiencia = mommy.make(AudienciaPublica,
+ numero=2,
+ nome='Nome_Audiencia_Publica',
+ tema='Tema_Audiencia_Publica',
+ data='2017-04-22',
+ hora_inicio='17:04')
+
+ mommy.make(AnexoAudienciaPublica,
+ audiencia=audiencia)
+
+ anexo_audiencia_publica = AnexoAudienciaPublica.objects.first()
+ assert anexo_audiencia_publica.audiencia == audiencia
+
+
@pytest.mark.django_db(transaction=False)
def test_valida_campos_obrigatorios_audiencia_form():
form = forms.AudienciaForm(data={})
@@ -35,7 +86,5 @@ def test_audiencia_form_hora_invalida():
'data': '2016-10-01',
'hora_inicio': '10:00',
'hora_fim': '9:00',
- })
+ })
assert not form.is_valid()
-
-
\ No newline at end of file
diff --git a/sapl/base/forms.py b/sapl/base/forms.py
index d78f4a5e4..d9594511b 100644
--- a/sapl/base/forms.py
+++ b/sapl/base/forms.py
@@ -2,7 +2,6 @@ import logging
import os
from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton
-from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row
from django import forms
from django.conf import settings
@@ -26,6 +25,7 @@ from sapl.comissoes.models import Reuniao, Comissao
from sapl.comissoes.models import Reuniao, Comissao
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row)
+from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.materia.models import (
MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
@@ -39,6 +39,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
models_with_gr_for_model, qs_override_django_filter,
choice_anos_com_normas, choice_anos_com_materias,
FilterOverridesMetaMixin, FileFieldCheckMixin)
+
from .models import AppConfig, CasaLegislativa
@@ -65,11 +66,6 @@ def get_roles():
class UsuarioCreateForm(ModelForm):
logger = logging.getLogger(__name__)
- username = forms.CharField(
- required=True,
- label="Nome de usuário",
- max_length=30
- )
firstname = forms.CharField(
required=True,
label="Nome",
@@ -108,8 +104,11 @@ class UsuarioCreateForm(ModelForm):
class Meta:
model = get_user_model()
- fields = ['username', 'firstname', 'lastname', 'email',
- 'password1', 'password2', 'user_active', 'roles']
+ fields = [
+ get_user_model().USERNAME_FIELD, 'firstname', 'lastname',
+ 'password1', 'password2', 'user_active', 'roles'
+ ] + (['email']
+ if get_user_model().USERNAME_FIELD != 'email' else [])
def clean(self):
super().clean()
@@ -151,9 +150,9 @@ class UsuarioCreateForm(ModelForm):
class UsuarioFilterSet(django_filters.FilterSet):
-
+
username = django_filters.CharFilter(
- label=_('Nome de Usuário'),
+ label=_('Nome de Usuário'),
lookup_expr='icontains')
class Meta:
@@ -164,7 +163,7 @@ class UsuarioFilterSet(django_filters.FilterSet):
super(UsuarioFilterSet, self).__init__(*args, **kwargs)
row0 = to_row([('username', 12)])
-
+
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
@@ -190,24 +189,30 @@ class UsuarioEditForm(ModelForm):
class Meta:
model = get_user_model()
- fields = ['email', 'password1', 'password2', 'user_active', 'roles']
+ fields = [
+ get_user_model().USERNAME_FIELD, 'password1',
+ 'password2', 'user_active', 'roles'
+ ] + (['email']
+ if get_user_model().USERNAME_FIELD != 'email' else [])
def __init__(self, *args, **kwargs):
super(UsuarioEditForm, self).__init__(*args, **kwargs)
- row1 = to_row([('email', 6),
+ row1 = to_row([('username', 12)])
+ row2 = to_row([('email', 6),
('user_active', 6)])
- row2 = to_row(
+ row3 = to_row(
[('password1', 6),
('password2', 6)])
- row3 = to_row([(form_actions(label='Salvar Alterações'), 6)])
+ row4 = to_row([(form_actions(label='Salvar Alterações'), 6)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
row1,
row2,
+ row3,
'roles',
form_actions(label='Salvar Alterações'))
@@ -867,22 +872,36 @@ class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = SessaoPlenaria
- fields = ['data_inicio']
+ fields = ['data_inicio',
+ 'sessao_legislativa',
+ 'tipo',
+ 'legislatura']
def __init__(self, *args, **kwargs):
super(RelatorioPresencaSessaoFilterSet, self).__init__(
*args, **kwargs)
+ self.form.fields['exibir_ordem_dia'] = forms.BooleanField(required=False,
+ label='Exibir presença das Ordens do Dia')
+ self.form.initial['exibir_ordem_dia'] = True
+
self.filters['data_inicio'].label = 'Período (Inicial - Final)'
- self.form.fields['data_inicio'].required = True
+
+ tipo_sessao_ordinaria = self.filters['tipo'].queryset.filter(nome='Ordinária')
+ if tipo_sessao_ordinaria:
+ self.form.initial['tipo'] = tipo_sessao_ordinaria.first()
row1 = to_row([('data_inicio', 12)])
+ row2 = to_row([('legislatura', 4),
+ ('sessao_legislativa', 4),
+ ('tipo', 4)])
+ row3 = to_row([('exibir_ordem_dia', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Presença dos parlamentares nas sessões plenárias'),
- row1, form_actions(label='Pesquisar'))
+ row1, row2, row3, form_actions(label='Pesquisar'))
)
@property
@@ -900,7 +919,7 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'tramitacao__status', 'tramitacao__data_tramitacao',
- 'tramitacao__unidade_tramitacao_local', 'tramitacao__unidade_tramitacao_destino']
+ 'tramitacao__unidade_tramitacao_local', 'tramitacao__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
super(RelatorioHistoricoTramitacaoFilterSet, self).__init__(
@@ -908,8 +927,10 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['tramitacao__status'].label = _('Status')
- self.filters['tramitacao__unidade_tramitacao_local'].label = _('Unidade Local (Origem)')
- self.filters['tramitacao__unidade_tramitacao_destino'].label = _('Unidade Destino')
+ self.filters['tramitacao__unidade_tramitacao_local'].label = _(
+ 'Unidade Local (Origem)')
+ self.filters['tramitacao__unidade_tramitacao_destino'].label = _(
+ 'Unidade Destino')
row1 = to_row([('tramitacao__data_tramitacao', 12)])
row2 = to_row([('tramitacao__unidade_tramitacao_local', 6),
@@ -927,7 +948,6 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
)
-
class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
@property
@@ -946,7 +966,8 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
- self.filters['tramitacao__unidade_tramitacao_local'].label = 'Unidade Local (Origem)'
+ self.filters[
+ 'tramitacao__unidade_tramitacao_local'].label = 'Unidade Local (Origem)'
self.filters['tramitacao__unidade_tramitacao_destino'].label = 'Unidade Destino'
self.filters['tramitacao__status'].label = 'Status de tramitação'
@@ -960,7 +981,7 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
- Fieldset(_('Tramitações por fim de prazo'),
+ Fieldset(_('Tramitações'),
row1, row2, row3,
form_actions(label='Pesquisar'))
)
@@ -1409,7 +1430,7 @@ class PartidoForm(FileFieldCheckMixin, ModelForm):
[('sigla', 2),
('nome', 6),
('data_criacao', 2),
- ('data_extincao', 2),])
+ ('data_extincao', 2), ])
row2 = to_row([('observacao', 12)])
row3 = to_row([('logo_partido', 12)])
@@ -1424,10 +1445,11 @@ class PartidoForm(FileFieldCheckMixin, ModelForm):
if not self.is_valid():
return cleaned_data
-
+
if cleaned_data['data_criacao'] and cleaned_data['data_extincao']:
if cleaned_data['data_criacao'] > cleaned_data['data_extincao']:
- raise ValidationError("Certifique-se de que a data de criação seja anterior à data de extinção.")
+ raise ValidationError(
+ "Certifique-se de que a data de criação seja anterior à data de extinção.")
return cleaned_data
@@ -1441,9 +1463,9 @@ class RelatorioHistoricoTramitacaoAdmFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
- fields = ['tipo', 'tramitacaoadministrativo__status',
+ fields = ['tipo', 'tramitacaoadministrativo__status',
'tramitacaoadministrativo__data_tramitacao',
- 'tramitacaoadministrativo__unidade_tramitacao_local',
+ 'tramitacaoadministrativo__unidade_tramitacao_local',
'tramitacaoadministrativo__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
@@ -1452,8 +1474,10 @@ class RelatorioHistoricoTramitacaoAdmFilterSet(django_filters.FilterSet):
self.filters['tipo'].label = 'Tipo de Documento'
self.filters['tramitacaoadministrativo__status'].label = _('Status')
- self.filters['tramitacaoadministrativo__unidade_tramitacao_local'].label = _('Unidade Local (Origem)')
- self.filters['tramitacaoadministrativo__unidade_tramitacao_destino'].label = _('Unidade Destino')
+ self.filters['tramitacaoadministrativo__unidade_tramitacao_local'].label = _(
+ 'Unidade Local (Origem)')
+ self.filters['tramitacaoadministrativo__unidade_tramitacao_destino'].label = _(
+ 'Unidade Destino')
row1 = to_row([('tramitacaoadministrativo__data_tramitacao', 12)])
row2 = to_row([('tramitacaoadministrativo__unidade_tramitacao_local', 6),
diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py
index 26fd54f4d..12192ab6f 100644
--- a/sapl/base/templatetags/common_tags.py
+++ b/sapl/base/templatetags/common_tags.py
@@ -223,8 +223,34 @@ def audio_url(value):
@register.filter
-def video_url(value):
- return True if url(value) and value.endswith("mp4") else False
+def is_video_url(value):
+ video_extensions = ["mp4", "ogg", "webm", "3gp", "ogv"]
+ has_ext = any([value.endswith(i) for i in video_extensions])
+ return url(value) and has_ext
+
+
+@register.filter
+def youtube_url(value):
+ # Test if YouTube video
+ # tested on https://pythex.org/
+ value = value.lower()
+ youtube_pattern = "^((https?://)?(www\.)?youtube\.com\/watch\?v=)"
+ r = re.findall(youtube_pattern, value)
+ return True if r else False
+
+@register.filter
+def facebook_url(value):
+ value = value.lower()
+ facebook_pattern = "^((https?://)?((www|pt-br)\.)?facebook\.com(\/.+)?\/videos(\/.*)?)"
+ r = re.findall(facebook_pattern, value)
+ return True if r else False
+
+@register.filter
+def youtube_id(value):
+ from urllib.parse import urlparse, parse_qs
+ u_pars = urlparse(value)
+ quer_v = parse_qs(u_pars.query).get('v')[0]
+ return quer_v
@register.filter
@@ -272,12 +298,20 @@ def urldetail(obj):
@register.filter
def filiacao_data_filter(parlamentar, data_inicio):
- return filiacao_data(parlamentar, data_inicio)
+ try:
+ filiacao = filiacao_data(parlamentar, data_inicio)
+ except Exception:
+ filiacao = ''
+ return filiacao
@register.filter
def filiacao_intervalo_filter(parlamentar, date_range):
- return filiacao_data(parlamentar, date_range[0], date_range[1])
+ try:
+ filiacao = filiacao_data(parlamentar, date_range[0], date_range[1])
+ except Exception:
+ filiacao = ''
+ return filiacao
@register.simple_tag
diff --git a/sapl/base/tests/test_base.py b/sapl/base/tests/test_base.py
new file mode 100644
index 000000000..296a241af
--- /dev/null
+++ b/sapl/base/tests/test_base.py
@@ -0,0 +1,24 @@
+import pytest
+from model_mommy import mommy
+
+from sapl.base.models import CasaLegislativa
+
+
+@pytest.mark.django_db(transaction=False)
+def test_casa_legislativa_model():
+ mommy.make(CasaLegislativa,
+ nome='Teste_Nome_Casa_Legislativa',
+ sigla='TSCL',
+ endereco='Teste_Endereço_Casa_Legislativa',
+ cep='12345678',
+ municipio='Teste_Municipio_Casa_Legislativa',
+ uf='DF')
+
+ casa_legislativa = CasaLegislativa.objects.first()
+
+ assert casa_legislativa.nome == 'Teste_Nome_Casa_Legislativa'
+ assert casa_legislativa.sigla == 'TSCL'
+ assert casa_legislativa.endereco == 'Teste_Endereço_Casa_Legislativa'
+ assert casa_legislativa.cep == '12345678'
+ assert casa_legislativa.municipio == 'Teste_Municipio_Casa_Legislativa'
+ assert casa_legislativa.uf == 'DF'
diff --git a/sapl/base/tests/test_view_base.py b/sapl/base/tests/test_view_base.py
index fc61ac160..6655317b3 100644
--- a/sapl/base/tests/test_view_base.py
+++ b/sapl/base/tests/test_view_base.py
@@ -1,6 +1,635 @@
import pytest
+from model_mommy import mommy
+import datetime
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
+from model_mommy import mommy
+
+from sapl.base.models import Autor, TipoAutor
+from sapl.comissoes.models import Comissao, TipoComissao
+from sapl.sessao.models import Bancada
+from sapl.protocoloadm.models import (Protocolo, DocumentoAdministrativo,
+ TipoDocumentoAdministrativo, Anexado)
+from sapl.materia.models import (TipoMateriaLegislativa, RegimeTramitacao,
+ MateriaLegislativa, Anexada)
+from sapl.parlamentares.models import (Parlamentar, Partido, Filiacao,
+ Legislatura, Mandato)
+
+from sapl.base.views import (protocolos_duplicados, protocolos_com_materias,
+ materias_protocolo_inexistente,
+ mandato_sem_data_inicio, parlamentares_duplicados,
+ parlamentares_mandatos_intersecao,
+ parlamentares_filiacoes_intersecao,
+ autores_duplicados,
+ bancada_comissao_autor_externo, anexados_ciclicos)
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_protocolos_duplicados():
+ mommy.make(
+ Protocolo,
+ numero=15,
+ ano=2031
+ )
+ mommy.make(
+ Protocolo,
+ numero=15,
+ ano=2031
+ )
+ mommy.make(
+ Protocolo,
+ numero=33,
+ ano=2033
+ )
+
+ lista_protocolos_duplicados = protocolos_duplicados()
+
+ assert len(lista_protocolos_duplicados) == 1
+ assert lista_protocolos_duplicados[0][1] == 2
+ assert lista_protocolos_duplicados[0][0].numero == 15
+ assert lista_protocolos_duplicados[0][0].ano == 2031
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_protocolos_com_materias():
+ mommy.make(
+ Protocolo,
+ numero=15,
+ ano=2035
+ )
+ mommy.make(
+ Protocolo,
+ numero=33,
+ ano=2035
+ )
+
+ tipo_materia = mommy.make(
+ TipoMateriaLegislativa,
+ descricao="Tipo_Materia_Teste"
+ )
+ regime_tramitacao = mommy.make(
+ RegimeTramitacao,
+ descricao="Regime_Tramitacao_Teste"
+ )
+ mommy.make(
+ MateriaLegislativa,
+ numero=16,
+ ano=2035,
+ data_apresentacao='2035-06-02',
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia,
+ numero_protocolo=15
+ )
+ mommy.make(
+ MateriaLegislativa,
+ numero=17,
+ ano=2035,
+ data_apresentacao='2035-06-05',
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia,
+ numero_protocolo=15
+ )
+
+ lista_protocolos_com_materias = protocolos_com_materias()
+
+ assert len(lista_protocolos_com_materias) == 1
+ assert lista_protocolos_com_materias[0][1] == 2
+ assert lista_protocolos_com_materias[0][0].numero_protocolo == 15
+ assert lista_protocolos_com_materias[0][0].ano == 2035
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_materias_protocolo_inexistente():
+ protocolo_a = mommy.make(
+ Protocolo,
+ numero=15,
+ ano=2031
+ )
+
+ tipo_materia = mommy.make(
+ TipoMateriaLegislativa,
+ descricao="Tipo_Materia_Teste"
+ )
+ regime_tramitacao = mommy.make(
+ RegimeTramitacao,
+ descricao="Regime_Tramitacao_Teste"
+ )
+ mommy.make(
+ MateriaLegislativa,
+ numero=16,
+ ano=2031,
+ data_apresentacao='2031-06-02',
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia,
+ numero_protocolo=15
+ )
+ materia = mommy.make(
+ MateriaLegislativa,
+ numero=17,
+ ano=2031,
+ data_apresentacao='2031-06-02',
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia,
+ numero_protocolo=16
+ )
+
+ lista_materias_protocolo_inexistente = materias_protocolo_inexistente()
+
+ assert len(lista_materias_protocolo_inexistente) == 1
+ assert lista_materias_protocolo_inexistente == [(materia, 2031, 16)]
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_mandatos_sem_data_inicio():
+ parlamentar = mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste",
+ nome_parlamentar="Nome_Parlamentar_Teste",
+ sexo='M'
+ )
+ legislatura = mommy.make(
+ Legislatura,
+ numero=1,
+ data_inicio='2015-05-02',
+ data_fim='2024-02-04',
+ data_eleicao='2015-02-05'
+ )
+
+ mandato_a = mommy.make(
+ Mandato,
+ parlamentar=parlamentar,
+ legislatura=legislatura
+ )
+ mommy.make(
+ Mandato,
+ parlamentar=parlamentar,
+ legislatura=legislatura,
+ data_inicio_mandato='2015-05-27'
+ )
+
+ lista_mandatos_sem_data_inicio = mandato_sem_data_inicio()
+
+ assert len(lista_mandatos_sem_data_inicio) == 1
+ assert lista_mandatos_sem_data_inicio[0] == mandato_a
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_parlamentares_duplicados():
+ mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste",
+ nome_parlamentar="Nome_Parlamentar_Teste",
+ sexo='M'
+ )
+ mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste",
+ nome_parlamentar="Nome_Parlamentar_Teste",
+ sexo='M'
+ )
+ mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste-1",
+ nome_parlamentar="Nome_Parlamentar_Teste-1",
+ sexo='M'
+ )
+
+ lista_dict_values_parlamentares_duplicados = parlamentares_duplicados()
+ parlamentar_duplicado = list(
+ lista_dict_values_parlamentares_duplicados[0]
+ )
+ parlamentar_duplicado.sort(key=str)
+
+ assert len(lista_dict_values_parlamentares_duplicados) == 1
+ assert parlamentar_duplicado == [2, "Nome_Parlamentar_Teste"]
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_parlamentares_mandatos_intersecao():
+ legislatura = mommy.make(
+ Legislatura,
+ numero=1,
+ data_inicio='2017-07-04',
+ data_fim='2170-05-01',
+ data_eleicao='2017-04-07'
+ )
+ parlamentar_a = mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste",
+ nome_parlamentar="Nome_Parlamentar_Teste",
+ sexo='M'
+ )
+ parlamentar_b = mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste-1",
+ nome_parlamentar="Nome_Parlamentar_Teste-1",
+ sexo='M'
+ )
+
+ mandato_a = mommy.make(
+ Mandato,
+ parlamentar=parlamentar_a,
+ legislatura=legislatura,
+ data_inicio_mandato='2017-07-08',
+ data_fim_mandato='2018-01-07'
+ )
+ mandato_b = mommy.make(
+ Mandato,
+ parlamentar=parlamentar_a,
+ legislatura=legislatura,
+ data_inicio_mandato='2017-07-09'
+ )
+ mommy.make(
+ Mandato,
+ parlamentar=parlamentar_b,
+ legislatura=legislatura,
+ data_inicio_mandato='2017-11-17',
+ data_fim_mandato='2018-08-02'
+ )
+ mommy.make(
+ Mandato,
+ parlamentar=parlamentar_b,
+ legislatura=legislatura,
+ data_inicio_mandato='2018-08-03'
+ )
+
+ lista_parlamentares = parlamentares_mandatos_intersecao()
+
+ assert len(lista_parlamentares) == 1
+ assert lista_parlamentares == [(parlamentar_a, mandato_a, mandato_b)]
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_parlamentares_filiacoes_intersecao():
+ partido = mommy.make(
+ Partido,
+ sigla="ST",
+ nome="Nome_Partido_Teste"
+ )
+ parlamentar_a = mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste",
+ nome_parlamentar="Nome_Parlamentar_Teste",
+ sexo='M'
+ )
+ parlamentar_b = mommy.make(
+ Parlamentar,
+ nome_completo="Nome_Completo_Parlamentar_Teste-1",
+ nome_parlamentar="Nome_Parlamentar_Teste-1",
+ sexo='M'
+ )
+
+ filiacao_a = mommy.make(
+ Filiacao,
+ parlamentar=parlamentar_a,
+ partido=partido,
+ data='2018-02-02',
+ data_desfiliacao='2019-08-01'
+ )
+ filiacao_b = mommy.make(
+ Filiacao,
+ parlamentar=parlamentar_a,
+ partido=partido,
+ data='2018-02-23',
+ data_desfiliacao='2020-02-04'
+ )
+ mommy.make(
+ Filiacao,
+ parlamentar=parlamentar_b,
+ partido=partido,
+ data='2018-02-07',
+ data_desfiliacao='2018-02-27'
+ )
+ mommy.make(
+ Filiacao,
+ parlamentar=parlamentar_b,
+ partido=partido,
+ data='2018-02-28'
+ )
+
+ lista_parlamentares = parlamentares_filiacoes_intersecao()
+
+ assert len(lista_parlamentares) == 1
+ assert lista_parlamentares == [(parlamentar_a, filiacao_b, filiacao_a)]
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_autores_duplicados():
+ tipo_autor = mommy.make(
+ TipoAutor,
+ descricao="Tipo_Autor_Teste"
+ )
+
+ mommy.make(
+ Autor,
+ tipo=tipo_autor,
+ nome="Nome_Autor_Teste"
+ )
+ mommy.make(
+ Autor,
+ tipo=tipo_autor,
+ nome="Nome_Autor_Teste"
+ )
+ mommy.make(
+ Autor,
+ tipo=tipo_autor,
+ nome="Nome_Autor_Teste-1"
+ )
+
+ lista_autores_duplicados = autores_duplicados()
+
+ assert len(lista_autores_duplicados) == 1
+ assert lista_autores_duplicados[0]['count'] == 2
+ assert lista_autores_duplicados[0]['nome'] == "Nome_Autor_Teste"
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_bancada_comissao_autor_externo():
+ tipo_autor = mommy.make(
+ TipoAutor,
+ descricao="Tipo_Autor_Teste"
+ )
+ tipo_autor_externo = mommy.make(
+ TipoAutor,
+ descricao="Externo"
+ )
+
+ legislatura = mommy.make(
+ Legislatura,
+ numero=1,
+ data_inicio='2012-01-03',
+ data_fim='2013-01-02',
+ data_eleicao='2011-10-04'
+ )
+
+ bancada_a = mommy.make(
+ Bancada,
+ legislatura=legislatura,
+ nome="Bancada_Teste",
+ data_criacao='2012-01-08',
+ )
+ bancada_a.autor.create(
+ nome="Nome_Autor_Teste",
+ tipo=tipo_autor
+ )
+
+ bancada_b = mommy.make(
+ Bancada,
+ legislatura=legislatura,
+ nome="Bancada_Teste-1",
+ data_criacao='2012-02-02'
+ )
+ autor_bancada_b = bancada_b.autor.create(
+ nome="Nome_Autor_Externo_Teste",
+ tipo=tipo_autor_externo
+ )
+
+ tipo_comissao = mommy.make(
+ TipoComissao,
+ nome="Tipo_Comissao_Teste",
+ natureza='T',
+ sigla="TCT"
+ )
+
+ comissao_a = mommy.make(
+ Comissao,
+ nome="Comissao_Teste",
+ sigla="CT",
+ data_criacao='2012-03-08',
+ )
+ comissao_a.autor.create(
+ nome="Nome_Autor_Teste",
+ tipo=tipo_autor
+ )
+
+ comissao_b = mommy.make(
+ Comissao,
+ nome="Comissao_Teste-1",
+ sigla="CT1",
+ data_criacao='2012-04-01',
+ )
+ autor_comissao_b = comissao_b.autor.create(
+ nome="Nome_Autor_Externo_Teste",
+ tipo=tipo_autor_externo
+ )
+
+ lista_bancada_comissao = bancada_comissao_autor_externo()
+
+ assert len(lista_bancada_comissao) == 2
+ assert lista_bancada_comissao[0][0:2] == (autor_bancada_b, bancada_b)
+ assert lista_bancada_comissao[0][2:4] == ('Bancada', 'sistema/bancada')
+ assert lista_bancada_comissao[1][0:2] == (autor_comissao_b, comissao_b)
+ assert lista_bancada_comissao[1][2:4] == ('Comissão', 'comissao')
+
+
+@pytest.mark.django_db(transaction=False)
+def test_lista_anexados_ciclicas():
+ ## DocumentoAdministrativo
+ tipo_documento = mommy.make(
+ TipoDocumentoAdministrativo,
+ sigla="TT",
+ descricao="Tipo_Teste"
+ )
+
+ documento_a = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=26,
+ ano=2019,
+ data='2019-05-15',
+ )
+ documento_b = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=27,
+ ano=2019,
+ data='2019-05-16',
+ )
+ documento_c = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=28,
+ ano=2019,
+ data='2019-05-17',
+ )
+ documento_a1 = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=29,
+ ano=2019,
+ data='2019-05-18',
+ )
+ documento_b1 = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=30,
+ ano=2019,
+ data='2019-05-19',
+ )
+ documento_c1 = mommy.make(
+ DocumentoAdministrativo,
+ tipo=tipo_documento,
+ numero=31,
+ ano=2019,
+ data='2019-05-20',
+ )
+
+ mommy.make(
+ Anexado,
+ documento_principal=documento_a,
+ documento_anexado=documento_b,
+ data_anexacao='2019-05-21'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_a,
+ documento_anexado=documento_c,
+ data_anexacao='2019-05-22'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_b,
+ documento_anexado=documento_c,
+ data_anexacao='2019-05-23'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_a1,
+ documento_anexado=documento_b1,
+ data_anexacao='2019-05-24'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_a1,
+ documento_anexado=documento_c1,
+ data_anexacao='2019-05-25'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_b1,
+ documento_anexado=documento_c1,
+ data_anexacao='2019-05-26'
+ )
+ mommy.make(
+ Anexado,
+ documento_principal=documento_c1,
+ documento_anexado=documento_b1,
+ data_anexacao='2019-05-27'
+ )
+
+ lista_documento_ciclicos = anexados_ciclicos(False)
+
+ ## Matéria
+ tipo_materia = mommy.make(
+ TipoMateriaLegislativa,
+ descricao="Tipo_Teste"
+ )
+ regime_tramitacao = mommy.make(
+ RegimeTramitacao,
+ descricao="Regime_Teste"
+ )
+
+ materia_a = mommy.make(
+ MateriaLegislativa,
+ numero=20,
+ ano=2018,
+ data_apresentacao="2018-01-04",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+ materia_b = mommy.make(
+ MateriaLegislativa,
+ numero=21,
+ ano=2019,
+ data_apresentacao="2019-05-04",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+ materia_c = mommy.make(
+ MateriaLegislativa,
+ numero=22,
+ ano=2019,
+ data_apresentacao="2019-05-05",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+ materia_a1 = mommy.make(
+ MateriaLegislativa,
+ numero=23,
+ ano=2018,
+ data_apresentacao="2019-05-06",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+ materia_b1 = mommy.make(
+ MateriaLegislativa,
+ numero=24,
+ ano=2019,
+ data_apresentacao="2019-05-07",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+ materia_c1 = mommy.make(
+ MateriaLegislativa,
+ numero=25,
+ ano=2019,
+ data_apresentacao="2019-05-08",
+ regime_tramitacao=regime_tramitacao,
+ tipo=tipo_materia
+ )
+
+ mommy.make(
+ Anexada,
+ materia_principal=materia_a,
+ materia_anexada=materia_b,
+ data_anexacao='2019-05-11'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_a,
+ materia_anexada=materia_c,
+ data_anexacao='2019-05-12'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_b,
+ materia_anexada=materia_c,
+ data_anexacao='2019-05-13'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_a1,
+ materia_anexada=materia_b1,
+ data_anexacao='2019-05-11'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_a1,
+ materia_anexada=materia_c1,
+ data_anexacao='2019-05-12'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_b1,
+ materia_anexada=materia_c1,
+ data_anexacao='2019-05-13'
+ )
+ mommy.make(
+ Anexada,
+ materia_principal=materia_c1,
+ materia_anexada=materia_b1,
+ data_anexacao='2019-05-14'
+ )
+
+ lista_materias_ciclicas = anexados_ciclicos(True)
+
+ assert len(lista_materias_ciclicas) == 2
+ assert lista_materias_ciclicas[0] == (datetime.date(2019,5,13), materia_b1, materia_c1)
+ assert lista_materias_ciclicas[1] == (datetime.date(2019,5,14), materia_c1, materia_b1)
+
+ assert len(lista_documento_ciclicos) == 2
+ assert lista_documento_ciclicos[0] == (datetime.date(2019,5,26), documento_b1, documento_c1)
+ assert lista_documento_ciclicos[1] == (datetime.date(2019,5,27), documento_c1, documento_b1)
@pytest.mark.django_db(transaction=False)
diff --git a/sapl/base/urls.py b/sapl/base/urls.py
index 8fbeb43b7..d9a1c5a94 100644
--- a/sapl/base/urls.py
+++ b/sapl/base/urls.py
@@ -29,17 +29,13 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
EstatisticasAcessoNormas,
RelatoriosListView,
ListarInconsistenciasView, ListarProtocolosDuplicadosView,
- ListarProtocolosComMateriasView,
- ListarMatProtocoloInexistenteView,
+ ListarProtocolosComMateriasView, ListarMatProtocoloInexistenteView,
ListarParlamentaresDuplicadosView,
- ListarFiliacoesSemDataFiliacaoView,
- ListarMandatoSemDataInicioView,
- ListarParlMandatosIntersecaoView,
- ListarParlFiliacoesIntersecaoView,
- ListarAutoresDuplicadosView,
- ListarBancadaComissaoAutorExternoView,
- ListarLegislaturaInfindavelView,
- pesquisa_textual,
+ ListarFiliacoesSemDataFiliacaoView, ListarMandatoSemDataInicioView,
+ ListarParlMandatosIntersecaoView, ListarParlFiliacoesIntersecaoView,
+ ListarAutoresDuplicadosView, ListarBancadaComissaoAutorExternoView,
+ ListarLegislaturaInfindavelView, ListarAnexadasCiclicasView,
+ ListarAnexadosCiclicosView, pesquisa_textual,
RelatorioHistoricoTramitacaoAdmView)
@@ -180,6 +176,13 @@ urlpatterns = [
url(r'^sistema/inconsistencias/legislatura_infindavel$',
ListarLegislaturaInfindavelView.as_view(),
name='lista_legislatura_infindavel'),
+ url(r'sistema/inconsistencias/anexadas_ciclicas$',
+ ListarAnexadasCiclicasView.as_view(),
+ name='lista_anexadas_ciclicas'),
+ url(r'sistema/inconsistencias/anexados_ciclicos$',
+ ListarAnexadosCiclicosView.as_view(),
+ name='lista_anexados_ciclicos'),
+
url(r'^sistema/pesquisa-textual',
pesquisa_textual,
name='pesquisa_textual'),
diff --git a/sapl/base/views.py b/sapl/base/views.py
index c56b5e880..f3b1c553d 100644
--- a/sapl/base/views.py
+++ b/sapl/base/views.py
@@ -35,15 +35,15 @@ from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm
from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Reuniao, Comissao
from sapl.crud.base import CrudAux, make_pagination
-from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao,
+from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao, Anexada,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
-from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato, Filiacao
+from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato, Filiacao, SessaoLegislativa
from sapl.protocoloadm.models import (Protocolo, TipoDocumentoAdministrativo,
StatusTramitacaoAdministrativo,
- DocumentoAdministrativo)
+ DocumentoAdministrativo, Anexado)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
- SessaoPlenariaPresenca, Bancada)
+ SessaoPlenariaPresenca, Bancada, TipoSessaoPlenaria)
from sapl.utils import (parlamentares_ativos, gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, mail_service_configured,
intervalos_tem_intersecao, remover_acentos)
@@ -342,14 +342,61 @@ class RelatorioPresencaSessaoView(FilterView):
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
return context
+
+ cd = self.filterset.form.cleaned_data
+ if not cd['data_inicio'] and not cd['sessao_legislativa'] \
+ and not cd['legislatura']:
+ msg = _("Formulário inválido! Preencha pelo menos algum dos campos Período, Legislatura ou Sessão Legislativa.")
+ messages.error(self.request, msg)
+ return context
+
+ # Caso a data tenha sido preenchida, verifica se foi preenchida corretamente
+ if self.request.GET.get('data_inicio_0') and not self.request.GET.get('data_inicio_1'):
+ msg = _("Formulário inválido! Preencha a data do Período Final.")
+ messages.error(self.request, msg)
+ return context
+
+ if not self.request.GET.get('data_inicio_0') and self.request.GET.get('data_inicio_1'):
+ msg = _("Formulário inválido! Preencha a data do Período Inicial.")
+ messages.error(self.request, msg)
+ return context
+
+ param0 = {}
+
+ legislatura_pk = self.request.GET.get('legislatura')
+ if legislatura_pk:
+ param0['sessao_plenaria__legislatura_id'] = legislatura_pk
+ legislatura = Legislatura.objects.get(id=legislatura_pk)
+ context['legislatura'] = legislatura
- # if 'salvar' not in self.request.GET:
- where = context['object_list'].query.where
- _range = where.children[0].rhs
+ sessao_legislativa_pk = self.request.GET.get('sessao_legislativa')
+ if sessao_legislativa_pk:
+ param0['sessao_plenaria__sessao_legislativa_id'] = sessao_legislativa_pk
+ sessao_legislativa = SessaoLegislativa.objects.get(id=sessao_legislativa_pk)
+ context['sessao_legislativa'] = sessao_legislativa
- sufixo = 'sessao_plenaria__data_inicio__range'
- param0 = {'%s' % sufixo: _range}
+ tipo_sessao_plenaria_pk = self.request.GET.get('tipo')
+ context['tipo'] = ''
+ if tipo_sessao_plenaria_pk:
+ param0['sessao_plenaria__tipo_id'] = tipo_sessao_plenaria_pk
+ context['tipo'] = TipoSessaoPlenaria.objects.get(id=tipo_sessao_plenaria_pk)
+ _range = []
+
+ if ('data_inicio_0' in self.request.GET) and self.request.GET['data_inicio_0'] and \
+ ('data_inicio_1' in self.request.GET) and self.request.GET['data_inicio_1']:
+ where = context['object_list'].query.where
+ _range = where.children[0].rhs
+
+ elif legislatura_pk and not sessao_legislativa_pk:
+ _range = [legislatura.data_inicio, legislatura.data_fim]
+
+ elif sessao_legislativa_pk:
+ _range = [sessao_legislativa.data_inicio, sessao_legislativa.data_fim]
+
+ param0.update({'sessao_plenaria__data_inicio__range': _range})
+
+
# Parlamentares com Mandato no intervalo de tempo (Ativos)
parlamentares_qs = parlamentares_ativos(
_range[0], _range[1]).order_by('nome_parlamentar')
@@ -357,16 +404,12 @@ class RelatorioPresencaSessaoView(FilterView):
'id', flat=True)
# Presenças de cada Parlamentar em Sessões
- presenca_sessao = SessaoPlenariaPresenca.objects.filter(
- parlamentar_id__in=parlamentares_id,
- sessao_plenaria__data_inicio__range=_range).values_list(
+ presenca_sessao = SessaoPlenariaPresenca.objects.filter(**param0).values_list(
'parlamentar_id').annotate(
sessao_count=Count('id'))
# Presenças de cada Ordem do Dia
- presenca_ordem = PresencaOrdemDia.objects.filter(
- parlamentar_id__in=parlamentares_id,
- sessao_plenaria__data_inicio__range=_range).values_list(
+ presenca_ordem = PresencaOrdemDia.objects.filter(**param0).values_list(
'parlamentar_id').annotate(
sessao_count=Count('id'))
@@ -433,6 +476,14 @@ class RelatorioPresencaSessaoView(FilterView):
context['periodo'] = (
self.request.GET['data_inicio_0'] +
' - ' + self.request.GET['data_inicio_1'])
+ context['sessao_legislativa'] = ''
+ context['legislatura'] = ''
+ context['exibir_ordem'] = self.request.GET.get('exibir_ordem_dia') == 'on'
+
+ if sessao_legislativa_pk:
+ context['sessao_legislativa'] = SessaoLegislativa.objects.get(id=sessao_legislativa_pk)
+ if legislatura_pk:
+ context['legislatura'] = Legislatura.objects.get(id=legislatura_pk)
# =====================================================================
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
@@ -498,7 +549,7 @@ class RelatorioDataFimPrazoTramitacaoView(FilterView):
def get_context_data(self, **kwargs):
context = super(RelatorioDataFimPrazoTramitacaoView,
self).get_context_data(**kwargs)
- context['title'] = _('Fim de Prazo de Tramitações')
+ context['title'] = _('Relatório de Tramitações')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
@@ -1016,10 +1067,128 @@ class ListarInconsistenciasView(PermissionRequiredMixin, ListView):
len(legislatura_infindavel())
)
)
-
+ tabela.append(
+ ('anexadas_ciclicas',
+ 'Matérias Anexadas cíclicas',
+ len(anexados_ciclicos(True))
+ )
+ )
+ tabela.append(
+ ('anexados_ciclicos',
+ 'Documentos Anexados cíclicos',
+ len(anexados_ciclicos(False))
+ )
+ )
return tabela
+def anexados_ciclicos(ofMateriaLegislativa):
+ ciclicos = []
+
+ if ofMateriaLegislativa:
+ principais = Anexada.objects.values(
+ 'materia_principal'
+ ).annotate(
+ count=Count('materia_principal')
+ ).filter(count__gt=0).order_by('-data_anexacao')
+ else:
+ principais = Anexado.objects.values(
+ 'documento_principal'
+ ).annotate(
+ count=Count('documento_principal')
+ ).filter(count__gt=0).order_by('-data_anexacao')
+
+ for principal in principais:
+ anexados_total = []
+
+ if ofMateriaLegislativa:
+ anexados = Anexada.objects.filter(
+ materia_principal=principal['materia_principal']
+ ).order_by('-data_anexacao')
+ else:
+ anexados = Anexado.objects.filter(
+ documento_principal=principal['documento_principal']
+ ).order_by('-data_anexacao')
+
+ anexados_temp = list(anexados)
+ while anexados_temp:
+ anexado = anexados_temp.pop()
+ if ofMateriaLegislativa:
+ if anexado.materia_anexada not in anexados_total:
+ if not principal['materia_principal'] == anexado.materia_anexada.pk:
+ anexados_total.append(anexado.materia_anexada)
+ anexados_anexado = Anexada.objects.filter(
+ materia_principal=anexado.materia_anexada
+ )
+ anexados_temp.extend(anexados_anexado)
+ else:
+ ciclicos.append((anexado.data_anexacao, anexado.materia_principal, anexado.materia_anexada))
+ else:
+ if anexado.documento_anexado not in anexados_total:
+ if not principal['documento_principal'] == anexado.documento_anexado.pk:
+ anexados_total.append(anexado.documento_anexado)
+ anexados_anexado = Anexado.objects.filter(
+ documento_principal=anexado.documento_anexado
+ )
+ anexados_temp.extend(anexados_anexado)
+ else:
+ ciclicos.append((anexado.data_anexacao, anexado.documento_principal, anexado.documento_anexado))
+
+ return ciclicos
+
+
+class ListarAnexadosCiclicosView(PermissionRequiredMixin, ListView):
+ model = get_user_model()
+ template_name = 'base/anexados_ciclicos.html'
+ context_object_name = 'anexados_ciclicos'
+ permission_required = ('base.list_appconfig',)
+ paginate_by = 10
+
+ def get_queryset(self):
+ return anexados_ciclicos(False)
+
+ def get_context_data(self, **kwargs):
+ context = super(
+ ListarAnexadosCiclicosView, self
+ ).get_context_data(**kwargs)
+
+ paginator = context['paginator']
+ page_obj = context['page_obj']
+
+ context['page_range'] = make_pagination(
+ page_obj.number, paginator.num_pages
+ )
+ context['NO_ENTRIES_MSG'] = 'Nenhum encontrado.'
+
+ return context
+
+
+class ListarAnexadasCiclicasView(PermissionRequiredMixin, ListView):
+ model = get_user_model()
+ template_name = 'base/anexadas_ciclicas.html'
+ context_object_name = 'anexadas_ciclicas'
+ permission_required = ('base.list_appconfig',)
+ paginate_by = 10
+
+ def get_queryset(self):
+ return anexados_ciclicos(True)
+
+ def get_context_data(self, **kwargs):
+ context = super(
+ ListarAnexadasCiclicasView, self
+ ).get_context_data(**kwargs)
+
+ paginator = context['paginator']
+ page_obj = context['page_obj']
+
+ context['page_range'] = make_pagination(
+ page_obj.number, paginator.num_pages
+ )
+ context['NO_ENTRIES_MSG'] = 'Nenhuma encontrada.'
+
+ return context
+
+
def legislatura_infindavel():
return Legislatura.objects.filter(data_fim__isnull=True).order_by('-numero')
diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py
index e999f0b8d..9f7c449f8 100644
--- a/sapl/comissoes/forms.py
+++ b/sapl/comissoes/forms.py
@@ -1,6 +1,7 @@
import logging
from django import forms
+from sapl.settings import MAX_DOC_UPLOAD_SIZE
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import transaction
@@ -381,6 +382,23 @@ class ReuniaoForm(ModelForm):
self.logger.error("A hora de término da reunião ({}) não pode ser menor que a de início ({})."
.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
raise ValidationError(msg)
+
+ upload_pauta = self.cleaned_data.get('upload_pauta', False)
+ upload_ata = self.cleaned_data.get('upload_ata', False)
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_pauta and upload_pauta.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Pauta da Reunião deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_pauta.size/1024)/1024))
+
+ if upload_ata and upload_ata.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Ata da Reunião deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_ata.size/1024)/1024))
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo da Reunião deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
return self.cleaned_data
@@ -412,6 +430,20 @@ class DocumentoAcessorioCreateForm(FileFieldCheckMixin, forms.ModelForm):
def create_documentoacessorio(self):
reuniao = Reuniao.objects.get(id=self.initial['parent_pk'])
+ def clean(self):
+ super(DocumentoAcessorioCreateForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ arquivo = self.cleaned_data.get('arquivo', False)
+
+ if arquivo and arquivo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Texto Integral deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (arquivo.size/1024)/1024))
+
+ return self.cleaned_data
+
class DocumentoAcessorioEditForm(FileFieldCheckMixin, forms.ModelForm):
@@ -424,3 +456,17 @@ class DocumentoAcessorioEditForm(FileFieldCheckMixin, forms.ModelForm):
def __init__(self, user=None, **kwargs):
super(DocumentoAcessorioEditForm, self).__init__(**kwargs)
+
+ def clean(self):
+ super(DocumentoAcessorioEditForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ arquivo = self.cleaned_data.get('arquivo', False)
+
+ if arquivo and arquivo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Texto Integral deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (arquivo.size/1024)/1024))
+
+ return self.cleaned_data
diff --git a/sapl/comissoes/tests/test_comissoes.py b/sapl/comissoes/tests/test_comissoes.py
index 3b45bf337..274e36adb 100644
--- a/sapl/comissoes/tests/test_comissoes.py
+++ b/sapl/comissoes/tests/test_comissoes.py
@@ -3,7 +3,8 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from model_mommy import mommy
-from sapl.comissoes.models import Comissao, Composicao, Periodo, TipoComissao, Reuniao
+from sapl.comissoes.models import Comissao, Composicao, Periodo
+from sapl.comissoes.models import TipoComissao, Reuniao
from sapl.parlamentares.models import Filiacao, Parlamentar, Partido
from sapl.comissoes import forms
@@ -45,6 +46,20 @@ def make_filiacao():
return Filiacao.objects.first()
+@pytest.mark.django_db(transaction=False)
+def test_tipo_comissao_model():
+ mommy.make(TipoComissao,
+ nome='Teste_Nome_Tipo_Comissao',
+ natureza='T',
+ sigla='TSTC')
+
+ tipo_comissao = TipoComissao.objects.first()
+
+ assert tipo_comissao.nome == 'Teste_Nome_Tipo_Comissao'
+ assert tipo_comissao.natureza == 'T'
+ assert tipo_comissao.sigla == 'TSTC'
+
+
@pytest.mark.django_db(transaction=False)
def test_incluir_parlamentar_errors(admin_client):
comissao = make_comissao()
@@ -106,7 +121,7 @@ def test_periodo_invalidas():
form = forms.PeriodoForm(data={'data_inicio': '10/11/2017',
'data_fim': '09/11/2017'
- })
+ })
assert not form.is_valid()
assert form.errors['__all__'] == [_('A Data Final não pode ser menor que '
'a Data Inicial')]
@@ -123,7 +138,7 @@ def test_valida_campos_obrigatorios_periodo_form():
assert errors['data_inicio'] == [_('Este campo é obrigatório.')]
assert len(errors) == 1
-
+
@pytest.mark.django_db(transaction=False)
def test_valida_campos_obrigatorios_reuniao_form():
@@ -141,4 +156,3 @@ def test_valida_campos_obrigatorios_reuniao_form():
assert errors['hora_inicio'] == [_('Este campo é obrigatório.')]
assert len(errors) == 6
-
diff --git a/sapl/compilacao/tests/test_compilacao.py b/sapl/compilacao/tests/test_compilacao.py
new file mode 100644
index 000000000..4eacb8cb1
--- /dev/null
+++ b/sapl/compilacao/tests/test_compilacao.py
@@ -0,0 +1,112 @@
+import pytest
+from model_mommy import mommy
+
+from sapl.compilacao.models import PerfilEstruturalTextoArticulado
+from sapl.compilacao.models import TipoTextoArticulado
+from sapl.compilacao.models import TextoArticulado, TipoNota
+from sapl.compilacao.models import TipoVide, TipoDispositivo
+from sapl.compilacao.models import TipoDispositivoRelationship
+
+
+@pytest.mark.django_db(transaction=False)
+def test_perfil_estrutural_texto_articulado_model():
+ perfil_estrutural_texto_articulado = mommy.make(
+ PerfilEstruturalTextoArticulado,
+ nome='Teste_Nome_Perfil',
+ sigla='TSPETA')
+
+ assert perfil_estrutural_texto_articulado.nome == 'Teste_Nome_Perfil'
+ assert perfil_estrutural_texto_articulado.sigla == 'TSPETA'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_texto_articulado_model():
+ tipo_texto_articulado = mommy.make(
+ TipoTextoArticulado,
+ sigla='TTP',
+ descricao='T_Desc_Tipo_Texto_Articulado'
+ )
+
+ assert tipo_texto_articulado.sigla == 'TTP'
+ assert tipo_texto_articulado.descricao == 'T_Desc_Tipo_Texto_Articulado'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_texto_articulado_model():
+ texto_articulado = mommy.make(
+ TextoArticulado,
+ ementa='Teste_Ementa_Texto_Articulado',
+ numero='12345678',
+ ano=2016,
+ )
+
+ assert texto_articulado.ementa == 'Teste_Ementa_Texto_Articulado'
+ assert texto_articulado.numero == '12345678'
+ assert texto_articulado.ano == 2016
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_nota_model():
+ tipo_nota = mommy.make(
+ TipoNota,
+ sigla='TTN',
+ nome='Teste_Nome_Tipo_Nota'
+ )
+
+ assert tipo_nota.sigla == 'TTN'
+ assert tipo_nota.nome == 'Teste_Nome_Tipo_Nota'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_vide_model():
+ tipo_vide = mommy.make(
+ TipoVide,
+ sigla='TTV',
+ nome='Teste_Nome_Tipo_Vide'
+ )
+
+ assert tipo_vide.sigla == 'TTV'
+ assert tipo_vide.nome == 'Teste_Nome_Tipo_Vide'
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_dispositivo_model():
+ tipo_dispositivo = mommy.make(
+ TipoDispositivo,
+ nome='Teste_Nome_Tipo_Dispositivo',
+ rotulo_ordinal=0
+ )
+
+ assert tipo_dispositivo.nome == 'Teste_Nome_Tipo_Dispositivo'
+ assert tipo_dispositivo.rotulo_ordinal == 0
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tipo_dispositivo_relationship_model():
+ tipo_dispositivo_pai = mommy.make(
+ TipoDispositivo,
+ nome='Tipo_Dispositivo_Pai',
+ rotulo_ordinal=0
+ )
+
+ t_dispositivo_filho = mommy.make(
+ TipoDispositivo,
+ nome='Tipo_Dispositivo_Filho',
+ rotulo_ordinal=0
+ )
+
+ p_e_texto_articulado = mommy.make(
+ PerfilEstruturalTextoArticulado,
+ nome='Teste_Nome_Perfil',
+ sigla='TSPETA')
+
+ tipo_dispositivo_relationship = mommy.make(
+ TipoDispositivoRelationship,
+ pai=tipo_dispositivo_pai,
+ filho_permitido=t_dispositivo_filho,
+ perfil=p_e_texto_articulado,
+ )
+
+ assert tipo_dispositivo_relationship.pai == tipo_dispositivo_pai
+ assert tipo_dispositivo_relationship.perfil == p_e_texto_articulado
+ assert tipo_dispositivo_relationship.filho_permitido == t_dispositivo_filho
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index 8955ebc31..85e202139 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -3,7 +3,7 @@ import logging
import os
from crispy_forms.bootstrap import Alert, InlineRadios
-from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset,
+from crispy_forms.layout import (HTML, Button, Field, Fieldset,
Layout, Row)
from django import forms
from django.contrib.contenttypes.models import ContentType
@@ -156,25 +156,6 @@ class MateriaSimplificadaForm(FileFieldCheckMixin, ModelForm):
)
super(MateriaSimplificadaForm, self).__init__(*args, **kwargs)
- def clean(self):
- super(MateriaSimplificadaForm, self).clean()
-
- if not self.is_valid():
- return self.cleaned_data
-
- cleaned_data = self.cleaned_data
-
- data_apresentacao = cleaned_data['data_apresentacao']
- ano = cleaned_data['ano']
-
- if data_apresentacao.year != ano:
- self.logger.error("O ano da matéria ({}) é diferente"
- " do ano na data de apresentação ({}).".format(ano, data_apresentacao.year))
- raise ValidationError("O ano da matéria não pode ser "
- "diferente do ano na data de apresentação")
-
- return cleaned_data
-
class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
@@ -256,13 +237,6 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
raise ValidationError(
_('Tipo do Protocolo deve ser o mesmo do Tipo Matéria'))
- if data_apresentacao.year != ano:
- self.logger.error("O ano da matéria ({}) é diferente "
- "do ano na data de apresentação ({})."
- .format(ano, data_apresentacao.year))
- raise ValidationError(_("O ano da matéria não pode ser "
- "diferente do ano na data de apresentação"))
-
ano_origem_externa = cleaned_data['ano_origem_externa']
data_origem_externa = cleaned_data['data_origem_externa']
@@ -275,6 +249,12 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
"pode ser diferente do ano na data de "
"origem externa"))
+ texto_original = self.cleaned_data.get('texto_original', False)
+
+ if texto_original and texto_original.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Texto Original deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (texto_original.size/1024)/1024))
+
return cleaned_data
def save(self, commit=False):
@@ -285,7 +265,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
@@ -364,6 +344,20 @@ class DocumentoAcessorioForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = DocumentoAcessorio
fields = ['tipo', 'nome', 'data', 'autor', 'ementa', 'arquivo']
+
+ def clean(self):
+ super(DocumentoAcessorioForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ arquivo = self.cleaned_data.get('arquivo', False)
+
+ if arquivo and arquivo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Texto Integral deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (arquivo.size/1024)/1024))
+
+ return self.cleaned_data
class RelatoriaForm(ModelForm):
@@ -561,7 +555,8 @@ class TramitacaoForm(ModelForm):
materia.em_tramitacao = False if tramitacao.status.indicador == "F" else True
materia.save()
- tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
+ tramitar_anexadas = sapl.base.models.AppConfig.attr(
+ 'tramitacao_materia')
if tramitar_anexadas:
lista_tramitacao = []
anexadas_list = lista_anexados(materia)
@@ -571,35 +566,38 @@ class TramitacaoForm(ModelForm):
ma.em_tramitacao = False if tramitacao.status.indicador == "F" else True
ma.save()
lista_tramitacao.append(Tramitacao(
- status=tramitacao.status,
- materia=ma,
- data_tramitacao=tramitacao.data_tramitacao,
- unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
- data_encaminhamento=tramitacao.data_encaminhamento,
- unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
- urgente=tramitacao.urgente,
- turno=tramitacao.turno,
- texto=tramitacao.texto,
- data_fim_prazo=tramitacao.data_fim_prazo,
- user=tramitacao.user,
- ip=tramitacao.ip
- ))
+ status=tramitacao.status,
+ materia=ma,
+ data_tramitacao=tramitacao.data_tramitacao,
+ unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
+ data_encaminhamento=tramitacao.data_encaminhamento,
+ unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
+ urgente=tramitacao.urgente,
+ turno=tramitacao.turno,
+ texto=tramitacao.texto,
+ data_fim_prazo=tramitacao.data_fim_prazo,
+ user=tramitacao.user,
+ ip=tramitacao.ip
+ ))
Tramitacao.objects.bulk_create(lista_tramitacao)
return tramitacao
-# Compara se os campos de duas tramitações são iguais,
+# Compara se os campos de duas tramitações são iguais,
# exceto os campos id, documento_id e timestamp
def compara_tramitacoes_mat(tramitacao1, tramitacao2):
if not tramitacao1 or not tramitacao2:
return False
lst_items = ['id', 'materia_id', 'timestamp']
- values = [(k,v) for k,v in tramitacao1.__dict__.items() if ((k not in lst_items) and (k[0] != '_'))]
- other_values = [(k,v) for k,v in tramitacao2.__dict__.items() if (k not in lst_items and k[0] != '_')]
+ values = [(k, v) for k, v in tramitacao1.__dict__.items()
+ if ((k not in lst_items) and (k[0] != '_'))]
+ other_values = [(k, v) for k, v in tramitacao2.__dict__.items()
+ if (k not in lst_items and k[0] != '_')]
return values == other_values
+
class TramitacaoUpdateForm(TramitacaoForm):
unidade_tramitacao_local = forms.ModelChoiceField(
queryset=UnidadeTramitacao.objects.all(),
@@ -673,7 +671,8 @@ class TramitacaoUpdateForm(TramitacaoForm):
materia.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
materia.save()
- tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
+ tramitar_anexadas = sapl.base.models.AppConfig.attr(
+ 'tramitacao_materia')
if tramitar_anexadas:
anexadas_list = lista_anexados(materia)
for ma in anexadas_list:
@@ -696,6 +695,7 @@ class TramitacaoUpdateForm(TramitacaoForm):
ma.save()
return nova_tram_principal
+
class LegislacaoCitadaForm(ModelForm):
tipo = forms.ModelChoiceField(
@@ -869,8 +869,10 @@ class AnexadaForm(ModelForm):
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao:
- self.logger.error("Data de anexação posterior à data de desanexação.")
- raise ValidationError(_("Data de anexação posterior à data de desanexação."))
+ self.logger.error(
+ "Data de anexação posterior à data de desanexação.")
+ raise ValidationError(
+ _("Data de anexação posterior à data de desanexação."))
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})."
@@ -899,9 +901,10 @@ class AnexadaForm(ModelForm):
if is_anexada:
self.logger.error("Matéria já se encontra anexada.")
raise ValidationError(_('Matéria já se encontra anexada'))
-
+
ciclico = False
- anexadas_anexada = Anexada.objects.filter(materia_principal=materia_anexada)
+ anexadas_anexada = Anexada.objects.filter(
+ materia_principal=materia_anexada)
while anexadas_anexada and not ciclico:
anexadas = []
@@ -910,15 +913,17 @@ class AnexadaForm(ModelForm):
if materia_principal == anexa.materia_anexada:
ciclico = True
- else:
+ else:
for a in Anexada.objects.filter(materia_principal=anexa.materia_anexada):
anexadas.append(a)
anexadas_anexada = anexadas
-
+
if ciclico:
- self.logger.error("A matéria não pode ser anexada por uma de suas anexadas.")
- raise ValidationError(_("A matéria não pode ser anexada por uma de suas anexadas."))
+ self.logger.error(
+ "A matéria não pode ser anexada por uma de suas anexadas.")
+ raise ValidationError(
+ _("A matéria não pode ser anexada por uma de suas anexadas."))
cleaned_data['materia_anexada'] = materia_anexada
@@ -1079,9 +1084,6 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
HTML(autor_modal),
row4, row6, row7, row9,
form_actions(label=_('Pesquisar')))
-
-
-
)
@property
@@ -1140,9 +1142,50 @@ def filtra_tramitacao_destino_and_status(status, destino):
'materia_id', flat=True)
+class DespachoInicialCreateForm(forms.Form):
+ comissao = forms.ModelMultipleChoiceField(
+ queryset=Comissao.objects.filter(ativa=True),
+ widget=forms.CheckboxSelectMultiple(),
+ label=Comissao._meta.verbose_name_plural)
+
+ def __init__(self, *args, **kwargs):
+ row1 = to_row(
+ [('comissao', 12), ])
+
+ self.helper = SaplFormHelper()
+ self.helper.form_method = 'POST'
+ self.helper.layout = SaplFormLayout(row1)
+ super().__init__(*args, **kwargs)
+
+ def clean(self):
+ super().clean()
+
+ comissoes = self.cleaned_data.get('comissao')
+ if not comissoes:
+ msg = _('Você deve escolher pelo menos uma comissão.')
+ raise ValidationError(msg)
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ errors = []
+ for comissao in comissoes:
+ if DespachoInicial.objects.filter(
+ materia=self.initial['materia'],
+ comissao=comissao,
+ ).exists():
+ msg = _('Já existe um Despacho cadastrado para %s' %
+ comissao)
+ errors.append(msg)
+ if errors:
+ raise ValidationError(errors)
+
+ return self.cleaned_data
+
+
class DespachoInicialForm(ModelForm):
comissao = forms.ModelChoiceField(
- queryset=Comissao.objects.filter(ativa=True))
+ queryset=Comissao.objects.filter(ativa=True), label=_('Comissão'))
class Meta:
model = DespachoInicial
@@ -1184,7 +1227,8 @@ class AutoriaForm(ModelForm):
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
+ self.fields['primeiro_autor'].initial = Autoria.objects.filter(
+ materia=materia).count() == 0
row1 = to_row([('tipo_autor', 4),
('autor', 4),
@@ -1254,8 +1298,9 @@ class AutoriaMultiCreateForm(Form):
super().__init__(*args, **kwargs)
if 'initial' in kwargs and 'autores' in kwargs['initial']:
- self.fields['primeiro_autor'].initial = kwargs['initial']['autores'].count() == 0
-
+ self.fields['primeiro_autor'].initial = kwargs['initial']['autores'].count(
+ ) == 0
+
row1 = to_row([('tipo_autor', 10), ('primeiro_autor', 2)])
row2 = to_row([('autor', 12), ])
@@ -1456,7 +1501,8 @@ class TipoProposicaoForm(ModelForm):
self.fields['content_type'].choices = [
(ct.pk, ct) for k, ct in content_types.items()]
- self.fields['content_type'].choices.sort(key=lambda x: str(x[1]))
+ # Ordena por id
+ self.fields['content_type'].choices.sort(key=lambda x: x[0])
if self.instance.pk:
self.fields[
@@ -1536,6 +1582,197 @@ class TipoProposicaoSelect(Select):
return option
+class TramitacaoEmLoteForm(ModelForm):
+ logger = logging.getLogger(__name__)
+
+ class Meta:
+ model = Tramitacao
+ fields = ['data_tramitacao',
+ 'unidade_tramitacao_local',
+ 'status',
+ 'urgente',
+ 'turno',
+ 'unidade_tramitacao_destino',
+ 'data_encaminhamento',
+ 'data_fim_prazo',
+ 'texto',
+ 'user',
+ 'ip']
+ widgets = {'user': forms.HiddenInput(),
+ 'ip': forms.HiddenInput()}
+
+
+ def __init__(self, *args, **kwargs):
+ super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs)
+ self.fields['data_tramitacao'].initial = timezone.now().date()
+ ust = UnidadeTramitacao.objects.select_related().all()
+ unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
+ for ut in ust if ut.comissao and ut.comissao.ativa]
+ unidade_tramitacao_destino.extend(
+ [(ut.pk, ut) for ut in ust if ut.orgao])
+ unidade_tramitacao_destino.extend(
+ [(ut.pk, ut) for ut in ust if ut.parlamentar])
+ self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
+ self.fields['urgente'].label = "Urgente? *"
+
+ row1 = to_row([
+ ('data_tramitacao', 4),
+ ('data_encaminhamento', 4),
+ ('data_fim_prazo', 4)
+ ])
+ row2 = to_row([
+ ('unidade_tramitacao_local', 6),
+ ('unidade_tramitacao_destino', 6),
+ ])
+ row3 = to_row([
+ ('status', 4),
+ ('urgente', 4),
+ ('turno', 4)
+ ])
+ row4 = to_row([
+ ('texto', 12)
+ ])
+
+ documentos_checkbox_HTML = '''
+
+
+ Selecione as matérias para tramitação:
+
+
+ '''
+
+ self.helper = SaplFormHelper()
+ self.helper.layout = Layout(
+ Fieldset(
+ 'Detalhes da tramitação:',
+ row1, row2, row3, row4,
+ HTML(documentos_checkbox_HTML),
+ form_actions(label='Salvar')
+ )
+ )
+
+
+ def clean(self):
+ cleaned_data = super(TramitacaoEmLoteForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ if 'data_encaminhamento' in cleaned_data:
+ data_enc_form = cleaned_data['data_encaminhamento']
+ if 'data_fim_prazo' in cleaned_data:
+ data_prazo_form = cleaned_data['data_fim_prazo']
+ if 'data_tramitacao' in cleaned_data:
+ data_tram_form = cleaned_data['data_tramitacao']
+
+ if not self.instance.data_tramitacao:
+
+ if cleaned_data['data_tramitacao'] > timezone.now().date():
+ self.logger.error('A data de tramitação ({}) deve ser '
+ 'menor ou igual a data de hoje ({})!'
+ .format(cleaned_data['data_tramitacao'], timezone.now().date()))
+ msg = _(
+ 'A data de tramitação deve ser ' +
+ 'menor ou igual a data de hoje!')
+ raise ValidationError(msg)
+
+ if data_enc_form:
+ if data_enc_form < data_tram_form:
+ self.logger.error('A data de encaminhamento ({}) deve ser '
+ 'maior que a data de tramitação ({})!'
+ .format(data_enc_form, data_tram_form))
+ msg = _('A data de encaminhamento deve ser ' +
+ 'maior que a data de tramitação!')
+ raise ValidationError(msg)
+
+ if data_prazo_form:
+ if data_prazo_form < data_tram_form:
+ self.logger.error('A data fim de prazo ({}) deve ser '
+ 'maior que a data de tramitação ({})!'
+ .format(data_prazo_form, data_tram_form))
+ msg = _('A data fim de prazo deve ser ' +
+ 'maior que a data de tramitação!')
+ raise ValidationError(msg)
+
+ return cleaned_data
+
+ @transaction.atomic
+ def save(self, commit=True):
+ cd = self.cleaned_data
+ materias = self.initial['materias']
+ user = self.initial['user'] if 'user' in self.initial else None
+ ip = self.initial['ip'] if 'ip' in self.initial else ''
+ tramitar_anexadas = AppConfig.attr('tramitacao_materia')
+ for mat_id in materias:
+ mat = MateriaLegislativa.objects.get(id=mat_id)
+ tramitacao = Tramitacao.objects.create(
+ status=cd['status'],
+ materia=mat,
+ data_tramitacao=cd['data_tramitacao'],
+ unidade_tramitacao_local=cd['unidade_tramitacao_local'],
+ unidade_tramitacao_destino=cd['unidade_tramitacao_destino'],
+ data_encaminhamento=cd['data_encaminhamento'],
+ urgente=cd['urgente'],
+ turno=cd['turno'],
+ texto=cd['texto'],
+ data_fim_prazo=cd['data_fim_prazo'],
+ user=user,
+ ip=ip
+ )
+ mat.em_tramitacao = False if tramitacao.status.indicador == "F" else True
+ mat.save()
+
+ if tramitar_anexadas:
+ lista_tramitacao = []
+ anexadas = lista_anexados(mat)
+ for ml in anexadas:
+ if not ml.tramitacao_set.all() \
+ or ml.tramitacao_set.last() \
+ .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
+ ml.em_tramitacao = False if tramitacao.status.indicador == "F" else True
+ ml.save()
+ lista_tramitacao.append(Tramitacao(
+ status=tramitacao.status,
+ materia=ml,
+ data_tramitacao=tramitacao.data_tramitacao,
+ unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
+ data_encaminhamento=tramitacao.data_encaminhamento,
+ unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
+ urgente=tramitacao.urgente,
+ turno=tramitacao.turno,
+ texto=tramitacao.texto,
+ data_fim_prazo=tramitacao.data_fim_prazo,
+ user=tramitacao.user,
+ ip=tramitacao.ip
+ ))
+ Tramitacao.objects.bulk_create(lista_tramitacao)
+
+ return tramitacao
+
+
class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
logger = logging.getLogger(__name__)
@@ -1584,7 +1821,6 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
'observacao',
'texto_original',
'materia_de_vinculo',
-
'tipo_materia',
'numero_materia',
'ano_materia',
@@ -1672,12 +1908,11 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
def clean_texto_original(self):
texto_original = self.cleaned_data.get('texto_original', False)
+
if texto_original and texto_original.size > MAX_DOC_UPLOAD_SIZE:
- max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
- self.logger.error(
- "- Arquivo muito grande. ( > {0}MB )".format(max_size))
- raise ValidationError(
- "Arquivo muito grande. ( > {0}MB )".format(max_size))
+ raise ValidationError("O arquivo Texto Original deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (texto_original.size/1024)/1024))
+
return texto_original
def gerar_hash(self, inst, receber_recibo):
@@ -1731,6 +1966,7 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
self.logger.info("MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) com sucesso."
.format(tm, am, nm))
cd['materia_de_vinculo'] = materia_de_vinculo
+
return cd
def save(self, commit=True):
@@ -1766,7 +2002,7 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
ano=timezone.now().year).aggregate(Max('numero_proposicao'))
numero__max = numero__max['numero_proposicao__max']
inst.numero_proposicao = (
- numero__max + 1) if numero__max else 1
+ numero__max + 1) if numero__max else 1
self.gerar_hash(inst, receber_recibo)
@@ -1864,7 +2100,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
attrs={'readonly': 'readonly'}))
regime_tramitacao = forms.ModelChoiceField(label="Regime de tramitação",
- required=False, queryset=RegimeTramitacao.objects.all())
+ required=False, queryset=RegimeTramitacao.objects.all())
gerar_protocolo = forms.ChoiceField(
required=False,
diff --git a/sapl/materia/migrations/0051_auto_20190703_1414.py b/sapl/materia/migrations/0051_auto_20190703_1414.py
new file mode 100644
index 000000000..fad0e1933
--- /dev/null
+++ b/sapl/materia/migrations/0051_auto_20190703_1414.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-07-03 17:14
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('materia', '0050_auto_20190521_1148'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='despachoinicial',
+ name='comissao',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comissoes.Comissao', verbose_name='Comissão'),
+ ),
+ ]
diff --git a/sapl/materia/models.py b/sapl/materia/models.py
index 096aabc97..d9a5e344a 100644
--- a/sapl/materia/models.py
+++ b/sapl/materia/models.py
@@ -485,7 +485,7 @@ class AssuntoMateria(models.Model):
@reversion.register()
class DespachoInicial(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
- comissao = models.ForeignKey(Comissao, on_delete=models.CASCADE)
+ comissao = models.ForeignKey(Comissao, on_delete=models.CASCADE, verbose_name="Comissão")
class Meta:
verbose_name = _('Despacho Inicial')
diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py
index 962dc2cff..2fe9145de 100644
--- a/sapl/materia/urls.py
+++ b/sapl/materia/urls.py
@@ -26,9 +26,11 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
TramitacaoEmLoteView, UnidadeTramitacaoCrud,
proposicao_texto, recuperar_materia,
ExcluirTramitacaoEmLoteView, RetornarProposicao,
- MateriaPesquisaSimplesView)
+ MateriaPesquisaSimplesView,
+ DespachoInicialMultiCreateView)
from sapl.norma.views import NormaPesquisaSimplesView
-from sapl.protocoloadm.views import (FichaPesquisaAdmView, FichaSelecionaAdmView)
+from sapl.protocoloadm.views import (
+ FichaPesquisaAdmView, FichaSelecionaAdmView)
from .apps import AppConfig
@@ -55,13 +57,20 @@ urlpatterns_impressos = [
name='impressos_materia_pesquisa'),
url(r'^materia/impressos/ficha-pesquisa-adm/$',
FichaPesquisaAdmView.as_view(),
- name= 'impressos_ficha_pesquisa_adm'),
+ name='impressos_ficha_pesquisa_adm'),
url(r'^materia/impressos/ficha-seleciona-adm/$',
FichaSelecionaAdmView.as_view(),
- name= 'impressos_ficha_seleciona_adm'),
+ name='impressos_ficha_seleciona_adm'),
]
urlpatterns_materia = [
+
+ # Esta customização substitui a url do crud desque que ela permaneça antes
+ # da inclusão das urls de DespachoInicialCrud
+ url(r'^materia/(?P\d+)/despachoinicial/create',
+ DespachoInicialMultiCreateView.as_view(),
+ name='despacho-inicial-multi'),
+
url(r'^materia/', include(MateriaLegislativaCrud.get_urls() +
AnexadaCrud.get_urls() +
AutoriaCrud.get_urls() +
@@ -76,7 +85,8 @@ urlpatterns_materia = [
url(r'^materia/(?P[0-9]+)/create_simplificado$',
CriarProtocoloMateriaView.as_view(),
name='materia_create_simplificado'),
- url(r'^materia/recuperar-materia', recuperar_materia, name='recuperar_materia'),
+ url(r'^materia/recuperar-materia',
+ recuperar_materia, name='recuperar_materia'),
url(r'^materia/(?P[0-9]+)/ta$',
MateriaTaView.as_view(), name='materia_ta'),
@@ -96,6 +106,7 @@ urlpatterns_materia = [
AutoriaMultiCreateView.as_view(),
name='autoria_multicreate'),
+
url(r'^materia/acessorio-em-lote', DocumentoAcessorioEmLoteView.as_view(),
name='acessorio_em_lote'),
url(r'^materia/(?P\d+)/anexada-em-lote', MateriaAnexadaEmLoteView.as_view(),
@@ -136,6 +147,7 @@ urlpatterns_proposicao = [
name='proposicao_texto'),
url(r'^proposicao/(?P\d+)/retornar', RetornarProposicao.as_view(),
name='retornar-proposicao'),
+
]
urlpatterns_sistema = [
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index 739f4c486..21c590349 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -1,13 +1,11 @@
+from datetime import datetime
+import itertools
import logging
import os
-import shutil
-import tempfile
-import weasyprint
-import itertools
-
-from datetime import datetime
from random import choice
+import shutil
from string import ascii_letters, digits
+import tempfile
from crispy_forms.layout import HTML
from django.conf import settings
@@ -28,6 +26,7 @@ from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView
from django_filters.views import FilterView
import weasyprint
+import weasyprint
import sapl
from sapl.base.email_utils import do_envia_email_confirmacao
@@ -47,11 +46,12 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm,
ConfirmarProposicaoForm,
DevolverProposicaoForm, LegislacaoCitadaForm,
OrgaoForm, ProposicaoForm, TipoProposicaoForm,
- TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm)
+ TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm,
+ DespachoInicialCreateForm)
from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo
-from sapl.settings import MEDIA_ROOT
+from sapl.settings import MEDIA_ROOT, MAX_DOC_UPLOAD_SIZE
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO,
gerar_hash_arquivo, get_base_url, get_client_ip,
get_mime_type_from_file_extension, montar_row_autor,
@@ -69,7 +69,8 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status,
- ExcluirTramitacaoEmLote, compara_tramitacoes_mat)
+ ExcluirTramitacaoEmLote, compara_tramitacoes_mat,
+ TramitacaoEmLoteForm)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
@@ -1140,9 +1141,9 @@ class RelatoriaCrud(MasterDetailCrud):
parlamentar = relatoria.parlamentar
comissao = relatoria.comissao
composicoes = [p.composicao for p in
- Participacao.objects.filter(
- parlamentar=parlamentar,
- composicao__comissao=comissao)]
+ Participacao.objects.filter(
+ parlamentar=parlamentar,
+ composicao__comissao=comissao)]
data_designacao = relatoria.data_designacao_relator
composicao = ''
for c in composicoes:
@@ -1203,7 +1204,8 @@ class TramitacaoCrud(MasterDetailCrud):
'-timestamp',
'-id').first()
- #TODO: Esta checagem foi inserida na issue #2027, mas é mesmo necessária?
+ # TODO: Esta checagem foi inserida na issue #2027, mas é mesmo
+ # necessária?
if ultima_tramitacao:
if ultima_tramitacao.unidade_tramitacao_destino:
context['form'].fields[
@@ -1257,7 +1259,8 @@ class TramitacaoCrud(MasterDetailCrud):
layout_key = 'TramitacaoUpdate'
def form_valid(self, form):
- dict_objeto_antigo = Tramitacao.objects.get(pk=self.kwargs['pk']).__dict__
+ dict_objeto_antigo = Tramitacao.objects.get(
+ pk=self.kwargs['pk']).__dict__
self.object = form.save()
dict_objeto_novo = self.object.__dict__
@@ -1269,7 +1272,8 @@ class TramitacaoCrud(MasterDetailCrud):
'data_encaminhamento', 'data_fim_prazo', 'urgente', 'turno'
]
- # Se não houve qualquer alteração em um dos dados, mantém o usuário e ip
+ # Se não houve qualquer alteração em um dos dados, mantém o usuário
+ # e ip
for atributo in atributos:
if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
self.object.user = user
@@ -1312,7 +1316,7 @@ class TramitacaoCrud(MasterDetailCrud):
materia = tramitacao.materia
url = reverse('sapl.materia:tramitacao_list',
kwargs={'pk': materia.id})
-
+
ultima_tramitacao = materia.tramitacao_set.order_by(
'-data_tramitacao',
'-timestamp',
@@ -1331,7 +1335,8 @@ class TramitacaoCrud(MasterDetailCrud):
if materia.tramitacao_set.count() == 0:
materia.em_tramitacao = False
materia.save()
- tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
+ tramitar_anexadas = sapl.base.models.AppConfig.attr(
+ 'tramitacao_materia')
if tramitar_anexadas:
mat_anexadas = lista_anexados(materia)
for ma in mat_anexadas:
@@ -1353,7 +1358,7 @@ class TramitacaoCrud(MasterDetailCrud):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context
-
+
def montar_helper_documento_acessorio(self):
autor_row = montar_row_autor('autor')
@@ -1484,20 +1489,58 @@ class AutoriaMultiCreateView(PermissionRequiredForAppCrudMixin, FormView):
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, primeiro_autor=primeiro_autor)
+ Autoria.objects.create(materia=self.materia,
+ autor=autor, primeiro_autor=primeiro_autor)
return FormView.form_valid(self, form)
+class DespachoInicialMultiCreateView(PermissionRequiredForAppCrudMixin, FormView):
+ app_label = sapl.materia.apps.AppConfig.label
+ form_class = DespachoInicialCreateForm
+ template_name = 'materia/despachoinicial_multicreate_form.html'
+
+ def get_initial(self):
+ initial = super().get_initial()
+ self.materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
+ initial['materia'] = self.materia
+ return initial
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['title'] = '%s (%s) ' % (
+ _('Adicionar Vários Despachos'), self.materia)
+ context['root_pk'] = self.kwargs['pk']
+ context['subnav_template_name'] = 'materia/subnav.yaml'
+ return context
+
+ def get_success_url(self):
+ messages.add_message(
+ self.request, messages.SUCCESS,
+ _('Despachos adicionados com sucesso.'))
+ return reverse(
+ 'sapl.materia:despachoinicial_list', kwargs={'pk': self.materia.pk})
+
+ def form_valid(self, form):
+ comissoes_selecionadas = form.cleaned_data['comissao']
+ for comissao in comissoes_selecionadas:
+ DespachoInicial.objects.create(
+ materia=self.materia, comissao=comissao)
+
+ return FormView.form_valid(self, form)
+
+ @property
+ def cancel_url(self):
+ return reverse(
+ 'sapl.materia:despachoinicial_list', kwargs={'pk': self.materia.pk})
+
+
class DespachoInicialCrud(MasterDetailCrud):
model = DespachoInicial
parent_field = 'materia'
help_topic = 'despacho_autoria'
public = [RP_LIST, RP_DETAIL]
- class CreateView(MasterDetailCrud.CreateView):
- form_class = DespachoInicialForm
-
class UpdateView(MasterDetailCrud.UpdateView):
form_class = DespachoInicialForm
@@ -1620,7 +1663,7 @@ class MateriaLegislativaCrud(Crud):
form_class = MateriaLegislativaForm
def get_initial(self):
- initial = super(CreateView, self).get_initial()
+ initial = super().get_initial()
initial['user'] = self.request.user
initial['ip'] = get_client_ip(self.request)
@@ -1639,7 +1682,7 @@ class MateriaLegislativaCrud(Crud):
dict_objeto_antigo = MateriaLegislativa.objects.get(
pk=self.kwargs['pk']
).__dict__
-
+
self.object = form.save()
dict_objeto_novo = self.object.__dict__
@@ -1647,7 +1690,7 @@ class MateriaLegislativaCrud(Crud):
'tipo_id', 'ano', 'numero', 'data_apresentacao', 'numero_protocolo',
'tipo_apresentacao', 'texto_original', 'apelido', 'dias_prazo', 'polemica',
'objeto', 'regime_tramitacao_id', 'em_tramitacao', 'data_fim_prazo',
- 'data_publicacao', 'complementar', 'tipo_origem_externa_id',
+ 'data_publicacao', 'complementar', 'tipo_origem_externa_id',
'numero_origem_externa', 'ano_origem_externa', 'local_origem_externa_id',
'data_origem_externa', 'ementa', 'indexacao', 'observacao'
]
@@ -1664,7 +1707,7 @@ class MateriaLegislativaCrud(Crud):
anexadas = lista_anexados(materia)
for anexada in anexadas:
- anexada.em_tramitacao = True if form.instance.em_tramitacao else False
+ anexada.em_tramitacao = True if form.instance.em_tramitacao else False
anexada.save()
return super().form_valid(form)
@@ -1686,7 +1729,8 @@ class MateriaLegislativaCrud(Crud):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
- context['materia'] = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
+ context['materia'] = MateriaLegislativa.objects.get(
+ pk=self.kwargs['pk'])
return context
class ListView(Crud.ListView, RedirectView):
@@ -2073,20 +2117,29 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Autor tem que ter menos do que 50 caracteres.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
-
+
+ if request.FILES['arquivo'].size > MAX_DOC_UPLOAD_SIZE:
+ msg = _("O arquivo Anexo de Texto Integral deve ser menor que {0:.1f} MB, \
+ o tamanho atual desse arquivo é {1:.1f} MB" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (request.FILES['arquivo'].size/1024)/1024))
+ messages.add_message(request, messages.ERROR, msg)
+ return self.get(request, self.kwargs)
+
tmp_name = os.path.join(MEDIA_ROOT, request.FILES['arquivo'].name)
with open(tmp_name, 'wb') as destination:
for chunk in request.FILES['arquivo'].chunks():
destination.write(chunk)
try:
doc_data = tz.localize(datetime.strptime(
- request.POST['data'], "%d/%m/%Y"))
+ request.POST['data'], "%d/%m/%Y"))
except Exception as e:
- msg = _('Formato da data incorreto. O formato deve ser da forma dd/mm/aaaa.')
- messages.add_message(request, messages.ERROR, msg)
- self.logger.error("User={}. {}. Data inserida: {}".format(username, str(msg), request.POST['data']))
- os.remove(tmp_name)
- return self.get(request, self.kwargs)
+ msg = _(
+ 'Formato da data incorreto. O formato deve ser da forma dd/mm/aaaa.')
+ messages.add_message(request, messages.ERROR, msg)
+ self.logger.error("User={}. {}. Data inserida: {}".format(
+ username, str(msg), request.POST['data']))
+ os.remove(tmp_name)
+ return self.get(request, self.kwargs)
for materia_id in marcadas:
doc = DocumentoAcessorio()
@@ -2100,25 +2153,27 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
try:
doc.clean_fields()
except ValidationError as e:
- for m in [ '%s: %s' % (DocumentoAcessorio()._meta.get_field(k).verbose_name, ''.join(v))
- for k,v in e.message_dict.items() ]:
+ for m in ['%s: %s' % (DocumentoAcessorio()._meta.get_field(k).verbose_name, ''.join(v))
+ for k, v in e.message_dict.items()]:
# Insere as mensagens de erro no formato:
# 'verbose_name do nome do campo': 'mensagem de erro'
messages.add_message(request, messages.ERROR, m)
- self.logger.error("User={}. {}. Nome do arquivo: {}.".format(username, str(msg), request.FILES['arquivo'].name))
+ self.logger.error("User={}. {}. Nome do arquivo: {}.".format(
+ username, str(msg), request.FILES['arquivo'].name))
os.remove(tmp_name)
return self.get(request, self.kwargs)
doc.save()
- diretorio = os.path.join(MEDIA_ROOT,
- 'sapl/public/documentoacessorio',
- str(doc_data.year),
- str(doc.id))
+ diretorio = os.path.join(MEDIA_ROOT,
+ 'sapl/public/documentoacessorio',
+ str(doc_data.year),
+ str(doc.id))
if not os.path.exists(diretorio):
os.makedirs(diretorio)
- file_path = os.path.join(diretorio,
+ file_path = os.path.join(diretorio,
request.FILES['arquivo'].name)
shutil.copy2(tmp_name, file_path)
- doc.arquivo.name = file_path.split(MEDIA_ROOT + "/")[1] # Retira MEDIA_ROOT do nome
+ doc.arquivo.name = file_path.split(
+ MEDIA_ROOT + "/")[1] # Retira MEDIA_ROOT do nome
doc.save()
os.remove(tmp_name)
@@ -2144,17 +2199,17 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
# Verifica se os campos foram preenchidos
if not self.request.GET.get('tipo', " "):
- msg =_('Por favor, selecione um tipo de matéria.')
+ msg = _('Por favor, selecione um tipo de matéria.')
messages.add_message(self.request, messages.ERROR, msg)
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
- msg =_('Por favor, preencha as datas.')
+ msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
- msg =_('Por favor, preencha as datas.')
+ msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
@@ -2163,8 +2218,10 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
'numero', '-ano')
principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
not_list = [self.kwargs['pk']] + \
- [m for m in principal.materia_principal_set.all().values_list('materia_anexada_id', flat=True)]
- context['object_list'] = context['object_list'].exclude(pk__in=not_list)
+ [m for m in principal.materia_principal_set.all(
+ ).values_list('materia_anexada_id', flat=True)]
+ context['object_list'] = context['object_list'].exclude(
+ pk__in=not_list)
context['temp_object_list'] = context['object_list']
context['object_list'] = []
@@ -2172,12 +2229,12 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
materia_anexada = obj
ciclico = False
anexadas_anexada = Anexada.objects.filter(
- materia_principal = materia_anexada
+ materia_principal=materia_anexada
)
while anexadas_anexada and not ciclico:
anexadas = []
-
+
for anexa in anexadas_anexada:
if principal == anexa.materia_anexada:
@@ -2185,7 +2242,7 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
else:
for a in Anexada.objects.filter(materia_principal=anexa.materia_anexada):
anexadas.append(a)
-
+
anexadas_anexada = anexadas
if not ciclico:
@@ -2216,7 +2273,7 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
-
+
if data_anexacao > v_data_desanexacao:
msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
@@ -2241,7 +2298,8 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Matéria(s) anexada(s).')
messages.add_message(request, messages.SUCCESS, msg)
- success_url = reverse('sapl.materia:anexada_list', kwargs={'pk': kwargs['pk']})
+ success_url = reverse('sapl.materia:anexada_list',
+ kwargs={'pk': kwargs['pk']})
return HttpResponseRedirect(success_url)
@@ -2254,39 +2312,34 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
logger = logging.getLogger(__name__)
+
def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteView,
self).get_context_data(**kwargs)
context['subnav_template_name'] = 'materia/em_lote/subnav_em_lote.yaml'
+ context['primeira_tramitacao'] = self.primeira_tramitacao
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
return context
- context['title'] = _('Primeira Tramitação em Lote')
-
+ context['object_list'] = context['object_list'].order_by(
+ 'ano', 'numero')
qr = self.request.GET.copy()
- context['unidade_destino'] = UnidadeTramitacao.objects.all()
- context['status_tramitacao'] = StatusTramitacao.objects.all()
- context['turnos_tramitacao'] = Tramitacao.TURNO_CHOICES
- context['urgente_tramitacao'] = YES_NO_CHOICES
- context['unidade_local'] = UnidadeTramitacao.objects.all()
- context['primeira_tramitacao'] = True
+ form = TramitacaoEmLoteForm()
+ context['form'] = form
- # Pega somente matéria que não possuem tramitação
- if (type(self.__dict__['filterset']).__name__ ==
- 'PrimeiraTramitacaoEmLoteFilterSet'):
- context['object_list'] = context['object_list'].filter(
- tramitacao__isnull=True)
+ if self.primeira_tramitacao:
+ context['title'] = _('Primeira Tramitação em Lote')
+ # Pega somente documentos que não possuem tramitação
+ context['object_list'] = [obj for obj in context['object_list']
+ if obj.tramitacao_set.all().count() == 0]
else:
context['title'] = _('Tramitação em Lote')
- context['unidade_local'] = [UnidadeTramitacao.objects.get(
- id=qr['tramitacao__unidade_tramitacao_destino'])]
-
- context['object_list'] = context['object_list'].order_by(
- 'ano', 'numero')
+ context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
+ id=qr['tramitacao__unidade_tramitacao_destino'])
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
@@ -2295,127 +2348,43 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return context
def post(self, request, *args, **kwargs):
+ user = request.user
+ ip = get_client_ip(request)
- marcadas = request.POST.getlist('materia_id')
-
- tz = timezone.get_current_timezone()
-
- username = request.user.username
-
- if len(marcadas) == 0:
- msg = _('Nenhuma máteria foi selecionada.')
+ materias_ids = request.POST.getlist('materias')
+ if not materias_ids:
+ msg = _("Escolha alguma matéria para ser tramitada.")
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
- obrigatorios = {'data_tramitacao': 'Data da Tramitação',
- 'unidade_tramitacao_local': 'Unidade Local',
- 'unidade_tramitacao_destino': 'Unidade Destino',
- 'status': 'Status',
- 'urgente': 'Urgente',
- 'texto': 'Texto da Ação'}
- for field, nome in obrigatorios.items():
- if not request.POST[field]:
- msg = _('Campo {} deve ser preenchido.'.format(nome))
- messages.add_message(request, messages.ERROR, msg)
- return self.get(request, self.kwargs)
- if not request.POST['data_encaminhamento']:
- data_encaminhamento = None
- else:
- try:
- data_encaminhamento = tz.localize(datetime.strptime(
- request.POST['data_encaminhamento'], "%d/%m/%Y"))
- except ValueError:
- msg = _('Formato da data de encaminhamento incorreto.')
- messages.add_message(request, messages.ERROR, msg)
- return self.get(request, self.kwargs)
+ form = TramitacaoEmLoteForm(request.POST,
+ initial= {'materias': materias_ids,
+ 'user': user, 'ip':ip})
- if request.POST['data_fim_prazo'] == '':
- data_fim_prazo = None
- else:
- try:
- data_fim_prazo = tz.localize(datetime.strptime(
- request.POST['data_fim_prazo'], "%d/%m/%Y"))
- except ValueError:
- msg = _('Formato da data fim do prazo incorreto.')
- messages.add_message(request, messages.ERROR, msg)
- return self.get(request, self.kwargs)
+ if form.is_valid():
+ form.save()
- # issue https://github.com/interlegis/sapl/issues/1123
- # TODO: usar Form
- urgente = request.POST['urgente'] == 'True'
- flag_error = False
+ msg = _('Tramitação completa.')
+ self.logger.info('user=' + user.username + '. Tramitação completa.')
+ messages.add_message(request, messages.SUCCESS, msg)
+ return self.get_success_url()
- materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)]
- tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
- materias_anexadas = []
- if tramitar_anexadas:
- for materia in materias_principais:
- materias_anexadas = materias_anexadas + lista_anexados(materia)
+ return self.form_invalid(form)
- materias = set(materias_principais + materias_anexadas)
+
+ def get_success_url(self):
+ return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
- for materia in materias:
- try:
- data_tramitacao = tz.localize(datetime.strptime(
- request.POST['data_tramitacao'], "%d/%m/%Y"))
- except ValueError:
- msg = _('Formato da data da tramitação incorreto.')
- messages.add_message(request, messages.ERROR, msg)
- return self.get(request, self.kwargs)
- user = request.user
- ip = get_client_ip(request)
- t = Tramitacao(
- materia=materia,
- data_tramitacao=data_tramitacao,
- data_encaminhamento=data_encaminhamento,
- data_fim_prazo=data_fim_prazo,
- unidade_tramitacao_local_id=request.POST[
- 'unidade_tramitacao_local'],
- unidade_tramitacao_destino_id=request.POST[
- 'unidade_tramitacao_destino'],
- urgente=urgente,
- status_id=request.POST['status'],
- turno=request.POST['turno'],
- texto=request.POST['texto'],
- user=user,
- ip=ip
- )
- t.save()
- try:
- self.logger.debug("user=" + username +
- ". Tentando enviar tramitação.")
- tramitacao_signal.send(sender=Tramitacao,
- post=t,
- request=self.request)
+ def form_invalid(self, form, *args, **kwargs):
+ for key, erros in form.errors.items():
+ if not key=='__all__':
+ [messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
+ else:
+ [messages.add_message(self.request, messages.ERROR, e) for e in erros]
+ return self.get(self.request, kwargs, {'form':form})
+
- except Exception as e:
- self.logger.error('user=' + username + '. Tramitação criada , mas e-mail de acompanhamento '
- 'de matéria não enviado. Há problemas na configuração '
- 'do e-mail. ' + str(e))
- flag_error = True
- if flag_error:
- msg = _('Tramitação criada, mas e-mail de acompanhamento '
- 'de matéria não enviado. A não configuração do servidor de e-mail '
- 'impede o envio de aviso de tramitação')
- messages.add_message(self.request, messages.WARNING, msg)
-
- status = StatusTramitacao.objects.get(id=request.POST['status'])
-
- for materia in materias:
- if status.indicador == 'F':
- materia.em_tramitacao = False
- elif self.primeira_tramitacao:
- materia.em_tramitacao = True
- materia.save()
-
- msg = _('Tramitação completa. ' + "Foram tramitadas " + str(len(materias)) + " matéria(s).")
- self.logger.info('user=' + username + '. Tramitação completa.')
- messages.add_message(request, messages.SUCCESS, msg)
-
- if self.primeira_tramitacao:
- return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
- return HttpResponseRedirect(reverse('sapl.materia:tramitacao_em_lote'))
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
filterset_class = TramitacaoEmLoteFilterSet
@@ -2428,7 +2397,7 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
qr = self.request.GET.copy()
- context['primeira_tramitacao'] = False
+ context['primeira_tramitacao'] = self.primeira_tramitacao
if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and
diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py
index 366b7d544..803cd2751 100644
--- a/sapl/norma/forms.py
+++ b/sapl/norma/forms.py
@@ -132,8 +132,12 @@ class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
'indexacao',
'observacao',
'texto_integral',
- 'assuntos']
- widgets = {'assuntos': widgets.CheckboxSelectMultiple}
+ 'assuntos',
+ 'user',
+ 'ip']
+ widgets = {'assuntos': widgets.CheckboxSelectMultiple,
+ 'user': forms.HiddenInput(),
+ 'ip': forms.HiddenInput()}
def clean(self):
@@ -189,27 +193,17 @@ class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
else:
cleaned_data['materia'] = None
- ano = cleaned_data['ano']
- data = cleaned_data['data']
-
- if data.year != ano:
- self.logger.error("O ano da norma ({}) é diferente "
- "do ano no campo data ({}).".format(ano, data.year))
- raise ValidationError("O ano da norma não pode ser "
- "diferente do ano no campo data")
return cleaned_data
def clean_texto_integral(self):
super(NormaJuridicaForm, self).clean()
texto_integral = self.cleaned_data.get('texto_integral', False)
+
if texto_integral and texto_integral.size > MAX_DOC_UPLOAD_SIZE:
- max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
- tam_fornecido = str(texto_integral.size / (1024 * 1024))
- self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(
- tam_fornecido, max_size))
- raise ValidationError(
- "Arquivo muito grande. ( > {0}MB )".format(max_size))
+ raise ValidationError("O arquivo Texto Integral deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (texto_integral.size/1024)/1024))
+
return texto_integral
def save(self, commit=False):
@@ -283,16 +277,16 @@ class AnexoNormaJuridicaForm(FileFieldCheckMixin, ModelForm):
def clean(self):
cleaned_data = super(AnexoNormaJuridicaForm, self).clean()
+
if not self.is_valid():
return cleaned_data
+
anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False)
+
if anexo_arquivo and anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE:
- max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
- tam_fornecido = str(anexo_arquivo.size / (1024 * 1024))
- self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(
- tam_fornecido, max_size))
- raise ValidationError(
- "Arquivo muito grande. ( > {0}MB )".format(max_size))
+ raise ValidationError("O Arquivo Anexo deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (anexo_arquivo.size/1024)/1024))
+
return cleaned_data
def save(self, commit=False):
diff --git a/sapl/norma/migrations/0025_auto_20190704_1403.py b/sapl/norma/migrations/0025_auto_20190704_1403.py
new file mode 100644
index 000000000..15db2793b
--- /dev/null
+++ b/sapl/norma/migrations/0025_auto_20190704_1403.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-07-04 17:03
+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),
+ ('norma', '0024_auto_20190425_0917'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='normajuridica',
+ name='ip',
+ field=models.CharField(blank=True, default='', max_length=30, verbose_name='IP'),
+ ),
+ migrations.AddField(
+ model_name='normajuridica',
+ name='user',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário'),
+ ),
+ ]
diff --git a/sapl/norma/models.py b/sapl/norma/models.py
index 6b3a18a1f..cd90e4930 100644
--- a/sapl/norma/models.py
+++ b/sapl/norma/models.py
@@ -10,7 +10,9 @@ from sapl.base.models import Autor
from sapl.compilacao.models import TextoArticulado
from sapl.materia.models import MateriaLegislativa
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
- restringe_tipos_de_arquivo_txt, texto_upload_path)
+ restringe_tipos_de_arquivo_txt,
+ texto_upload_path,
+ get_settings_auth_user_model)
@reversion.register()
@@ -138,6 +140,20 @@ class NormaJuridica(models.Model):
through_fields=('norma', 'autor'),
symmetrical=False)
+ user = models.ForeignKey(
+ get_settings_auth_user_model(),
+ verbose_name=_('Usuário'),
+ on_delete=models.PROTECT,
+ null=True,
+ blank=True
+ )
+ ip = models.CharField(
+ verbose_name=_('IP'),
+ max_length=30,
+ blank=True,
+ default=''
+ )
+
class Meta:
verbose_name = _('Norma Jurídica')
verbose_name_plural = _('Normas Jurídicas')
diff --git a/sapl/norma/views.py b/sapl/norma/views.py
index 735d595a3..8d9a62eaa 100644
--- a/sapl/norma/views.py
+++ b/sapl/norma/views.py
@@ -20,7 +20,7 @@ from sapl.base.models import AppConfig
from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud, make_pagination)
-from sapl.utils import show_results_filter_set
+from sapl.utils import show_results_filter_set, get_client_ip
from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm)
@@ -217,20 +217,24 @@ class NormaCrud(Crud):
return self.search_url
def get_initial(self):
- username = self.request.user.username
+ initial = super().get_initial()
+ initial['user'] = self.request.user
+ initial['ip'] = get_client_ip(self.request)
+
+ username = self.request.user.username
try:
self.logger.debug(
'user=' + username + '. Tentando obter objeto de modelo da esfera da federação.')
esfera = sapl.base.models.AppConfig.objects.last(
).esfera_federacao
- self.initial['esfera_federacao'] = esfera
+ initial['esfera_federacao'] = esfera
except:
self.logger.error(
'user=' + username + '. Erro ao obter objeto de modelo da esfera da federação.')
pass
- self.initial['complemento'] = False
- return self.initial
+ initial['complemento'] = False
+ return initial
layout_key = 'NormaJuridicaCreate'
@@ -249,7 +253,7 @@ class NormaCrud(Crud):
layout_key = 'NormaJuridicaCreate'
def get_initial(self):
- initial = super(UpdateView, self).get_initial()
+ initial = super().get_initial()
norma = NormaJuridica.objects.get(id=self.kwargs['pk'])
if norma.materia:
initial['tipo_materia'] = norma.materia.tipo
@@ -258,6 +262,41 @@ class NormaCrud(Crud):
initial['esfera_federacao'] = norma.esfera_federacao
return initial
+ def form_valid(self, form):
+ norma_antiga = NormaJuridica.objects.get(
+ pk=self.kwargs['pk']
+ )
+
+ # Feito desta forma para que sejam materializados os assuntos antigos
+ assuntos_antigos = set(norma_antiga.assuntos.all())
+
+ dict_objeto_antigo = norma_antiga.__dict__
+ self.object = form.save()
+ dict_objeto_novo = self.object.__dict__
+
+ atributos = ['tipo_id', 'numero', 'ano', 'data', 'esfera_federacao',
+ 'complemento', 'materia_id', 'numero',
+ 'data_publicacao', 'data_vigencia',
+ 'veiculo_publicacao', 'pagina_inicio_publicacao',
+ 'pagina_fim_publicacao', 'ementa', 'indexacao',
+ 'observacao', 'texto_integral']
+
+ for atributo in atributos:
+ if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
+ self.object.user = self.request.user
+ self.object.ip = get_client_ip(self.request)
+ self.object.save()
+ break
+
+ # Campo Assuntos não veio no __dict__, então é comparado separadamente
+ assuntos_novos = set(self.object.assuntos.all())
+ if assuntos_antigos != assuntos_novos:
+ self.object.user = self.request.user
+ self.object.ip = get_client_ip(self.request)
+ self.object.save()
+
+ return super().form_valid(form)
+
def recuperar_norma(request):
logger = logging.getLogger(__name__)
diff --git a/sapl/painel/views.py b/sapl/painel/views.py
index 333c3771e..5cadba9a1 100644
--- a/sapl/painel/views.py
+++ b/sapl/painel/views.py
@@ -523,11 +523,14 @@ def get_dados_painel(request, pk):
if casa and app_config and (bool(casa.logotipo)):
brasao = casa.logotipo.url \
if app_config.mostrar_brasao_painel else None
-
+
response = {
'sessao_plenaria': str(sessao),
'sessao_plenaria_data': sessao.data_inicio.strftime('%d/%m/%Y'),
'sessao_plenaria_hora_inicio': sessao.hora_inicio,
+ 'sessao_solene': sessao.tipo.nome == "Solene",
+ 'sessao_finalizada': sessao.finalizada,
+ 'tema_solene': sessao.tema_solene,
'cronometro_aparte': get_cronometro_status(request, 'aparte'),
'cronometro_discurso': get_cronometro_status(request, 'discurso'),
'cronometro_ordem': get_cronometro_status(request, 'ordem'),
diff --git a/sapl/parlamentares/urls.py b/sapl/parlamentares/urls.py
index 4c1434333..6e175bafe 100644
--- a/sapl/parlamentares/urls.py
+++ b/sapl/parlamentares/urls.py
@@ -19,7 +19,8 @@ from sapl.parlamentares.views import (CargoMesaCrud, ColigacaoCrud,
parlamentares_frente_selected,
remove_parlamentar_composicao,
parlamentares_filiados, BlocoCrud,
- PesquisarParlamentarView, VincularParlamentarView)
+ PesquisarParlamentarView, VincularParlamentarView,
+ get_sessoes_legislatura)
from .apps import AppConfig
@@ -90,5 +91,8 @@ urlpatterns = [
url(r'^mesa-diretora/remove-parlamentar-composicao/$',
remove_parlamentar_composicao, name='remove_parlamentar_composicao'),
+
+ url(r'^parlamentar/get-sessoes-legislatura/$',
+ get_sessoes_legislatura, name='get_sessoes_legislatura'),
]
diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py
index 874f53385..c81ed46bb 100644
--- a/sapl/parlamentares/views.py
+++ b/sapl/parlamentares/views.py
@@ -1176,4 +1176,15 @@ class BlocoCrud(CrudAux):
form_class = BlocoForm
def get_success_url(self):
- return reverse('sapl.parlamentares:bloco_list')
\ No newline at end of file
+ return reverse('sapl.parlamentares:bloco_list')
+
+
+def get_sessoes_legislatura(request):
+
+ legislatura_id = request.GET['legislatura']
+
+ json_response = {'sessoes_legislativas': []}
+ for s in SessaoLegislativa.objects.filter(legislatura_id=legislatura_id):
+ json_response['sessoes_legislativas'].append( (s.id, str(s)) )
+
+ return JsonResponse(json_response)
\ No newline at end of file
diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py
index f56409c0a..859de2850 100644
--- a/sapl/protocoloadm/forms.py
+++ b/sapl/protocoloadm/forms.py
@@ -5,6 +5,7 @@ from crispy_forms.bootstrap import InlineRadios, Alert, FormActions
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Div, Submit
from django import forms
+from sapl.settings import MAX_DOC_UPLOAD_SIZE
from django.core.exceptions import (MultipleObjectsReturned,
ObjectDoesNotExist, ValidationError)
from django.db import models, transaction
@@ -657,6 +658,20 @@ class DocumentoAcessorioAdministrativoForm(FileFieldCheckMixin, ModelForm):
'data': forms.DateInput(format='%d/%m/%Y')
}
+ def clean(self):
+ super(DocumentoAcessorioAdministrativoForm, self).clean()
+
+ if not self.is_valid():
+ return self.cleaned_data
+
+ arquivo = self.cleaned_data.get('arquivo', False)
+
+ if arquivo and arquivo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (arquivo.size/1024)/1024))
+
+ return self.cleaned_data
+
class TramitacaoAdmForm(ModelForm):
@@ -1142,6 +1157,12 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
' documento vinculado'
% (numero_protocolo, ano_protocolo)))
+ texto_integral = self.cleaned_data.get('texto_integral', False)
+
+ if texto_integral and texto_integral.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Texto Integral deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (texto_integral.size/1024)/1024))
+
return self.cleaned_data
def save(self, commit=True):
@@ -1587,12 +1608,6 @@ class TramitacaoEmLoteAdmForm(ModelForm):
'maior que a data de tramitação!')
raise ValidationError(msg)
- if cleaned_data['unidade_tramitacao_local'] == cleaned_data['unidade_tramitacao_destino']:
- msg = _('Unidade tramitação local deve ser diferente da unidade tramitação destino.')
- self.logger.error('Unidade tramitação local ({}) deve ser diferente da unidade tramitação destino'
- .format(cleaned_data['unidade_tramitacao_local']))
- raise ValidationError(msg)
-
return cleaned_data
@transaction.atomic
diff --git a/sapl/protocoloadm/migrations/0022_auto_20190715_1101.py b/sapl/protocoloadm/migrations/0022_auto_20190715_1101.py
new file mode 100644
index 000000000..c7bb30444
--- /dev/null
+++ b/sapl/protocoloadm/migrations/0022_auto_20190715_1101.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-07-15 14:01
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('protocoloadm', '0021_merge_20190429_1531'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='protocolo',
+ name='ip_data_hora_manual',
+ field=models.CharField(blank=True, help_text='Endereço IP da estação de trabalho do usuário que está realizando Protocolo e informando data e hora manualmente.', max_length=256, verbose_name='IP'),
+ ),
+ migrations.AlterField(
+ model_name='protocolo',
+ name='user_data_hora_manual',
+ field=models.CharField(blank=True, help_text='Usuário que está realizando Protocolo e informando data e hora manualmente.', max_length=256, verbose_name='IP'),
+ ),
+ ]
diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py
index 8396349a8..f0e40f9c7 100644
--- a/sapl/protocoloadm/models.py
+++ b/sapl/protocoloadm/models.py
@@ -57,7 +57,6 @@ class Protocolo(models.Model):
null=False,
choices=RANGE_ANOS,
verbose_name=_('Ano do Protocolo'))
-
data = models.DateField(null=True, blank=True,
verbose_name=_('Data do Protocolo'),
help_text=_('Informado manualmente'))
@@ -66,12 +65,12 @@ class Protocolo(models.Model):
help_text=_('Informado manualmente'))
timestamp_data_hora_manual = models.DateTimeField(default=timezone.now)
user_data_hora_manual = models.CharField(
- max_length=20, blank=True,
+ max_length=256, blank=True,
verbose_name=_('IP'),
help_text=_('Usuário que está realizando Protocolo e informando '
'data e hora manualmente.'))
ip_data_hora_manual = models.CharField(
- max_length=15, blank=True,
+ max_length=256, blank=True,
verbose_name=_('IP'),
help_text=_('Endereço IP da estação de trabalho '
'do usuário que está realizando Protocolo e informando '
@@ -346,12 +345,12 @@ class TramitacaoAdministrativo(models.Model):
class Anexado(models.Model):
documento_principal = models.ForeignKey(
DocumentoAdministrativo, related_name='documento_principal_set',
- on_delete = models.CASCADE,
+ on_delete=models.CASCADE,
verbose_name=_('Documento Principal')
)
documento_anexado = models.ForeignKey(
DocumentoAdministrativo, related_name='documento_anexado_set',
- on_delete = models.CASCADE,
+ on_delete=models.CASCADE,
verbose_name=_('Documento Anexado')
)
data_anexacao = models.DateField(verbose_name=_('Data Anexação'))
@@ -369,7 +368,7 @@ class Anexado(models.Model):
'documento_anexado_tipo': self.documento_anexado.tipo,
'documento_anexado_numero': self.documento_anexado.numero,
'documento_anexado_ano': self.documento_anexado.ano
- }
+ }
@reversion.register()
diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py
index bd9b823dc..a1166f81b 100644
--- a/sapl/protocoloadm/tests/test_protocoloadm.py
+++ b/sapl/protocoloadm/tests/test_protocoloadm.py
@@ -881,20 +881,6 @@ def test_tramitacao_lote_documentos_form(admin_client):
["A data fim de prazo deve ser maior que a data de tramitação!"]
assert not form.is_valid()
- form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
- form.data = {'data_tramitacao': '2019-05-14',
- 'data_encaminhamento' : '2019-05-15',
- 'data_fim_prazo': '2019-05-18',
- 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
- 'unidade_tramitacao_destino': unidade_tramitacao_local_1.id,
- 'status': status.id,
- 'urgente': False,
- 'texto': 'aaaa'}
-
- assert form.errors['__all__'] == \
- ["Unidade tramitação local deve ser diferente da unidade tramitação destino."]
- assert not form.is_valid()
-
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': '2019-05-14',
'data_encaminhamento' : '2019-05-15',
@@ -1037,22 +1023,6 @@ def test_tramitacao_lote_documentos_views(admin_client):
assert 'Status: Este campo é obrigatório.' in msgs
assert 'Unidade Destino: Este campo é obrigatório.' in msgs
assert 'Texto da Ação: Este campo é obrigatório.' in msgs
-
- response = admin_client.post(url_lote,
- {'documentos': documentos,
- 'data_tramitacao': date(2019, 5, 15),
- 'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
- 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
- 'status': status.id,
- 'urgente': False,
- 'texto': 'aaaa',
- 'salvar':'salvar'},
- follow=True)
- assert response.status_code == 200
-
- msgs = [m.message for m in response.context['messages']]
-
- assert 'Unidade tramitação local deve ser diferente da unidade tramitação destino.' in msgs
response = admin_client.post(url_lote,
{'documentos': documentos,
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
index 32f6748ad..eabccca90 100755
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -11,6 +11,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
+from django.db import transaction
from django.db.models import Max, Q
from django.http import Http404, HttpResponse, JsonResponse
from django.http.response import HttpResponseRedirect
@@ -539,6 +540,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
initial['hora'] = timezone.localtime(timezone.now())
return initial
+ @transaction.atomic
def form_valid(self, form):
protocolo = form.save(commit=False)
username = self.request.user.username
@@ -726,6 +728,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
initial['hora'] = timezone.localtime(timezone.now())
return initial
+ @transaction.atomic
def form_valid(self, form):
protocolo = form.save(commit=False)
username = self.request.user.username
@@ -983,7 +986,7 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
def get_context_data(self, **kwargs):
context = super(
- DocumentoAnexadoEmLoteView,self
+ DocumentoAnexadoEmLoteView, self
).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk']
@@ -1545,7 +1548,7 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
qr = self.request.GET.copy()
- context['primeira_tramitacao'] = False
+ context['primeira_tramitacao'] = self.primeira_tramitacao
if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and
diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
index 805731a70..0ede61f97 100644
--- a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
+++ b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
@@ -128,6 +128,9 @@ def inf_basicas(inf_basicas_dic):
if dat_fim_sessao or hr_fim_sessao:
tmp += '\t\tEncerramento: ' + \
dat_fim_sessao + ' - ' + hr_fim_sessao + ' \n'
+ if inf_basicas_dic.get('tema_solene'):
+ tmp += '\t\tTema da Sessão Solene: ' + \
+ inf_basicas_dic['tema_solene'] + ' \n'
return tmp
diff --git a/sapl/relatorios/urls.py b/sapl/relatorios/urls.py
index 9ca2284a0..05ad22671 100644
--- a/sapl/relatorios/urls.py
+++ b/sapl/relatorios/urls.py
@@ -6,7 +6,7 @@ from .views import (relatorio_capa_processo,
relatorio_etiqueta_protocolo, relatorio_materia,
relatorio_ordem_dia, relatorio_pauta_sessao,
relatorio_protocolo, relatorio_sessao_plenaria,
- resumo_ata_pdf)
+ resumo_ata_pdf, relatorio_sessao_plenaria_pdf)
app_name = AppConfig.name
@@ -31,4 +31,6 @@ urlpatterns = [
relatorio_pauta_sessao, name='relatorio_pauta_sessao'),
url(r'^relatorios/(?P\d+)/resumo_ata$',
resumo_ata_pdf, name='resumo_ata_pdf'),
+ url(r'^relatorios/(?P\d+)/sessao-plenaria-pdf$',
+ relatorio_sessao_plenaria_pdf, name='relatorio_sessao_plenaria_pdf'),
]
diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py
index cb1d05cca..be65f7b93 100755
--- a/sapl/relatorios/views.py
+++ b/sapl/relatorios/views.py
@@ -519,6 +519,9 @@ def get_sessao_plenaria(sessao, casa):
inf_basicas_dic["dat_fim_sessao"] = ''
inf_basicas_dic["hr_fim_sessao"] = sessao.hora_fim
inf_basicas_dic["nom_camara"] = casa.nome
+
+ if sessao.tipo.nome == 'Solene':
+ inf_basicas_dic["tema_solene"] = sessao.tema_solene
# Conteudo multimidia
cont_mult_dic = {}
@@ -1350,3 +1353,79 @@ def relatorio_doc_administrativos(request, context):
return response
+def relatorio_sessao_plenaria_pdf(request, pk):
+ base_url=request.build_absolute_uri()
+ logger = logging.getLogger(__name__)
+ username = request.user.username
+ casa = CasaLegislativa.objects.first()
+ if not casa:
+ raise Http404
+
+ rodape = get_rodape(casa)
+ rodape = ' '.join(rodape)
+
+ try:
+ logger.debug("user=" + username +
+ ". Tentando obter SessaoPlenaria com id={}.".format(pk))
+ sessao = SessaoPlenaria.objects.get(id=pk)
+ except ObjectDoesNotExist as e:
+ logger.error("user=" + username +
+ ". Essa SessaoPlenaria não existe (pk={}). ".format(pk) + str(e))
+ raise Http404('Essa página não existe')
+
+ (inf_basicas_dic,
+ cont_mult_dic,
+ lst_mesa,
+ lst_presenca_sessao,
+ lst_ausencia_sessao,
+ lst_expedientes,
+ lst_expediente_materia,
+ lst_expediente_materia_vot_nom,
+ lst_oradores_expediente,
+ lst_presenca_ordem_dia,
+ lst_votacao,
+ lst_votacao_vot_nom,
+ lst_oradores_ordemdia,
+ lst_oradores,
+ lst_ocorrencias) = get_sessao_plenaria(sessao, casa)
+
+ html_template = render_to_string('relatorios/relatorio_sessao_plenaria.html',
+ {
+ "inf_basicas_dic":inf_basicas_dic,
+ "lst_mesa":lst_mesa,
+ "lst_presenca_sessao":lst_presenca_sessao,
+ "lst_ausencia_sessao":lst_ausencia_sessao,
+ "lst_expedientes":lst_expedientes,
+ "lst_expediente_materia":lst_expediente_materia,
+ "lst_oradores_expediente":lst_oradores_expediente,
+ "lst_presenca_ordem_dia":lst_presenca_ordem_dia,
+ "lst_votacao":lst_votacao,
+ "lst_oradores":lst_oradores,
+ "lst_ocorrencias":lst_ocorrencias,
+ "rodape":rodape,
+ "data": dt.today().strftime('%d/%m/%Y')
+ })
+
+ info = "Resumo da {}ª Reunião {} \
+ da {}ª Sessão Legislativa da {} \
+ Legislatura".format(inf_basicas_dic['num_sessao_plen'],
+ inf_basicas_dic['nom_sessao'],
+ inf_basicas_dic['num_sessao_leg'],
+ inf_basicas_dic['num_legislatura'],
+ inf_basicas_dic['num_legislatura']
+ )
+
+ html_header = render_to_string('relatorios/header_ata.html',{"casa":casa,
+ "MEDIA_URL": MEDIA_URL,
+ "logotipo": casa.logotipo,
+ "info":info})
+
+ pdf_file = make_pdf(base_url=base_url, main_template=html_template, header_template=html_header)
+
+ response = HttpResponse(content_type='application/pdf;')
+ response['Content-Disposition'] = 'inline; filename=relatorio.pdf'
+ response['Content-Transfer-Encoding'] = 'binary'
+ response.write(pdf_file)
+
+ return response
+
diff --git a/sapl/rules/apps.py b/sapl/rules/apps.py
index c0dc19fd8..2247e5c94 100644
--- a/sapl/rules/apps.py
+++ b/sapl/rules/apps.py
@@ -84,18 +84,7 @@ def create_proxy_permissions(
ctypes.add(ctype)
- # FIXME: Retirar try except quando sapl passar a usar django 1.11
- try:
- logger.info("_get_all_permissions")
- # Função não existe mais em Django 1.11
- # como sapl ainda não foi para Django 1.11
- # esta excessão foi adicionada para caso o
- # Sapl esteja rodando em um projeto 1.11 não ocorra erros
- _all_perms_of_klass = _get_all_permissions(klass._meta, ctype)
- except Exception as e:
- logger.error(str(e))
- # Nova função usada em projetos com Django 1.11 e o sapl é uma app
- _all_perms_of_klass = _get_all_permissions(klass._meta)
+ _all_perms_of_klass = _get_all_permissions(klass._meta)
for perm in _all_perms_of_klass:
searched_perms.append((ctype, perm))
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
index 9b3fc1f90..01f0c3636 100644
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -11,6 +11,7 @@ from django.forms.widgets import CheckboxSelectMultiple
from django.utils.translation import ugettext_lazy as _
import django_filters
+from sapl.settings import MAX_DOC_UPLOAD_SIZE
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
@@ -149,6 +150,24 @@ class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm):
"entre a data de início e fim tanto da "
"Legislatura quanto da Sessão Legislativa.")
+
+ upload_pauta = self.cleaned_data.get('upload_pauta', False)
+ upload_ata = self.cleaned_data.get('upload_ata', False)
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_pauta and upload_pauta.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Pauta da Sessão deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_pauta.size/1024)/1024))
+
+ if upload_ata and upload_ata.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Ata da Sessão deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_ata.size/1024)/1024))
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo da Sessão deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
+
return self.cleaned_data
@@ -656,6 +675,12 @@ class OradorForm(ModelForm):
"Já existe orador nesta posição de ordem de pronunciamento"
))
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo do Orador deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
return self.cleaned_data
class Meta:
@@ -691,6 +716,12 @@ class OradorExpedienteForm(ModelForm):
raise ValidationError(_(
'Já existe orador nesta posição da ordem de pronunciamento'))
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo do Orador deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
return self.cleaned_data
class Meta:
@@ -728,6 +759,12 @@ class OradorOrdemDiaForm(ModelForm):
"Já existe orador nesta posição de ordem de pronunciamento"
))
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo do Orador deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
return self.cleaned_data
class Meta:
@@ -966,9 +1003,15 @@ class JustificativaAusenciaForm(ModelForm):
sessao_plenaria = self.instance.sessao_plenaria
+ upload_anexo = self.cleaned_data.get('upload_anexo', False)
+
+ if upload_anexo and upload_anexo.size > MAX_DOC_UPLOAD_SIZE:
+ raise ValidationError("O arquivo Anexo de Justificativa deve ser menor que {0:.1f} mb, o tamanho atual desse arquivo é {1:.1f} mb" \
+ .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (upload_anexo.size/1024)/1024))
+
if not sessao_plenaria.finalizada or sessao_plenaria.finalizada is None:
raise ValidationError(
- "A sessão deve está finalizada para registrar uma Ausência")
+ "A sessão deve estar finalizada para registrar uma Ausência")
else:
return self.cleaned_data
diff --git a/sapl/sessao/migrations/0041_sessaoplenaria_tema_solene.py b/sapl/sessao/migrations/0041_sessaoplenaria_tema_solene.py
new file mode 100644
index 000000000..8219d2c3c
--- /dev/null
+++ b/sapl/sessao/migrations/0041_sessaoplenaria_tema_solene.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-05-31 12:37
+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='sessaoplenaria',
+ name='tema_solene',
+ field=models.TextField(blank=True, max_length=500, verbose_name='Tema da Sessão Solene'),
+ ),
+ ]
diff --git a/sapl/sessao/migrations/0042_merge_20190612_0925.py b/sapl/sessao/migrations/0042_merge_20190612_0925.py
new file mode 100644
index 000000000..3ca598ee3
--- /dev/null
+++ b/sapl/sessao/migrations/0042_merge_20190612_0925.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2019-06-12 12:25
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0041_auto_20190610_1300'),
+ ('sessao', '0041_sessaoplenaria_tema_solene'),
+ ]
+
+ operations = [
+ ]
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index 8ab65ebfd..d438caa9a 100644
--- a/sapl/sessao/models.py
+++ b/sapl/sessao/models.py
@@ -208,6 +208,8 @@ class SessaoPlenaria(models.Model):
interativa = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão interativa'))
+ tema_solene = models.TextField(
+ blank=True, max_length=500, verbose_name=_('Tema da Sessão Solene'))
class Meta:
verbose_name = _('Sessão Plenária')
diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py
index c570dfde8..730469c29 100644
--- a/sapl/sessao/urls.py
+++ b/sapl/sessao/urls.py
@@ -33,7 +33,8 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
renumerar_materias_expediente,
sessao_legislativa_legislatura_ajax,
VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente,
- VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView)
+ VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView,
+ recuperar_nome_tipo_sessao)
from .apps import AppConfig
@@ -68,6 +69,9 @@ urlpatterns = [
recuperar_numero_sessao_view,
name='recuperar_numero_sessao_view'
),
+ url(r'^sessao/recuperar-nome-tipo-sessao/',
+ recuperar_nome_tipo_sessao,
+ name='recuperar_nome_tipo_sessao'),
url(r'^sessao/sessao-legislativa-legislatura-ajax/',
sessao_legislativa_legislatura_ajax,
name='sessao_legislativa_legislatura_ajax_view'),
@@ -173,7 +177,7 @@ urlpatterns = [
name='votacaonominalexpdetail'),
url(r'^sessao/(?P\d+)/matexp/votsimb/(?P\d+)/(?P\d+)$',
VotacaoExpedienteView.as_view(), name='votacaosimbolicaexp'),
- url(r'^sessao/(?P\d+)/matexp/votsec/view/(?P\d+)/(?P\d+)$',
+ url(r'^sessao/(?P\d+)/matexp/votsimb/view/(?P\d+)/(?P\d+)$',
VotacaoExpedienteEditView.as_view(), name='votacaosimbolicaexpedit'),
url(r'^sessao/(?P\d+)/matexp/votsec/(?P\d+)/(?P\d+)$',
VotacaoExpedienteView.as_view(), name='votacaosecretaexp'),
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
index 295f22543..271f0b3d3 100755
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -515,7 +515,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
form_class = OrdemDiaForm
def get_initial(self):
- initial = super(UpdateView, self).get_initial()
+ initial = super().get_initial()
initial['tipo_materia'] = self.object.materia.tipo.id
initial['numero_materia'] = self.object.materia.numero
initial['ano_materia'] = self.object.materia.ano
@@ -576,7 +576,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
form_class = ExpedienteMateriaForm
def get_initial(self):
- initial = super(CreateView, self).get_initial()
+ initial = super().get_initial()
initial['data_ordem'] = SessaoPlenaria.objects.get(
pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y')
max_numero_ordem = ExpedienteMateria.objects.filter(
@@ -594,7 +594,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
form_class = ExpedienteMateriaForm
def get_initial(self):
- initial = super(UpdateView, self).get_initial()
+ initial = super().get_initial()
initial['tipo_materia'] = self.object.materia.tipo.id
initial['numero_materia'] = self.object.materia.numero
initial['ano_materia'] = self.object.materia.ano
@@ -614,6 +614,15 @@ class OradorCrud(MasterDetailCrud):
class ListView(MasterDetailCrud.ListView):
ordering = ['numero_ordem', 'parlamentar']
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao_pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=sessao_pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm
@@ -625,18 +634,87 @@ class OradorCrud(MasterDetailCrud):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
- class UpdateView(MasterDetailCrud.UpdateView):
+class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
def get_initial(self):
- initial = super(UpdateView, self).get_initial()
+ initial = super().get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero': self.object.numero_ordem})
return initial
+class OradorExpedienteCrud(OradorCrud):
+ model = OradorExpediente
+
+ class CreateView(MasterDetailCrud.CreateView):
+
+ form_class = OradorForm
+
+ def get_initial(self):
+ return {'id_sessao': self.kwargs['pk']}
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao_pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=sessao_pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+ def get_success_url(self):
+ return reverse('sapl.sessao:orador_list',
+ kwargs={'pk': self.kwargs['pk']})
+
+
+ class UpdateView(MasterDetailCrud.UpdateView):
+
+ form_class = OradorForm
+
+ def get_initial(self):
+ initial = super().get_initial()
+ initial.update({'id_sessao': self.object.sessao_plenaria.id})
+ initial.update({'numero':self.object.numero_ordem})
+
+ return initial
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao_pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=sessao_pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+
+ class DetailView(MasterDetailCrud.DetailView):
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao_pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=sessao_pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+
+ class DeleteView(MasterDetailCrud.DeleteView):
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao_pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=sessao_pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+
class OradorExpedienteCrud(OradorCrud):
model = OradorExpediente
@@ -647,6 +725,17 @@ class OradorExpedienteCrud(OradorCrud):
def get_initial(self):
return {'id_sessao': self.kwargs['pk']}
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+
def get_success_url(self):
return reverse('sapl.sessao:oradorexpediente_list',
kwargs={'pk': self.kwargs['pk']})
@@ -659,6 +748,40 @@ class OradorExpedienteCrud(OradorCrud):
'numero': self.object.numero_ordem}
+ class ListView(MasterDetailCrud.ListView):
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+ class DetailView(MasterDetailCrud.DetailView):
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
+
+ class UpdateView(MasterDetailCrud.UpdateView):
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ pk = context['root_pk']
+ sessao = SessaoPlenaria.objects.get(id=pk)
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
class OradorOrdemDiaCrud(OradorCrud):
model = OradorOrdemDia
@@ -676,7 +799,7 @@ class OradorOrdemDiaCrud(OradorCrud):
form_class = OradorOrdemDiaForm
def get_initial(self):
- initial = super(UpdateView, self).get_initial()
+ initial = super().get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero': self.object.numero_ordem})
@@ -735,6 +858,16 @@ def sessao_legislativa_legislatura_ajax(request):
return JsonResponse({'sessao_legislativa': lista_sessoes})
+def recuperar_nome_tipo_sessao(request):
+ try:
+ tipo = TipoSessaoPlenaria.objects.get(pk=request.GET['tipo'])
+ tipo_nome = tipo.nome
+ except ObjectDoesNotExist:
+ tipo_nome = ''
+
+ return JsonResponse({'nome_tipo': tipo_nome})
+
+
class SessaoCrud(Crud):
model = SessaoPlenaria
help_topic = 'sessao_legislativa'
@@ -764,6 +897,18 @@ class SessaoCrud(Crud):
form_class = SessaoPlenariaForm
+ @property
+ def layout_key(self):
+ return 'SessaoSolene'
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ return context
+
def get_initial(self):
return {'sessao_legislativa': self.object.sessao_legislativa}
@@ -772,6 +917,10 @@ class SessaoCrud(Crud):
form_class = SessaoPlenariaForm
logger = logging.getLogger(__name__)
+ @property
+ def layout_key(self):
+ return 'SessaoSolene'
+
@property
def cancel_url(self):
return self.search_url
@@ -804,6 +953,26 @@ class SessaoCrud(Crud):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'sessaoplenaria_list'))
+ class DetailView(Crud.DetailView):
+
+ @property
+ def layout_key(self):
+ sessao = self.object
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ return 'SessaoSolene'
+ return 'SessaoPlenaria'
+
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+ # self.layout_key = 'SessaoSolene'
+ return context
+
class SessaoPermissionMixin(PermissionRequiredForAppCrudMixin,
FormMixin,
@@ -837,6 +1006,10 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s (%s) ' % (
_('Presença'), self.object)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
@method_decorator(permission_required(
@@ -921,17 +1094,23 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
cronometro_ordem = cronometro_ordem.seconds
cronometro_consideracoes = cronometro_consideracoes.seconds
+ sessao_pk = kwargs['pk']
+ sessao = SessaoPlenaria.objects.get(pk=sessao_pk)
context = TemplateView.get_context_data(self, **kwargs)
context.update({
'head_title': str(_('Painel Plenário')),
- 'sessao_id': kwargs['pk'],
- 'root_pk': kwargs['pk'],
- 'sessaoplenaria': SessaoPlenaria.objects.get(pk=kwargs['pk']),
+ 'sessao_id': sessao_pk,
+ 'root_pk': sessao_pk,
+ 'sessaoplenaria': sessao,
'cronometro_discurso': cronometro_discurso,
'cronometro_aparte': cronometro_aparte,
'cronometro_ordem': cronometro_ordem,
'cronometro_consideracoes': cronometro_consideracoes})
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
+
return context
@@ -1154,8 +1333,12 @@ class MesaView(FormMixin, DetailView):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s (%s) ' % (
_('Mesa Diretora'), self.object)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
-
+
def get_success_url(self):
pk = self.kwargs['pk']
return reverse('sapl.sessao:mesa', kwargs={'pk': pk})
@@ -1363,14 +1546,18 @@ def get_identificação_basica(sessao_plenaria):
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
data_fim = sessao_plenaria.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
- return({'basica': [
+ tema_solene = sessao_plenaria.tema_solene
+ context = {'basica': [
_('Tipo de Sessão: %(tipo)s') % {'tipo': sessao_plenaria.tipo},
_('Abertura: %(abertura)s - %(hora_inicio)s') % {
'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio},
_('Encerramento: %(encerramento)s %(hora_fim)s') % {
- 'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim}
- ],
- 'sessaoplenaria': sessao_plenaria})
+ 'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim},
+ ],
+ 'sessaoplenaria': sessao_plenaria}
+ if sessao_plenaria.tipo.nome == "Solene" and tema_solene:
+ context.update({'tema_solene': 'Tema da Sessão Solene: %s' % tema_solene})
+ return context
def get_conteudo_multimidia(sessao_plenaria):
@@ -1531,10 +1718,11 @@ def get_assinaturas(sessao_plenaria):
context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_mesa': mesa_dia})
- elif config_assinatura_ata == 'P' and presidente_dia:
+ elif config_assinatura_ata == 'P' and presidente_dia and presidente_dia[0]:
context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'})
- context.update({'assinatura_mesa': presidente_dia})
+ assinatura_presidente = [{'parlamentar': presidente_dia[0], 'cargo': "Presidente"}]
+ context.update({'assinatura_mesa': assinatura_presidente})
return context
@@ -1824,6 +2012,11 @@ class ResumoView(DetailView):
'decimo_terceiro_ordenacao': 'oradores_explicacoes.html',
'decimo_quarto_ordenacao': 'ocorrencias_da_sessao.html'
})
+
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
def get(self, request, *args, **kwargs):
@@ -1848,6 +2041,10 @@ class ExpedienteView(FormMixin, DetailView):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s (%s) ' % (
_('Expediente Diversos'), self.object)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
@method_decorator(permission_required('sessao.add_expedientesessao'))
@@ -1937,6 +2134,10 @@ class OcorrenciaSessaoView(FormMixin, DetailView):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = 'Ocorrências da Sessão (%s) ' % (
self.object)
+ sessao = context['object']
+ tipo_sessao = sessao.tipo
+ if tipo_sessao.nome == "Solene":
+ context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
def delete(self):
@@ -2662,8 +2863,7 @@ class VotacaoNominalTransparenciaDetailView(TemplateView):
template_name = 'sessao/votacao/nominal_transparencia.html'
def get_context_data(self, **kwargs):
- context = super(VotacaoNominalTransparenciaDetailView,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
materia_votacao = self.request.GET.get('materia', None)
@@ -2747,8 +2947,7 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
template_name = 'sessao/votacao/simbolica_transparencia.html'
def get_context_data(self, **kwargs):
- context = super(VotacaoSimbolicaTransparenciaDetailView,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
materia_votacao = self.request.GET.get('materia', None)
@@ -3015,7 +3214,7 @@ class SessaoListView(ListView):
return SessaoPlenaria.objects.all().order_by('-data_inicio')
def get_context_data(self, **kwargs):
- context = super(SessaoListView, self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
@@ -3179,8 +3378,7 @@ class PesquisarSessaoPlenariaView(FilterView):
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
- super(PesquisarSessaoPlenariaView,
- self).get_filterset_kwargs(filterset_class)
+ super().get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
@@ -3196,8 +3394,7 @@ class PesquisarSessaoPlenariaView(FilterView):
return kwargs
def get_context_data(self, **kwargs):
- context = super(PesquisarSessaoPlenariaView,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
context['title'] = _('Pesquisar Sessão Plenária')
paginator = context['paginator']
@@ -3209,7 +3406,7 @@ class PesquisarSessaoPlenariaView(FilterView):
return context
def get(self, request, *args, **kwargs):
- super(PesquisarSessaoPlenariaView, self).get(request)
+ super().get(request)
# Se a pesquisa estiver quebrando com a paginação
# Olhe esta função abaixo
@@ -3247,8 +3444,7 @@ class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
logger.debug('Pesquisa de PautaSessao.')
def get_context_data(self, **kwargs):
- context = super(PesquisarPautaSessaoView,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
context['title'] = _('Pesquisar Pauta de Sessão')
return context
@@ -3269,8 +3465,7 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
- super(AdicionarVariasMateriasExpediente,
- self).get_filterset_kwargs(filterset_class)
+ super().get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
@@ -3294,8 +3489,7 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
return kwargs
def get_context_data(self, **kwargs):
- context = super(MateriaLegislativaPesquisaView,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
context['title'] = _('Pesquisar Matéria Legislativa')
context['root_pk'] = self.kwargs['pk']
@@ -3362,8 +3556,7 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
logger = logging.getLogger(__name__)
def get_filterset_kwargs(self, filterset_class):
- super(AdicionarVariasMateriasExpediente,
- self).get_filterset_kwargs(filterset_class)
+ super().get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
@@ -3581,8 +3774,7 @@ class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
retiradapauta=None)
def get_context_data(self, **kwargs):
- context = super(VotacaoEmBlocoExpediente,
- self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk']
if not verifica_sessao_iniciada(self.request, self.kwargs['pk']):
diff --git a/sapl/settings.py b/sapl/settings.py
index 1167d33f3..07b2d6904 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.158'
+SAPL_VERSION = '3.1.159'
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@@ -239,7 +239,7 @@ DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='')
SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='')
EMAIL_RUNNING = None
-MAX_DOC_UPLOAD_SIZE = 60 * 1024 * 1024 # 60MB
+MAX_DOC_UPLOAD_SIZE = 80 * 1024 * 1024 # 80MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# Internationalization
diff --git a/sapl/static/sapl/css/relatorio.css b/sapl/static/sapl/css/relatorio.css
index b51a40c2b..6fd166c99 100644
--- a/sapl/static/sapl/css/relatorio.css
+++ b/sapl/static/sapl/css/relatorio.css
@@ -1,5 +1,5 @@
@page{
- margin-top: 4.5cm;
+ margin-top: 5.2cm;
size: A4 portrait;
}
@@ -53,4 +53,41 @@ fieldset {
page-break-after: avoid;
margin:5px;
padding:0px;
-}
\ No newline at end of file
+}
+
+
+table {
+ max-width: 520px;
+}
+table.grayTable {
+ border: 1px solid #6e6e6e;
+ width: 100%;
+ text-align: left;
+ border-collapse: collapse;
+}
+table.grayTable td, table.grayTable th {
+ border: 1px solid #000000;
+}
+table.grayTable tbody td {
+ font-size: 10px;
+ max-width: 80px;
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ text-align: justify;
+}
+table.grayTable tr:nth-child(even) {
+ background: #dddddd;
+}
+table.grayTable thead {
+ background: #BBBBBB;
+ border-bottom: 2px solid #000000;
+}
+table.grayTable thead th {
+ font-size:10px;
+ color: rgb(0, 0, 0);
+ border-left: 1px solid #000000;
+
+}
+table.grayTable thead th:first-child {
+ border-left: none;
+}
\ No newline at end of file
diff --git a/sapl/templates/base.html b/sapl/templates/base.html
index 0df0d6dee..653677a32 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.158
+ Release: 3.1.159
diff --git a/sapl/templates/base/RelatorioAtas_filter.html b/sapl/templates/base/RelatorioAtas_filter.html
index adc494431..9eab9ae8f 100644
--- a/sapl/templates/base/RelatorioAtas_filter.html
+++ b/sapl/templates/base/RelatorioAtas_filter.html
@@ -1,6 +1,7 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags staticfiles %}
+{% load webpack_static from webpack_loader %}
{% block base_content %}
{% if not filter_url %}
@@ -26,7 +27,7 @@
{{sessao}}
-
+
{% endfor %}
diff --git a/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html
index 0960a958b..caa585a82 100644
--- a/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html
+++ b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html
@@ -14,7 +14,7 @@
PARÂMETROS DE PESQUISA:
Período: {{ data_tramitacao }}
Tipo de matéria: {{ tipo }}
- Status atual: {{ tramitacao__status }}
+ Status de tramitação: {{ tramitacao__status }}
Local de origem: {{ tramitacao__unidade_tramitacao_local }}
Local de destino: {{ tramitacao__unidade_tramitacao_destino }}
{% if object_list %}
diff --git a/sapl/templates/base/RelatorioPresencaSessao_filter.html b/sapl/templates/base/RelatorioPresencaSessao_filter.html
index 71032d36a..c3ad733af 100644
--- a/sapl/templates/base/RelatorioPresencaSessao_filter.html
+++ b/sapl/templates/base/RelatorioPresencaSessao_filter.html
@@ -20,34 +20,93 @@
PERÍODO: {{periodo}}
- TOTAIS NO PERÍODO - SESSÕES: {{total_sessao}} - ORDENS DO DIA: {{total_ordemdia}}
+ Legislatura: {{legislatura}}
+ Sessão Legislativa: {{sessao_legislativa}}
+ Tipo Sessão Plenária: {{tipo}}
+ TOTAIS NO PERÍODO - SESSÕES: {{total_sessao}} - ORDENS DO DIA: {{total_ordemdia}}
+ Exibir presença das Ordens do Dia: {% if exibir_ordem %} Sim {% else %} Não {% endif %}
Nome Parlamentar / Partido
- Titular
+ Titular?
+ Ativo?
Sessão
- Ordem do Dia
+ {% if exibir_ordem %} Ordem do Dia {% endif %}
(Qtd)
( % )
- (Qtd)
- ( % )
+ {% if exibir_ordem %}
+ (Qtd)
+ ( % )
+ {% endif %}
{% for p in parlamentares %}
{{p.parlamentar}} / {{p.parlamentar|filiacao_intervalo_filter:date_range|default:"Sem Partido"}}
- {%if p.titular %} Sim {% else %} Não {% endif %}
+ {% if p.titular %} Sim {% else %} Não {% endif %}
+ {% if p.parlamentar.ativo %} Sim {% else %} Não {% endif %}
{{p.sessao_count}}
{{p.sessao_porc}}
- {{p.ordemdia_count}}
- {{p.ordemdia_porc}}
+ {% if exibir_ordem %}
+ {{p.ordemdia_count}}
+ {{p.ordemdia_porc}}
+ {% endif %}
{% endfor %}
{% endif %}
{% endblock base_content %}
+
+{% block extra_js %}
+
+
+
+{% endblock %}
diff --git a/sapl/templates/base/anexadas_ciclicas.html b/sapl/templates/base/anexadas_ciclicas.html
new file mode 100644
index 000000000..9008d3428
--- /dev/null
+++ b/sapl/templates/base/anexadas_ciclicas.html
@@ -0,0 +1,35 @@
+{% extends "base.html" %}
+{% load common_tags %}
+{% block base_content %}
+
+ Lista de Matérias Anexadas Cíclicas
+
+ {% if not anexadas_ciclicas %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Matéria Fim do Ciclo
+ Matéria Início do Ciclo
+
+
+
+ {% for data, fim, inicio in anexadas_ciclicas %}
+
+ {{ data }}
+
+ {{ fim }}
+
+
+ {{ inicio }}
+
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
+{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/anexados_ciclicos.html b/sapl/templates/base/anexados_ciclicos.html
new file mode 100644
index 000000000..0e98659d3
--- /dev/null
+++ b/sapl/templates/base/anexados_ciclicos.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+{% load common_tags %}
+{% block base_content %}
+
+ Lista de Documentos Anexados Cíclicos
+
+ {% if not anexados_ciclicos %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Data Anexação
+ Documento Fim do Ciclo
+ Documento Início do Ciclo
+
+
+
+ {% for data, fim, inicio in anexados_ciclicos %}
+
+ {{ data }}
+
+ {{ fim }}
+
+
+ {{ inicio }}
+
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
+{% endblock base_content %}
diff --git a/sapl/templates/base/autores_duplicados.html b/sapl/templates/base/autores_duplicados.html
index 361ff7add..0b9234429 100644
--- a/sapl/templates/base/autores_duplicados.html
+++ b/sapl/templates/base/autores_duplicados.html
@@ -1,30 +1,30 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Autores Duplicados
-
- {% if not autores_duplicados %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Autor
- Quantidade
-
-
-
- {% for autor in autores_duplicados %}
-
- {{ autor.nome }}
- {{ autor.count }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Autores Duplicados
+
+ {% if not autores_duplicados %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Autor
+ Quantidade
+
+
+
+ {% for autor in autores_duplicados %}
+
+ {{ autor.nome }}
+ {{ autor.count }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/bancada_comissao_autor_externo.html b/sapl/templates/base/bancada_comissao_autor_externo.html
index 9edaf21f7..15789ae10 100644
--- a/sapl/templates/base/bancada_comissao_autor_externo.html
+++ b/sapl/templates/base/bancada_comissao_autor_externo.html
@@ -1,36 +1,36 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Bancadas e Comissões com Autor Externo
-
- {% if not bancada_comissao_autor_externo %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Descrição do Objeto
- Objeto
- Autor
-
-
-
- {% for autor, objeto, descricao_objeto, link in bancada_comissao_autor_externo %}
-
- {{ descricao_objeto }}
-
- {{ objeto }}
-
-
- {{ autor.nome }}
-
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Bancadas e Comissões com Autor Externo
+
+ {% if not bancada_comissao_autor_externo %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Descrição do Objeto
+ Objeto
+ Autor
+
+
+
+ {% for autor, objeto, descricao_objeto, link in bancada_comissao_autor_externo %}
+
+ {{ descricao_objeto }}
+
+ {{ objeto }}
+
+
+ {{ autor.nome }}
+
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/filiacoes_sem_data_filiacao.html b/sapl/templates/base/filiacoes_sem_data_filiacao.html
index 22d24f972..949306def 100644
--- a/sapl/templates/base/filiacoes_sem_data_filiacao.html
+++ b/sapl/templates/base/filiacoes_sem_data_filiacao.html
@@ -1,32 +1,32 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Filiações sem Data Filiação
-
- {% if not filiacoes_sem_data_filiacao %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Parlamentar Filiado
- Partido
-
-
-
- {% for filiacao in filiacoes_sem_data_filiacao %}
-
-
- {{ filiacao.parlamentar }}
-
- {{ filiacao.partido }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Filiações sem Data Filiação
+
+ {% if not filiacoes_sem_data_filiacao %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Parlamentar Filiado
+ Partido
+
+
+
+ {% for filiacao in filiacoes_sem_data_filiacao %}
+
+
+ {{ filiacao.parlamentar }}
+
+ {{ filiacao.partido }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/legislatura_infindavel.html b/sapl/templates/base/legislatura_infindavel.html
index a44c544e1..05a708ae9 100644
--- a/sapl/templates/base/legislatura_infindavel.html
+++ b/sapl/templates/base/legislatura_infindavel.html
@@ -1,32 +1,32 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Legislaturas sem Data Fim
-
- {% if not legislatura_infindavel %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Número Legislatura
- Data Eleição
- Data Início
-
-
-
- {% for legislatura in legislatura_infindavel %}
-
- {{ legislatura.numero }}
- {{ legislatura.data_eleicao }}
- {{ legislatura.data_inicio }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Legislaturas sem Data Fim
+
+ {% if not legislatura_infindavel %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Número Legislatura
+ Data Eleição
+ Data Início
+
+
+
+ {% for legislatura in legislatura_infindavel %}
+
+ {{ legislatura.numero }}
+ {{ legislatura.data_eleicao }}
+ {{ legislatura.data_inicio }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/lista_inconsistencias.html b/sapl/templates/base/lista_inconsistencias.html
index 121422ade..309495199 100644
--- a/sapl/templates/base/lista_inconsistencias.html
+++ b/sapl/templates/base/lista_inconsistencias.html
@@ -1,22 +1,22 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Inconsistências
-
-
-
- {% for complemento_link, nome, valor in tabela_inconsistencias %}
-
-
- {{ nome }}
-
- {{ valor }}
-
- {% endfor %}
-
-
-
- {% include 'paginacao.html'%}
+
+ Lista de Inconsistências
+
+
+
+ {% for complemento_link, nome, valor in tabela_inconsistencias %}
+
+
+ {{ nome }}
+
+ {{ valor }}
+
+ {% endfor %}
+
+
+
+ {% include 'paginacao.html' %}
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/mandato_sem_data_inicio.html b/sapl/templates/base/mandato_sem_data_inicio.html
index 09c151d7a..00837e03f 100644
--- a/sapl/templates/base/mandato_sem_data_inicio.html
+++ b/sapl/templates/base/mandato_sem_data_inicio.html
@@ -1,32 +1,32 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Mandatos sem Data Inicial
-
- {% if not mandato_sem_data_inicio %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Parlamentar do Mandato
- Legislatura do Mandato
-
-
-
- {% for mandato in mandato_sem_data_inicio %}
-
-
- {{ mandato.parlamentar }}
-
- {{ mandato.legislatura }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Mandatos sem Data Inicial
+
+ {% if not mandato_sem_data_inicio %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Parlamentar do Mandato
+ Legislatura do Mandato
+
+
+
+ {% for mandato in mandato_sem_data_inicio %}
+
+
+ {{ mandato.parlamentar }}
+
+ {{ mandato.legislatura }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/materias_protocolo_inexistente.html b/sapl/templates/base/materias_protocolo_inexistente.html
index 879a6d460..059053b06 100644
--- a/sapl/templates/base/materias_protocolo_inexistente.html
+++ b/sapl/templates/base/materias_protocolo_inexistente.html
@@ -1,34 +1,34 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Matérias Legislativas com Protocolo Inexistente
-
- {% if not materias_protocolo_inexistente %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Matéria Legislativa
- Ano
- Número Protocolo
-
-
-
- {% for materia, ano, numero_protocolo in materias_protocolo_inexistente %}
-
-
- {{ materia }}
-
- {{ ano }}
- {{ numero_protocolo }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Matérias Legislativas com Protocolo Inexistente
+
+ {% if not materias_protocolo_inexistente %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Matéria Legislativa
+ Ano
+ Número Protocolo
+
+
+
+ {% for materia, ano, numero_protocolo in materias_protocolo_inexistente %}
+
+
+ {{ materia }}
+
+ {{ ano }}
+ {{ numero_protocolo }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/parlamentares_duplicados.html b/sapl/templates/base/parlamentares_duplicados.html
index 2e63a04bc..0bb86e2ce 100644
--- a/sapl/templates/base/parlamentares_duplicados.html
+++ b/sapl/templates/base/parlamentares_duplicados.html
@@ -1,32 +1,32 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Parlamentares Duplicados
-
- {% if not parlamentares_duplicados %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Nome do Parlamentar
- Quantidade
-
-
-
- {% for parlamentar, quantidade in parlamentares_duplicados %}
-
-
- {{ parlamentar }}
-
- {{ quantidade }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Parlamentares Duplicados
+
+ {% if not parlamentares_duplicados %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Nome do Parlamentar
+ Quantidade
+
+
+
+ {% for quantidade, parlamentar in parlamentares_duplicados %}
+
+
+ {{ parlamentar }}
+
+ {{ quantidade }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/parlamentares_filiacoes_intersecao.html b/sapl/templates/base/parlamentares_filiacoes_intersecao.html
index b0949e05a..80dedd41a 100644
--- a/sapl/templates/base/parlamentares_filiacoes_intersecao.html
+++ b/sapl/templates/base/parlamentares_filiacoes_intersecao.html
@@ -1,34 +1,34 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Parlamentares com Filiações com Interseção
-
- {% if not parlamentares_filiacoes_intersecao %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Parlamentar
- Filiação 1
- Filiação 2
-
-
-
- {% for parlamentar, filiacao_a , filiacao_b in parlamentares_filiacoes_intersecao %}
-
-
- {{ parlamentar }}
-
- {{filiacao_a.data|date:"d/m/Y"}} - {{filiacao_a.data_desfiliacao|date:"d/m/Y"}}
- {{filiacao_b.data|date:"d/m/Y"}} - {{filiacao_b.data_desfiliacao|date:"d/m/Y"}}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Parlamentares com Filiações com Interseção
+
+ {% if not parlamentares_filiacoes_intersecao %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Parlamentar
+ Filiação 1
+ Filiação 2
+
+
+
+ {% for parlamentar, filiacao_a , filiacao_b in parlamentares_filiacoes_intersecao %}
+
+
+ {{ parlamentar }}
+
+ {{ filiacao_a.data|date:"d/m/Y" }} - {{ filiacao_a.data_desfiliacao|date:"d/m/Y" }}
+ {{ filiacao_b.data|date:"d/m/Y" }} - {{ filiacao_b.data_desfiliacao|date:"d/m/Y" }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/parlamentares_mandatos_intersecao.html b/sapl/templates/base/parlamentares_mandatos_intersecao.html
index 2d4c915a4..5ba19017b 100644
--- a/sapl/templates/base/parlamentares_mandatos_intersecao.html
+++ b/sapl/templates/base/parlamentares_mandatos_intersecao.html
@@ -1,34 +1,34 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Parlamentares com Mandatos em Interseção
-
- {% if not parlamentares_mandatos_intersecao %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Parlamentar
- Mandato 1
- Mandato 2
-
-
-
- {% for parlamentar, mandato_a, mandato_b in parlamentares_mandatos_intersecao %}
-
-
- {{ parlamentar }}
-
- {{ mandato_a.legislatura}}{{mandato_a.data_inicio_mandato|date:"d/m/Y"}} - {{mandato_a.data_fim_mandato|date:"d/m/Y"}}
- {{ mandato_b.legislatura }}{{mandato_b.data_inicio_mandato|date:"d/m/Y"}} - {{mandato_b.data_fim_mandato|date:"d/m/Y"}}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Parlamentares com Mandatos em Interseção
+
+ {% if not parlamentares_mandatos_intersecao %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Parlamentar
+ Mandato 1
+ Mandato 2
+
+
+
+ {% for parlamentar, mandato_a, mandato_b in parlamentares_mandatos_intersecao %}
+
+
+ {{ parlamentar }}
+
+ {{ mandato_a.legislatura }}{{ mandato_a.data_inicio_mandato|date:"d/m/Y" }} - {{ mandato_a.data_fim_mandato|date:"d/m/Y" }}
+ {{ mandato_b.legislatura }}{{ mandato_b.data_inicio_mandato|date:"d/m/Y" }} - {{ mandato_b.data_fim_mandato|date:"d/m/Y" }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/protocolos_com_materias.html b/sapl/templates/base/protocolos_com_materias.html
index 1e98bad5c..25a88e49a 100644
--- a/sapl/templates/base/protocolos_com_materias.html
+++ b/sapl/templates/base/protocolos_com_materias.html
@@ -1,30 +1,30 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Protocolos que Excedem o Limite de Matérias Vinculadas
-
- {% if not protocolos_com_materias %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Protocolo
- Quantidade de Matérias Vinculas
-
-
-
- {% for materia, quantidade in protocolos_com_materias %}
-
- {{ materia.numero_protocolo }}/{{ materia.ano }}
- {{ quantidade }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Protocolos que Excedem o Limite de Matérias Vinculadas
+
+ {% if not protocolos_com_materias %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Protocolo
+ Quantidade de Matérias Vinculas
+
+
+
+ {% for materia, quantidade in protocolos_com_materias %}
+
+ {{ materia.numero_protocolo }}/{{ materia.ano }}
+ {{ quantidade }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/protocolos_duplicados.html b/sapl/templates/base/protocolos_duplicados.html
index 15056991f..6a45a0045 100644
--- a/sapl/templates/base/protocolos_duplicados.html
+++ b/sapl/templates/base/protocolos_duplicados.html
@@ -1,32 +1,32 @@
{% extends "base.html" %}
{% load common_tags %}
{% block base_content %}
-
- Lista de Protocolos Duplicados
-
- {% if not protocolos_duplicados %}
- {{ NO_ENTRIES_MSG }}
- {% else %}
-
-
-
- Protocolo
- Quantidade
-
-
-
- {% for protocolo, quantidade in protocolos_duplicados %}
-
-
- {{ protocolo }}
-
- {{ quantidade }}
-
- {% endfor %}
-
-
- {% endif %}
-
- {% include 'paginacao.html'%}
-
+
+ Lista de Protocolos Duplicados
+
+ {% if not protocolos_duplicados %}
+ {{ NO_ENTRIES_MSG }}
+ {% else %}
+
+
+
+ Protocolo
+ Quantidade
+
+
+
+ {% for protocolo, quantidade in protocolos_duplicados %}
+
+
+ {{ protocolo }}
+
+ {{ quantidade }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% include 'paginacao.html' %}
+
{% endblock base_content %}
\ No newline at end of file
diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html
index 5ac6d4d77..c2fcf4d0d 100644
--- a/sapl/templates/base/relatorios_list.html
+++ b/sapl/templates/base/relatorios_list.html
@@ -37,8 +37,8 @@
Histórico de tramitações por período e local informados.
- Tramitações de Matérias por fim de prazo
- Tramitações com fim de prazo no intervalo informado.
+ Tramitações de Matérias
+ Tramitações de matéria com status informado no intervalo.
Reunião de Comissão
diff --git a/sapl/templates/comissoes/reuniao_detail.html b/sapl/templates/comissoes/reuniao_detail.html
index c8c32cd98..be4152e44 100644
--- a/sapl/templates/comissoes/reuniao_detail.html
+++ b/sapl/templates/comissoes/reuniao_detail.html
@@ -1,4 +1,4 @@
-{% extends "crud/detail.html" %}
+{% extends "crud/detail_detail.html" %}
{% load i18n %}
{% block detail_content %}
diff --git a/sapl/templates/crud/detail.html b/sapl/templates/crud/detail.html
index 0058fc917..2d4f86b91 100644
--- a/sapl/templates/crud/detail.html
+++ b/sapl/templates/crud/detail.html
@@ -72,13 +72,21 @@
Este navegador não suporta o elemento áudio.
- {% elif column.text|video_url %}
+ {% elif column.text|is_video_url %}
+ {% elif column.text|youtube_url %}
+ VIDEO
+ {% elif column.text|facebook_url %}
+
+
{% elif column.text|url %}
{% else %}
@@ -131,4 +139,7 @@
{% endblock table_content %}
{% endblock base_content %}
-{% block extra_js %}{% endblock %}
+{% block extra_js %}
+
+
+{% endblock %}
diff --git a/sapl/templates/floppyforms/image_thumbnail.html b/sapl/templates/floppyforms/image_thumbnail.html
index 7d7b414a1..79d0f40db 100644
--- a/sapl/templates/floppyforms/image_thumbnail.html
+++ b/sapl/templates/floppyforms/image_thumbnail.html
@@ -1,5 +1,5 @@
{% load i18n staticfiles thumbnail %}
-
+{% load webpack_static from webpack_loader %}
diff --git a/sapl/templates/materia/despachoinicial_multicreate_form.html b/sapl/templates/materia/despachoinicial_multicreate_form.html
new file mode 100644
index 000000000..2d1045d09
--- /dev/null
+++ b/sapl/templates/materia/despachoinicial_multicreate_form.html
@@ -0,0 +1,7 @@
+{% extends "crud/form.html" %}
+{% load i18n %}
+{% load crispy_forms_tags %}
+{% load common_tags %}
+
+{% block extra_js %}
+{% endblock %}
diff --git a/sapl/templates/materia/em_lote/acessorio.html b/sapl/templates/materia/em_lote/acessorio.html
index 89fc2fff8..a2afa460d 100644
--- a/sapl/templates/materia/em_lote/acessorio.html
+++ b/sapl/templates/materia/em_lote/acessorio.html
@@ -22,7 +22,7 @@
Tipo*
-
+
{% for t in tipos_docs %} {{t}} {% endfor %}
@@ -31,14 +31,14 @@
@@ -47,7 +47,7 @@
@@ -65,7 +65,7 @@
diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html
index 5cc4a0b90..1c68274e6 100644
--- a/sapl/templates/materia/em_lote/tramitacao.html
+++ b/sapl/templates/materia/em_lote/tramitacao.html
@@ -1,134 +1,28 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
-{% block actions %}{% endblock %}
{% block detail_content %}
- {% if not show_results %}
- {% crispy filter.form %}
- {% endif %}
-
- {% if show_results %}
- {% if object_list|length > 0 %}
- {% if object_list|length == 1 %}
- {% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}
- {% else %}
- Foram encontradas {{object_list|length}} matérias.
- {% endif %}
-
+ {% if not show_results %}
+ {% crispy filter.form %}
{% else %}
- Nenhuma matéria encontrada.
- {% endif %}
- {% endif %}
+ {% if object_list|length > 0 %}
+ {% if object_list|length == 1 %}
+ {% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}
+ {% else %}
+ Foram encontradas {{object_list|length}} matérias.
+ {% endif %}
+ {% crispy form %}
+ {% else %}
+ Nenhuma matéria encontrada.
+ {% endif %}
+
+ {% endif%}
{% endblock detail_content %}
+
{% block extra_js %}
{% endblock %}
diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml
index 5d50d2122..b5e11a036 100644
--- a/sapl/templates/navbar.yaml
+++ b/sapl/templates/navbar.yaml
@@ -35,7 +35,7 @@
url: sapl.protocoloadm:pesq_doc_adm
- title: {% trans 'Tramitação em Lote' %}
url: sapl.protocoloadm:primeira_tramitacao_em_lote_docadm
- check_permission: sapl.protocoloadm:add_tramitacaoadministrativo
+ check_permission: protocoloadm.add_tramitacaoadministrativo
- title: {% trans 'Atividade Legislativa' %}
children:
diff --git a/sapl/templates/norma/normajuridica_detail.html b/sapl/templates/norma/normajuridica_detail.html
index e45a7e486..7d8509830 100644
--- a/sapl/templates/norma/normajuridica_detail.html
+++ b/sapl/templates/norma/normajuridica_detail.html
@@ -87,6 +87,38 @@
+
+
+ {% if user.is_superuser %}
+
+ {% if object.user %}
+
+ {% endif %}
+ {% if object.ip %}
+
+ {% endif %}
+
+ {% endif %}
{% if object.texto_articulado.exists and object.texto_articulado.first.has_view_permission %}
diff --git a/sapl/templates/norma/normajuridica_form.html b/sapl/templates/norma/normajuridica_form.html
index 4c29fc98b..91531c4d1 100644
--- a/sapl/templates/norma/normajuridica_form.html
+++ b/sapl/templates/norma/normajuridica_form.html
@@ -57,6 +57,54 @@
numeroField.val(numero.replace(/^0+/, ''));
}
});
+
+ var modal_estilos = 'display: block;'
+ +'width: 85%; max-width: 600px;'
+ +'background: #fff; padding: 15px;'
+ +'border-radius: 5px;'
+ +'-webkit-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);'
+ +'-moz-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);'
+ +'box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);'
+ +'position: fixed;'
+ +'top: 50%; left: 50%;'
+ +'transform: translate(-50%,-50%);'
+ +'z-index: 99999999; text-align: center';
+
+ var fundo_modal_estilos = 'top: 0; right: 0;'
+ +'bottom: 0; left: 0; position: fixed;'
+ +'background-color: rgba(0, 0, 0, 0.6); z-index: 99999999;'
+ +'display: none;';
+
+ var meu_modal = '
'
+ +'
'
+ +'
Atenção! Ano de apresentação e ano da norma são diferentes. '
+ +''
+ +'Compreendo e quero continuar '
+ +'';
+
+ function verifica_ano(){
+ let ano = $("select#id_ano.select").val();
+ let data_apresentacao = $("input#id_data.dateinput").val();
+ let ano_apresentacao = data_apresentacao.substr(data_apresentacao.length - 4);
+
+ if(ano && ano_apresentacao && ano_apresentacao != ano){
+ $('#fundo_modal').fadeIn();
+ }
+ }
+
+ $(document).ready(function() {
+ $("body").append(meu_modal);
+
+ $("#fundo_modal, #close_model_btn").click(function(){ $("#fundo_modal").hide(); });
+ $("#meu_modal").click(function(e){ e.stopPropagation(); });
+
+ $("select#id_ano.select.form-control").blur(function(){
+ verifica_ano();
+ });
+ $("input#id_data.dateinput.form-control").blur(function(){
+ verifica_ano();
+ });
+ });
{% endblock %}
diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html
index 476e700c8..217a09053 100644
--- a/sapl/templates/painel/index.html
+++ b/sapl/templates/painel/index.html
@@ -89,17 +89,22 @@
Considerações Finais:
-
-
+
+
Resultado
-
-
+
+
+
+
+
+
Matéria em Votação
+
+
-
-
Matéria em Votação
-
-
+
+
Tema da Sessão Solene
+
@@ -234,6 +239,7 @@
$("#sessao_plenaria").text(data["sessao_plenaria"])
$("#sessao_plenaria_data").text("Data Início: " + data["sessao_plenaria_data"])
$("#sessao_plenaria_hora_inicio").text("Hora Início: " + data["sessao_plenaria_hora_inicio"])
+ $("#sessao_solene_tema").text(data["tema_solene"])
if (data["status_painel"] == false) {
$("#message").text("PAINEL ENCONTRA-SE FECHADO");
}
@@ -241,6 +247,12 @@
$("#message").text("");
}
+ if (data["sessao_solene"]){
+ $("#resultado_votacao_div").hide();
+ $("#obs_materia_div").hide();
+ $('#tema_solene_div').show();
+ }
+
if (data["brasao"] != null)
$("#logo-painel").attr("src", data["brasao"]);
@@ -381,7 +393,11 @@
audioAlertFinish.play();
}
- if (data['materia_legislativa_texto']){
+ if(data['sessao_finalizada']){
+ $("#obs_materia_div").hide();
+ $("#resultado_votacao_div").hide();
+ }
+ else if (data['materia_legislativa_texto']){
if (data["status_painel"] == true){
$("#materia_legislativa_texto").text(data["materia_legislativa_texto"]);
}
@@ -410,15 +426,18 @@
$("#resultado_votacao").text(data["tipo_resultado"]);
$("#resultado_votacao").css("color", "#45919D");
var resultado_votacao_upper = $("#resultado_votacao").text().toUpperCase();
- if (resultado_votacao_upper.search("APROV") != -1){
- $("#resultado_votacao").css("color", "green");
- }
- if (resultado_votacao_upper.search("REJEIT") != -1){
- $("#resultado_votacao").css("color", "red");
- }
+ if (resultado_votacao_upper.search("APROV") != -1){
+ $("#resultado_votacao").css("color", "green");
+ $("#mat_em_votacao").text("Matéria Votada");
+ }
+ if (resultado_votacao_upper.search("REJEIT") != -1){
+ $("#resultado_votacao").css("color", "red");
+ $("#mat_em_votacao").text("Matéria Votada");
+ }
}
else{
$("#resultado_votacao").text('');
+ $("#mat_em_votacao").text("Matéria em Votação");
}
},
error: function(err) {
diff --git a/sapl/templates/painel/voto_nominal.html b/sapl/templates/painel/voto_nominal.html
index aa1a8f9cf..ecd915c25 100644
--- a/sapl/templates/painel/voto_nominal.html
+++ b/sapl/templates/painel/voto_nominal.html
@@ -90,25 +90,23 @@
{% csrf_token %}
-
{% else %}
@@ -139,11 +137,13 @@
document.getElementById("date").innerHTML = n;
$(window).on('beforeunload', function () {
- $("input[type=submit], input[type=button]").prop("disabled", "disabled");
- });
- $( "#votosim" ).mouseleave(function(){document.location.reload(true);});
- $( "#votonao" ).mouseleave(function(){document.location.reload(true);});
- $( "#votoabstencao" ).mouseleave(function(){document.location.reload(true);});
+ $("input[type=submit], input[type=button]").prop("disabled", "disabled");
+ });
+
+ //TODO: Este código é necessário?
+ // $( "#votosim" ).mouseleave(function(){document.location.reload(true);});
+ // $( "#votonao" ).mouseleave(function(){document.location.reload(true);});
+ // $( "#votoabstencao" ).mouseleave(function(){document.location.reload(true);});
$(document).on('keyup', (e) => {
var tecla_press = e.keyCode;
@@ -160,34 +160,34 @@
case 86: //86 = valor da tecla V
document.querySelectorAll("#voltar button")[0].click();
break;
-
};
});
- $(document).ready(
- function(){
-
- function checkTime(i) {
- if (i<10) {i = "0" + i}; // add zero in front of numbers < 10
- return i;
- }
- function startTime() {
- var today=new Date();
- var h=today.getHours();
- var m=today.getMinutes();
- var s=today.getSeconds();
- m = checkTime(m);
- s = checkTime(s);
- $("#relogio").text(h+":"+m+":"+s)
- var t = setTimeout(function(){
- startTime()
- }, 500);
- }
- startTime();
-
- setTimeout(function() {
- document.location.reload(true);
- }, 30000)
- });
+ function checkTime(i) {
+ if (i<10)
+ i = "0" + i; // add zero in front of numbers < 10
+ return i;
+ }
+
+ function startTime() {
+ var today=new Date();
+ var h=today.getHours();
+ var m=today.getMinutes();
+ var s=today.getSeconds();
+ m = checkTime(m);
+ s = checkTime(s);
+ $("#relogio").text(h+":"+m+":"+s)
+ var t = setTimeout(function(){
+ startTime()
+ }, 500);
+ }
+
+ $(document).ready(function(){
+ startTime();
+
+ setTimeout(function() {
+ document.location.reload(true);
+ }, 30000)
+ });
diff --git a/sapl/templates/parlamentares/materias.html b/sapl/templates/parlamentares/materias.html
index c5e1448c8..bd30fd7b0 100644
--- a/sapl/templates/parlamentares/materias.html
+++ b/sapl/templates/parlamentares/materias.html
@@ -11,7 +11,7 @@
Matérias ({{nome_parlamentar}})
-Primeiro Autor
+Primeiro Autor
{% for autoria in autoria.0 %}
@@ -20,7 +20,7 @@
{{ materias.1 }}
-
+
{{ materias.2}}
@@ -32,7 +32,7 @@
Total: {{ autoria.1 }}
-Co-Autor
+Co-Autor
{% for coautoria in coautoria.0 %}
@@ -41,7 +41,7 @@
{{ materias.1 }}
-
+
{{ materias.2}}
diff --git a/sapl/templates/protocoloadm/protocolo_list.html b/sapl/templates/protocoloadm/protocolo_list.html
index 27c63edc8..337745da4 100644
--- a/sapl/templates/protocoloadm/protocolo_list.html
+++ b/sapl/templates/protocoloadm/protocolo_list.html
@@ -2,7 +2,6 @@
{% load i18n %}
{% load tz %}
{% load crispy_forms_tags %}
-{% load static %}
{% load webpack_static from webpack_loader %}
{% block detail_content %}
diff --git a/sapl/templates/protocoloadm/protocolo_mostrar.html b/sapl/templates/protocoloadm/protocolo_mostrar.html
index 8c3f669b7..b5e7328e0 100644
--- a/sapl/templates/protocoloadm/protocolo_mostrar.html
+++ b/sapl/templates/protocoloadm/protocolo_mostrar.html
@@ -22,7 +22,7 @@
{% endif %}
Natureza do Processo: {% if protocolo.tipo_processo == 0 %} Administrativo {% elif protocolo.tipo_processo == 1 %} Legislativo {% endif %}
- Número de Páginas: {{ protocolo.numero_paginas }}
+ Número de Páginas: {{ protocolo.numero_paginas|default_if_none:"Não informado" }}
Observação: {{ protocolo.observacao|default:"Não informado" }}
Anulado: {% if protocolo.anulado %} Sim {% else %} Não {% endif %}
diff --git a/sapl/templates/relatorios/header_ata.html b/sapl/templates/relatorios/header_ata.html
index 4cc43efe6..5e7f87356 100644
--- a/sapl/templates/relatorios/header_ata.html
+++ b/sapl/templates/relatorios/header_ata.html
@@ -8,24 +8,28 @@
-
+
-
-
+ {% if info %}
+ {{info}}
+ {% else %}
+
+ {% endif %}
+