Browse Source

Merge branch '3.1.x' into votacao_multipla

pull/2241/head
cristian-longhi 6 years ago
committed by GitHub
parent
commit
e11ee90e58
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Dockerfile
  2. 2
      docker-compose.yml
  3. 2
      requirements/dev-requirements.txt
  4. 23
      requirements/requirements.txt
  5. 97
      sapl/base/forms.py
  6. 8
      sapl/base/tests/teststub_urls.py
  7. 12
      sapl/base/urls.py
  8. 153
      sapl/base/views.py
  9. 11
      sapl/comissoes/forms.py
  10. 2
      sapl/comissoes/models.py
  11. 1
      sapl/comissoes/tests/test_comissoes.py
  12. 2
      sapl/compilacao/compilacao_data_tables.sql
  13. 35
      sapl/compilacao/migrations/0007_auto_20180911_1600.py
  14. 11
      sapl/crud/base.py
  15. 5
      sapl/materia/forms.py
  16. 21
      sapl/materia/migrations/0030_tramitacao_timestamp.py
  17. 3
      sapl/materia/models.py
  18. 23
      sapl/materia/views.py
  19. 8
      sapl/norma/forms.py
  20. 1
      sapl/norma/views.py
  21. 30
      sapl/protocoloadm/forms.py
  22. 20
      sapl/protocoloadm/migrations/0006_documentoadministrativo_restrito.py
  23. 5
      sapl/protocoloadm/models.py
  24. 6
      sapl/protocoloadm/tests/test_protocoloadm.py
  25. 22
      sapl/protocoloadm/views.py
  26. 6
      sapl/relatorios/templates/pdf_pauta_sessao_gerar.py
  27. 2
      sapl/relatorios/urls.py
  28. 29
      sapl/relatorios/views.py
  29. 29
      sapl/sessao/forms.py
  30. 37
      sapl/sessao/migrations/0023_auto_20180914_1315.py
  31. 8
      sapl/sessao/models.py
  32. 16
      sapl/sessao/serializers.py
  33. 4
      sapl/sessao/urls.py
  34. 145
      sapl/sessao/views.py
  35. 22
      sapl/settings.py
  36. 1
      sapl/templates/base/RelatorioAtas_filter.html
  37. 38
      sapl/templates/base/RelatorioAudiencia_filter.html
  38. 5
      sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html
  39. 5
      sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
  40. 37
      sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html
  41. 5
      sapl/templates/base/RelatorioMateriasPorAutor_filter.html
  42. 6
      sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html
  43. 38
      sapl/templates/base/RelatorioReuniao_filter.html
  44. 10
      sapl/templates/base/relatorios_list.html
  45. 3
      sapl/templates/compilacao/text_edit_bloco.html
  46. 34
      sapl/templates/compilacao/text_list_blocoalteracao.html
  47. 10
      sapl/templates/materia/materialegislativa_detail.html
  48. 6
      sapl/templates/norma/normajuridica_filter.html
  49. 4
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  50. 12
      sapl/templates/sessao/blocos_ata/assinaturas.html
  51. 0
      sapl/templates/sessao/blocos_ata/conteudo_multimidia.html
  52. 9
      sapl/templates/sessao/blocos_ata/expedientes.html
  53. 8
      sapl/templates/sessao/blocos_ata/identificacao_basica.html
  54. 10
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  55. 10
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  56. 25
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  57. 23
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  58. 10
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  59. 12
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  60. 9
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  61. 25
      sapl/templates/sessao/expedientemateria_form.html
  62. 2
      sapl/templates/sessao/layouts.yaml
  63. 2
      sapl/templates/sessao/pauta_sessao_detail.html
  64. 2
      sapl/templates/sessao/pauta_sessao_filter.html
  65. 23
      sapl/templates/sessao/resumo_ata.html
  66. 6
      sapl/templates/sessao/subnav.yaml
  67. 2
      sapl/test_urls.py
  68. 6
      sapl/urls.py
  69. 2
      setup.py

2
Dockerfile

@ -40,7 +40,7 @@ COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files
RUN python3 manage.py bower_install -- --allow-root --no-input && \
RUN python3 manage.py bower_install --allow-root && \
python3 manage.py compilescss
RUN python3 manage.py collectstatic --noinput --clear

2
docker-compose.yml

@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
image: interlegis/sapl:3.1.113
image: interlegis/sapl:3.1.119
restart: always
environment:
ADMIN_PASSWORD: interlegis

2
requirements/dev-requirements.txt

@ -2,7 +2,7 @@
autopep8==1.2.4
beautifulsoup4==4.6.0
django-debug-toolbar==1.5
django-debug-toolbar==1.8
ipdb==0.10.1
pdbpp==0.9.2
pip-review==0.4

23
requirements/requirements.txt

@ -1,24 +1,21 @@
dj-database-url==0.4.1
django-haystack==2.6.0
django>=1.9,<1.10
# TODO O django-admin-bootstrapped 2.5.7 não inseriu a mudança que permite
# a compatibilidade com Django 1.9+. A linha abaixo será mudada quando uma
# nova versão do django-admin-bootstrapped for lançada
git+git://github.com/django-admin-bootstrapped/django-admin-bootstrapped.git
django>=1.10,<1.11
git+git://github.com/rubgombar1/django-admin-bootstrapped.git
django-bootstrap3==7.0.1
django-bower==5.1.0
django-bower==5.2.0
django-braces==1.9.0
django-compressor==2.0
django-crispy-forms==1.6.0
django-extensions==1.6.7
django-extra-views==0.8.0
django-crispy-forms==1.6.1
django-extensions==1.9.8
django-extra-views==0.11.0
django-filter==0.15.3
django-floppyforms==1.6.2
django-model-utils==2.5
django-sass-processor==0.5.4
django-model-utils==3.1.1
django-sass-processor==0.5.8
djangorestframework==3.4.0
drfdocs==0.0.11
easy-thumbnails==2.3
git+git://github.com/jasperlittle/django-rest-framework-docs
easy-thumbnails==2.5
django-image-cropping==1.1.0
git+git://github.com/interlegis/trml2pdf.git
libsass==0.11.1

97
sapl/base/forms.py

@ -18,6 +18,8 @@ from django.utils.translation import string_concat
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row)
from sapl.audiencia.models import AudienciaPublica,TipoAudienciaPublica
from sapl.comissoes.models import Reuniao, Comissao
from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.parlamentares.models import SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria
@ -169,15 +171,15 @@ class SessaoLegislativaForm(ModelForm):
if not self.is_valid():
return cleaned_data
flag_edit = True
data_inicio = cleaned_data['data_inicio']
data_fim = cleaned_data['data_fim']
legislatura = cleaned_data['legislatura']
numero = cleaned_data['numero']
data_inicio_leg = legislatura.data_inicio
data_fim_leg = legislatura.data_fim
pk = self.initial['id']
# Querys para verificar se existem Sessões Legislativas no período selecionado no form
pk = self.initial['id'] if self.initial else None
# Queries para verificar se existem Sessões Legislativas no período selecionado no form
# Caso onde a data_inicio e data_fim são iguais a de alguma sessão já criada
primeiro_caso = Q(data_inicio=data_inicio, data_fim=data_fim)
# Caso onde a data_inicio está entre o início e o fim de uma Sessão já existente
@ -192,22 +194,24 @@ class SessaoLegislativaForm(ModelForm):
'inserida, favor verificar as Sessões existentes antes de criar uma '
'nova Sessão Legislativa')
sessoes_legislativas = SessaoLegislativa.objects.filter(legislatura=legislatura).exclude(pk=pk)
#sessoes_legislativas = SessaoLegislativa.objects.filter(legislatura=legislatura).exclude(pk=pk)
if sessoes_legislativas:
numeracoes = [n.numero for n in sessoes_legislativas]
numeracoes = sorted(numeracoes)
ult = max(numeracoes)
# if sessoes_legislativas:
# numeracoes = [n.numero for n in sessoes_legislativas]
# numeracoes = sorted(numeracoes)
# ult = max(numeracoes)
#
# else:
# ult = SessaoLegislativa.objects.latest('data_fim')
# flag_edit = ult.id != pk
# ult = ult.numero
else:
ult = SessaoLegislativa.objects.latest('data_fim')
ult = ult.numero
ult = 0
if numero <= ult:
if numero <= ult and flag_edit:
raise ValidationError('O número da Sessão Legislativa não pode ser menor ou igual '
'que o de Sessões Legislativas passadas')
if data_inicio < data_inicio_leg or \
data_inicio > data_fim_leg:
raise ValidationError('A data de início da Sessão Legislativa deve estar compreendida '
@ -233,11 +237,10 @@ class SessaoLegislativaForm(ModelForm):
if data_inicio_intervalo < data_inicio or \
data_inicio_intervalo < data_inicio_leg or \
data_inicio_intervalo > data_fim or \
data_inicio_intervalo > data_inicio_leg:
data_inicio_intervalo > data_fim_leg:
raise ValidationError('A data de início do intervalo deve estar compreendida entre '
'as datas de início e fim tanto da Legislatura quanto da '
'própria Sessão Legislativa')
if data_fim_intervalo:
if data_fim_intervalo > data_fim or \
data_fim_intervalo > data_fim_leg or \
@ -729,6 +732,67 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
)
class RelatorioReuniaoFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioReuniaoFilterSet, self).qs
return parent.distinct().order_by('-data', 'comissao')
class Meta:
model = Reuniao
fields = ['comissao', 'data',
'nome','tema']
def __init__(self, *args, **kwargs):
super(RelatorioReuniaoFilterSet, self).__init__(
*args, **kwargs)
row1 = to_row([('data', 12)])
row2 = to_row(
[('comissao', 4),
('nome', 4),
('tema', 4)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Reunião de Comissão'),
row1, row2,
form_actions(label='Pesquisar'))
)
class RelatorioAudienciaFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioAudienciaFilterSet, self).qs
return parent.distinct().order_by('-data', 'tipo')
class Meta:
model = AudienciaPublica
fields = ['tipo', 'data',
'nome']
def __init__(self, *args, **kwargs):
super(RelatorioAudienciaFilterSet, self).__init__(
*args, **kwargs)
row1 = to_row([('data', 12)])
row2 = to_row(
[('tipo', 4),
('nome', 4)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Audiência Pública'),
row1, row2,
form_actions(label='Pesquisar'))
)
class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet):
ano = django_filters.ChoiceFilter(required=True,
@ -814,7 +878,8 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioMateriasPorAutorFilterSet, self).qs
return parent.distinct().filter(autoria__primeiro_autor=True).order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero')
return parent.distinct().filter(autoria__primeiro_autor=True)\
.order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero')
class Meta:
model = MateriaLegislativa

8
sapl/base/tests/teststub_urls.py

@ -1,11 +1,9 @@
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.views.generic.base import TemplateView
from sapl.urls import urlpatterns as original_patterns
ptrn = patterns('',
url(r'^zzzz$',
ptrn = [url(r'^zzzz$',
TemplateView.as_view(
template_name='index.html'), name='zzzz'))
template_name='index.html'), name='zzzz')]
urlpatterns = original_patterns + ptrn

12
sapl/base/urls.py

@ -16,12 +16,14 @@ from .forms import LoginForm, NovaSenhaForm, RecuperarSenhaForm
from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
CreateUsuarioView, DeleteUsuarioView, EditUsuarioView,
HelpTopicView, ListarUsuarioView, LogotipoView,
RelatorioAtasView, RelatorioDataFimPrazoTramitacaoView,
RelatorioAtasView, RelatorioAudienciaView,
RelatorioDataFimPrazoTramitacaoView,
RelatorioHistoricoTramitacaoView,
RelatorioMateriasPorAnoAutorTipoView,
RelatorioMateriasPorAutorView,
RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView, SaplSearchView)
RelatorioPresencaSessaoView,
RelatorioReuniaoView, SaplSearchView)
app_name = AppConfig.name
@ -104,6 +106,12 @@ urlpatterns = [
url(r'^sistema/relatorios/atas$',
RelatorioAtasView.as_view(),
name='atas'),
url(r'^sistema/relatorios/reuniao$',
RelatorioReuniaoView.as_view(),
name='reuniao'),
url(r'^sistema/relatorios/audiencia$',
RelatorioAudienciaView.as_view(),
name='audiencia'),
url(r'^email/validate/(?P<uidb64>[0-9A-Za-z_\-]+)/'
'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',

153
sapl/base/views.py

@ -25,8 +25,10 @@ from sapl import settings
from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm
from sapl.base.models import Autor, TipoAutor
from sapl.crud.base import CrudAux, make_pagination
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.comissoes.models import Reuniao, Comissao
from sapl.materia.models import (Autoria, MateriaLegislativa,
TipoMateriaLegislativa)
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca)
from sapl.utils import (parlamentares_ativos, sapl_logger,
@ -34,12 +36,14 @@ from sapl.utils import (parlamentares_ativos, sapl_logger,
from .forms import (AlterarSenhaForm, CasaLegislativaForm,
ConfiguracoesAppForm, RelatorioAtasFilterSet,
RelatorioAudienciaFilterSet,
RelatorioDataFimPrazoTramitacaoFilterSet,
RelatorioHistoricoTramitacaoFilterSet,
RelatorioMateriasPorAnoAutorTipoFilterSet,
RelatorioMateriasPorAutorFilterSet,
RelatorioMateriasTramitacaoilterSet,
RelatorioPresencaSessaoFilterSet, UsuarioCreateForm,
RelatorioPresencaSessaoFilterSet,
RelatorioReuniaoFilterSet, UsuarioCreateForm,
UsuarioEditForm)
from .models import AppConfig, CasaLegislativa
@ -262,6 +266,9 @@ class RelatorioAtasView(FilterView):
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['periodo'] = (
self.request.GET['data_inicio_0'] +
' - ' + self.request.GET['data_inicio_1'])
return context
@ -370,10 +377,29 @@ class RelatorioHistoricoTramitacaoView(FilterView):
context = super(RelatorioHistoricoTramitacaoView,
self).get_context_data(**kwargs)
context['title'] = _('Histórico de Tramitações')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['data_tramitacao'] = (self.request.GET['tramitacao__data_tramitacao_0'] + ' - ' +
self.request.GET['tramitacao__data_tramitacao_1'])
if self.request.GET['tipo']:
tipo = self.request.GET['tipo']
context['tipo'] = (str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacao__status']:
tramitacao_status = self.request.GET['tramitacao__status']
context['tramitacao__status'] = (str(StatusTramitacao.objects.get(id=tramitacao_status)))
else:
context['tramitacao__status'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_local']:
context['tramitacao__unidade_tramitacao_local'] = \
(str(UnidadeTramitacao.objects.get(id=self.request.GET['tramitacao__unidade_tramitacao_local'])))
else:
context['tramitacao__unidade_tramitacao_destino'] = ''
return context
@ -387,14 +413,99 @@ class RelatorioDataFimPrazoTramitacaoView(FilterView):
context = super(RelatorioDataFimPrazoTramitacaoView,
self).get_context_data(**kwargs)
context['title'] = _('Fim de Prazo de Tramitações')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['data_tramitacao'] = (self.request.GET['tramitacao__data_fim_prazo_0'] + ' - ' +
self.request.GET['tramitacao__data_fim_prazo_1'])
if self.request.GET['tipo']:
tipo = self.request.GET['tipo']
context['tipo'] = (str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacao__status']:
tramitacao_status = self.request.GET['tramitacao__status']
context['tramitacao__status'] = (str(StatusTramitacao.objects.get(id=tramitacao_status)))
else:
context['tramitacao__status'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_local']:
context['tramitacao__unidade_tramitacao_local'] = \
(str(UnidadeTramitacao.objects.get(id=self.request.GET['tramitacao__unidade_tramitacao_local'])))
else:
context['tramitacao__unidade_tramitacao_destino'] = ''
return context
class RelatorioReuniaoView(FilterView):
model = Reuniao
filterset_class = RelatorioReuniaoFilterSet
template_name = 'base/RelatorioReuniao_filter.html'
def get_filterset_kwargs(self, filterset_class):
super(RelatorioReuniaoView,
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
return kwargs
def get_context_data(self, **kwargs):
context = super(RelatorioReuniaoView,
self).get_context_data(**kwargs)
context['title'] = _('Reunião de Comissão')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
if self.request.GET['comissao']:
comissao = self.request.GET['comissao']
context['comissao'] = (str(Comissao.objects.get(id=comissao)))
else:
context['comissao'] = ''
return context
class RelatorioAudienciaView(FilterView):
model = AudienciaPublica
filterset_class = RelatorioAudienciaFilterSet
template_name = 'base/RelatorioAudiencia_filter.html'
def get_filterset_kwargs(self, filterset_class):
super(RelatorioAudienciaView,
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
return kwargs
def get_context_data(self, **kwargs):
context = super(RelatorioAudienciaView,
self).get_context_data(**kwargs)
context['title'] = _('Audiência Pública')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
if self.request.GET['tipo']:
tipo = self.request.GET['tipo']
context['tipo'] = (str(TipoAudienciaPublica.objects.get(id=tipo)))
else:
context['tipo'] = ''
return context
class RelatorioMateriasTramitacaoView(FilterView):
model = MateriaLegislativa
filterset_class = RelatorioMateriasTramitacaoilterSet
@ -405,6 +516,8 @@ class RelatorioMateriasTramitacaoView(FilterView):
self).get_context_data(**kwargs)
context['title'] = _('Matérias em Tramitação')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
qs = context['object_list']
@ -424,7 +537,22 @@ class RelatorioMateriasTramitacaoView(FilterView):
if qtde > 0:
qtdes[tipo] = qtde
context['qtdes'] = qtdes
context['ano'] = (self.request.GET['ano'])
if self.request.GET['tipo']:
tipo = self.request.GET['tipo']
context['tipo'] = (str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacao__status']:
tramitacao_status = self.request.GET['tramitacao__status']
context['tramitacao__status'] = (str(StatusTramitacao.objects.get(id=tramitacao_status)))
else:
context['tramitacao__status'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_destino']:
context['tramitacao__unidade_tramitacao_destino'] = (str(UnidadeTramitacao.objects.get(id=
self.request.GET['tramitacao__unidade_tramitacao_destino'])))
else:
context['tramitacao__unidade_tramitacao_destino'] = ''
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
@ -489,7 +617,8 @@ class RelatorioMateriasPorAnoAutorTipoView(FilterView):
self).get_context_data(**kwargs)
context['title'] = _('Matérias por Ano, Autor e Tipo')
if not self.filterset.form.is_valid():
return context
qtdes = {}
for tipo in TipoMateriaLegislativa.objects.all():
qs = kwargs['object_list']
@ -502,6 +631,7 @@ class RelatorioMateriasPorAnoAutorTipoView(FilterView):
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['ano'] = self.request.GET['ano']
if 'ano' in self.request.GET and self.request.GET['ano']:
ano = int(self.request.GET['ano'])
@ -530,6 +660,8 @@ class RelatorioMateriasPorAutorView(FilterView):
self).get_context_data(**kwargs)
context['title'] = _('Matérias por Autor')
if not self.filterset.form.is_valid():
return context
qtdes = {}
for tipo in TipoMateriaLegislativa.objects.all():
@ -543,6 +675,19 @@ class RelatorioMateriasPorAutorView(FilterView):
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
if self.request.GET['tipo']:
tipo = int(self.request.GET['tipo'])
context['tipo'] = (str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['autoria__autor']:
autor = int(self.request.GET['autoria__autor'])
context['autor'] = (str(Autor.objects.get(id=autor)))
else:
context['autor'] = ''
context['periodo'] = (
self.request.GET['data_apresentacao_0'] +
' - ' + self.request.GET['data_apresentacao_1'])
return context

11
sapl/comissoes/forms.py

@ -64,9 +64,14 @@ class PeriodoForm(forms.ModelForm):
if data_fim and data_fim < data_inicio:
raise ValidationError('A Data Final não pode ser menor que '
'a Data Inicial')
legislatura = Legislatura.objects.filter(data_inicio__lte=data_inicio,
data_fim__gte=data_fim)
# Evita NoneType exception se não preenchida a data_fim
if not data_fim:
data_fim = data_inicio
legislatura = Legislatura.objects.filter(data_inicio__lte=data_inicio,
data_fim__gte=data_fim,
)
if not legislatura:
raise ValidationError('O período informado '

2
sapl/comissoes/models.py

@ -111,6 +111,8 @@ class Periodo(models.Model): # PeriodoCompComissao
if self.data_inicio and self.data_fim:
return '%s - %s' % (self.data_inicio.strftime("%d/%m/%Y"),
self.data_fim.strftime("%d/%m/%Y"))
elif self.data_inicio and not self.data_fim:
return '%s - ' % self.data_inicio.strftime("%d/%m/%Y")
else:
return '-'

1
sapl/comissoes/tests/test_comissoes.py

@ -74,6 +74,7 @@ def test_incluir_comissao_submit(admin_client):
'nome': 'Comissão Teste',
'sigla': 'CT',
'data_criacao': '2016-03-22',
'unidade_deliberativa': True,
'salvar': 'salvar'},
follow=True)
assert response.status_code == 200

2
sapl/compilacao/compilacao_data_tables.sql

@ -260,6 +260,8 @@ INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id,
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 1, -1, false);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 2, -1, true);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (3, 125, false, 3, -1, false);
INSERT INTO compilacao_tiponota (id, sigla, nome, modelo) VALUES (1, 'NE', 'Nota Explicativa', '');

35
sapl/compilacao/migrations/0007_auto_20180911_1600.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-03-21 13:54
from __future__ import unicode_literals
from django.db import migrations, models
def insert_relacionamento_entre_dispositivos(apps, schema_editor):
TipoDispositivoRelationship = apps.get_model(
'compilacao', 'TipoDispositivoRelationship')
try:
if TipoDispositivoRelationship.objects.exists():
rel = TipoDispositivoRelationship()
rel.filho_permitido_id = 3
rel.pai_id = 125
rel.filho_de_insercao_automatica = False
rel.perfil_id = 3
rel.quantidade_permitida = -1
rel.permitir_variacao = False
rel.save()
except:
pass
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0006_auto_20180321_1054'),
]
operations = [
migrations.RunPython(insert_relacionamento_entre_dispositivos),
]

11
sapl/crud/base.py

@ -17,8 +17,8 @@ from django.http.response import Http404
from django.shortcuts import redirect
from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView)
from django.views.generic.base import ContextMixin
@ -30,6 +30,7 @@ from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
from sapl.settings import BASE_DIR
from sapl.utils import normalize
logger = logging.getLogger(BASE_DIR.name)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
@ -411,10 +412,13 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
m = self.model
fn = fn.split('__')
for f in fn:
if not f:
continue
f = m._meta.get_field(f)
if hasattr(f, 'related_model') and f.related_model:
m = f.related_model
s.append(force_text(f.verbose_name))
if f:
s.append(force_text(f.verbose_name))
s = ' / '.join(s)
r.append(s)
return r
@ -440,6 +444,9 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
if isinstance(name, tuple):
s = ''
for j, n in enumerate(name):
if not n:
s += '<br>'
continue
m = obj
n = n.split('__')
for f in n[:-1]:

5
sapl/materia/forms.py

@ -676,7 +676,8 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
widget=forms.HiddenInput())
ementa = django_filters.CharFilter(lookup_expr='icontains')
indexacao = django_filters.CharFilter(lookup_expr='icontains')
indexacao = django_filters.CharFilter(lookup_expr='icontains',
label=_('Indexação'))
em_tramitacao = django_filters.ChoiceFilter(required=False,
label='Em tramitação',
@ -1160,7 +1161,7 @@ class TipoProposicaoSelect(Select):
str(data_has_perfil),
force_text(option_label))
def render_options(self, choices, selected_choices):
def render_options(self, selected_choices):
# Normalize to strings.
selected_choices = set(force_text(v) for v in selected_choices)
output = []

21
sapl/materia/migrations/0030_tramitacao_timestamp.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-09-18 12:13
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('materia', '0029_auto_20180901_1628'),
]
operations = [
migrations.AddField(
model_name='tramitacao',
name='timestamp',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

3
sapl/materia/models.py

@ -908,6 +908,9 @@ class Tramitacao(models.Model):
null=True,
verbose_name=_('Status'))
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
# TODO: Remover os campos de data
# TODO: pois timestamp supre a necessidade
timestamp = models.DateTimeField(default=timezone.now)
data_tramitacao = models.DateField(verbose_name=_('Data Tramitação'))
unidade_tramitacao_local = models.ForeignKey(
UnidadeTramitacao,

23
sapl/materia/views.py

@ -744,6 +744,10 @@ class ProposicaoCrud(Crud):
% (p.tipo, numero, p.ano)))
except ValueError:
pass
except AttributeError:
pass
except TypeError:
pass
elif action == 'return':
if not p.data_envio:
@ -1076,6 +1080,7 @@ class TramitacaoCrud(MasterDetailCrud):
ultima_tramitacao = Tramitacao.objects.filter(
materia_id=self.kwargs['pk']).order_by(
'-data_tramitacao',
'-timestamp',
'-id').first()
if ultima_tramitacao:
@ -1146,6 +1151,7 @@ class TramitacaoCrud(MasterDetailCrud):
qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao',
'-timestamp',
'-id')
class DeleteView(MasterDetailCrud.DeleteView):
@ -1158,6 +1164,7 @@ class TramitacaoCrud(MasterDetailCrud):
ultima_tramitacao = materia.tramitacao_set.order_by(
'-data_tramitacao',
'-timestamp',
'-id').first()
if tramitacao.pk != ultima_tramitacao.pk:
@ -1843,7 +1850,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
# issue https://github.com/interlegis/sapl/issues/1123
# TODO: usar Form
urgente = request.POST['urgente'] == 'True'
flag_error = False
for materia_id in marcadas:
t = Tramitacao(
materia_id=materia_id,
@ -1861,9 +1868,17 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
texto=request.POST['texto']
)
t.save()
tramitacao_signal.send(sender=Tramitacao,
post=t,
request=self.request)
try:
tramitacao_signal.send(sender=Tramitacao,
post=t,
request=self.request)
except Exception:
flag_error = True
if flag_error:
msg = _('Tramitação criada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
messages.add_message(self.request, messages.ERROR, msg)
status = StatusTramitacao.objects.get(id=request.POST['status'])

8
sapl/norma/forms.py

@ -52,6 +52,9 @@ class NormaFilterSet(django_filters.FilterSet):
ementa = django_filters.CharFilter(lookup_expr='icontains')
indexacao = django_filters.CharFilter(lookup_expr='icontains',
label=_('Indexação'))
assuntos = django_filters.ModelChoiceFilter(
queryset=AssuntoNorma.objects.all())
@ -67,13 +70,14 @@ class NormaFilterSet(django_filters.FilterSet):
row1 = to_row([('tipo', 4), ('numero', 4), ('ano', 4)])
row2 = to_row([('data', 6), ('data_publicacao', 6)])
row3 = to_row([('ementa', 6), ('assuntos', 6), ('o',6)])
row3 = to_row([('ementa', 6), ('assuntos', 6)])
row4 = to_row([('o',6), ('indexacao', 6)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Norma'),
row1, row2, row3,
row1, row2, row3, row4,
form_actions(label='Pesquisar'))
)

1
sapl/norma/views.py

@ -236,6 +236,7 @@ class NormaCrud(Crud):
initial['tipo_materia'] = norma.materia.tipo
initial['ano_materia'] = norma.materia.ano
initial['numero_materia'] = norma.materia.numero
initial['esfera_federacao'] = norma.esfera_federacao
return initial

30
sapl/protocoloadm/forms.py

@ -304,15 +304,15 @@ class ProtocoloDocumentForm(ModelForm):
numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True)
assunto = forms.CharField(
widget=forms.Textarea, label='Assunto', required=True)
widget=forms.Textarea, label=_('Assunto'), required=True)
interessado = forms.CharField(required=True,
label='Interessado')
label=_('Interessado'))
observacao = forms.CharField(required=False,
widget=forms.Textarea, label='Observação')
widget=forms.Textarea, label=_('Observação'))
numero = forms.IntegerField(required=False, label='Número de Protocolo (opcional)')
numero = forms.IntegerField(required=False, label=_('Número de Protocolo (opcional)'))
class Meta:
model = Protocolo
@ -394,12 +394,12 @@ class ProtocoloMateriaForm(ModelForm):
numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True)
observacao = forms.CharField(required=False,
widget=forms.Textarea, label='Observação')
widget=forms.Textarea, label=_('Observação'))
assunto_ementa = forms.CharField(required=True,
widget=forms.Textarea, label='Ementa')
widget=forms.Textarea, label=_('Ementa'))
numero = forms.IntegerField(required=False, label='Número de Protocolo (opcional)')
numero = forms.IntegerField(required=False, label=_('Número de Protocolo (opcional)'))
class Meta:
model = Protocolo
@ -636,6 +636,11 @@ class DocumentoAdministrativoForm(ModelForm):
label=Protocolo._meta.
get_field('numero').verbose_name)
restrito = forms.ChoiceField(label=_('Acesso Restrito'),
widget=forms.RadioSelect(),
choices=YES_NO_CHOICES,
initial=False)
class Meta:
model = DocumentoAdministrativo
fields = ['tipo',
@ -653,6 +658,7 @@ class DocumentoAdministrativoForm(ModelForm):
'observacao',
'texto_integral',
'protocolo',
'restrito'
]
widgets = {'protocolo': forms.HiddenInput()}
@ -682,7 +688,7 @@ class DocumentoAdministrativoForm(ModelForm):
tipo=tipo_documento,
ano=ano_protocolo).exists()
if doc_exists:
raise ValidationError('Documento já existente')
raise ValidationError(_('Documento já existente'))
# campos opcionais, mas que se informados devem ser válidos
if numero_protocolo and ano_protocolo:
@ -740,7 +746,7 @@ class DocumentoAdministrativoForm(ModelForm):
[('assunto', 12)])
row4 = to_row(
[('interessado', 9), ('tramitacao', 3)])
[('interessado', 8), ('tramitacao', 2), (InlineRadios('restrito'), 2)])
row5 = to_row(
[('texto_integral', 12)])
@ -878,7 +884,7 @@ class DesvincularMateriaForm(forms.Form):
def pega_ultima_tramitacao_adm():
return TramitacaoAdministrativo.objects.values(
'materia_id').annotate(data_encaminhamento=Max(
'documento_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'),
id=Max('id')).values_list('id', flat=True)
@ -895,7 +901,7 @@ def filtra_tramitacao_adm_destino(destino):
return TramitacaoAdministrativo.objects.filter(
id__in=lista,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)
'documento_id', flat=True)
def filtra_tramitacao_adm_destino_and_status(status, destino):
@ -904,4 +910,4 @@ def filtra_tramitacao_adm_destino_and_status(status, destino):
id__in=lista,
status=status,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)
'documento_id', flat=True)

20
sapl/protocoloadm/migrations/0006_documentoadministrativo_restrito.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-09-10 12:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0005_auto_20180824_1241'),
]
operations = [
migrations.AddField(
model_name='documentoadministrativo',
name='restrito',
field=models.BooleanField(default=False, verbose_name='Acesso Restrito'),
),
]

5
sapl/protocoloadm/models.py

@ -93,7 +93,7 @@ class Protocolo(models.Model):
user_anulacao = models.CharField(max_length=20, blank=True)
ip_anulacao = models.CharField(max_length=15, blank=True)
justificativa_anulacao = models.CharField(
max_length=60, blank=True, verbose_name='Motivo')
max_length=60, blank=True, verbose_name=_('Motivo'))
timestamp_anulacao = models.DateTimeField(blank=True, null=True)
class Meta:
@ -148,6 +148,9 @@ class DocumentoAdministrativo(models.Model):
null=True,
upload_to=texto_upload_path,
verbose_name=_('Texto Integral'))
restrito = models.BooleanField(default=False,
verbose_name=_('Acesso Restrito'),
blank=True)
class Meta:
verbose_name = _('Documento Administrativo')

6
sapl/protocoloadm/tests/test_protocoloadm.py

@ -359,8 +359,9 @@ def test_documento_administrativo_invalido():
assert errors['assunto'] == [_('Este campo é obrigatório.')]
assert errors['numero'] == [_('Este campo é obrigatório.')]
assert errors['data'] == [_('Este campo é obrigatório.')]
assert errors['restrito'] == [_('Este campo é obrigatório.')]
assert len(errors) == 5
assert len(errors) == 6
@pytest.mark.django_db(transaction=False)
@ -374,7 +375,8 @@ def test_documento_administrativo_protocolo_inexistente():
'numero': '1',
'data': '2017-10-10',
'numero_protocolo': '11',
'ano_protocolo': '2017'
'ano_protocolo': '2017',
'restrito': False
})
assert not form.is_valid()

22
sapl/protocoloadm/views.py

@ -142,6 +142,13 @@ class DocumentoAdministrativoCrud(Crud):
class DetailView(DocumentoAdministrativoMixin, Crud.DetailView):
def get(self, *args, **kwargs):
pk = self.kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk)
if documento.restrito and self.request.user.is_anonymous():
return redirect('/')
return super(Crud.DetailView, self).get(args, kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.layout_display[0]['rows'][-1][0]['text'] = (
@ -561,18 +568,19 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
kwargs = {'data': self.request.GET or None}
status_tramitacao = self.request.GET.get('tramitacao__status')
status_tramitacao = self.request.GET.get(
'tramitacaoadministrativo__status')
unidade_destino = self.request.GET.get(
'tramitacao__unidade_tramitacao_destino')
'tramitacaoadministrativo__unidade_tramitacao_destino')
qs = self.get_queryset()
qs = qs.prefetch_related("documentoacessorioadministrativo_set",
"tramitacaoadministrativo_set",
"tipo",
"tramitacaoadministrativo_set__status",
"tramitacaoadministrativo_set__unidade_tramitacao_local",
"tramitacaoadministrativo_set__unidade_tramitacao_destino")
"tramitacaoadministrativo_set",
"tipo",
"tramitacaoadministrativo_set__status",
"tramitacaoadministrativo_set__unidade_tramitacao_local",
"tramitacaoadministrativo_set__unidade_tramitacao_destino")
if status_tramitacao and unidade_destino:
lista = filtra_tramitacao_adm_destino_and_status(status_tramitacao,

6
sapl/relatorios/templates/pdf_pauta_sessao_gerar.py

@ -145,10 +145,10 @@ def votacao(lst_votacao):
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td >Ementa</td><td>Situação</td></tr>\n'
for votacao in lst_votacao:
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + votacao['id_materia'] + '</para>\n' + '<para style="P3"><b>Processo: </b>' + votacao[
'des_numeracao'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + votacao['des_turno'] + '</para>\n' + '<para style="P3"><b>Autor: </b>' + votacao['nom_autor'] + '</para></td>\n'
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + str(votacao['id_materia']) + '</para>\n' + '<para style="P3"><b>Processo: </b>' + str(votacao[
'des_numeracao']) + '</para>\n' + '<para style="P3"><b>Turno: </b>' + str(votacao['des_turno']) + '</para>\n' + '<para style="P3"><b>Autor: </b>' + str(votacao['nom_autor']) + '</para></td>\n'
tmp += '<td><para style="P4">' + \
votacao['txt_ementa'] + '</para></td>\n'
str(votacao['txt_ementa']) + '</para></td>\n'
tmp += '<td><para style="P3">' + \
str(votacao['des_situacao']) + '</para></td></tr>\n'

2
sapl/relatorios/urls.py

@ -26,6 +26,6 @@ urlpatterns = [
relatorio_protocolo, name='relatorio_protocolo'),
url(r'^relatorios/(?P<nro>\d+)/(?P<ano>\d+)/etiqueta-protocolo$',
relatorio_etiqueta_protocolo, name='relatorio_etiqueta_protocolo'),
url(r'^relatorios/pauta-sessao$',
url(r'^relatorios/pauta-sessao/(?P<pk>\d+)/$',
relatorio_pauta_sessao, name='relatorio_pauta_sessao'),
]

29
sapl/relatorios/views.py

@ -751,6 +751,9 @@ def get_turno(dic, materia, sessao_data_inicio):
'materia__tipo').order_by(
'-data_tramitacao'
).first()
if tramitacao is None:
tramitacao = materia.tramitacao_set.last()
if tramitacao is not None:
for t in Tramitacao.TURNO_CHOICES:
if t[0] == tramitacao.turno:
@ -986,7 +989,7 @@ def get_etiqueta_protocolos(prots):
return protocolos
def relatorio_pauta_sessao(request):
def relatorio_pauta_sessao(request, pk):
'''
pdf__pauta_sessao_gerar.py
'''
@ -1002,7 +1005,7 @@ def relatorio_pauta_sessao(request):
rodape = get_rodape(casa)
imagem = get_imagem(casa)
sessao = SessaoPlenaria.objects.first()
sessao = SessaoPlenaria.objects.get(id=pk)
lst_expediente_materia, lst_votacao, inf_basicas_dic = get_pauta_sessao(
sessao, casa)
@ -1087,9 +1090,10 @@ def get_pauta_sessao(sessao, casa):
lst_votacao = []
for votacao in OrdemDia.objects.filter(
data_ordem=sessao.data_inicio, sessao_plenaria=sessao):
sessao_plenaria=sessao):
materia = MateriaLegislativa.objects.filter(
id=votacao.materia.id).first()
dic_votacao = {}
dic_votacao["num_ordem"] = votacao.numero_ordem
dic_votacao["id_materia"] = str(
@ -1098,11 +1102,17 @@ def get_pauta_sessao(sessao, casa):
dic_votacao["ordem_observacao"] = votacao.observacao
dic_votacao["des_numeracao"] = ' '
# numeracao = Numeracao.objects.filter(materia=materia)
# if numeracao is not None:
# numeracao = numeracao.first()
# dic_votacao["des_numeracao"] = str(
# numeracao.numero_materia) + '/' + str(numeracao.ano_materia)
numeracao = Numeracao.objects.filter(
materia=votacao.materia).first()
if numeracao is not None:
numeracao = numeracao.first()
dic_votacao["des_numeracao"] = str(
numeracao.numero_materia) + '/' + str(numeracao.ano_materia)
turno, tramitacao = get_turno(dic_votacao, materia, sessao.data_inicio)
dic_votacao["des_turno"] = turno
dic_votacao["des_situacao"] = tramitacao
dic_votacao["nom_autor"] = ' '
autoria = Autoria.objects.filter(
@ -1126,9 +1136,6 @@ def get_pauta_sessao(sessao, casa):
elif autoria is None:
dic_votacao["nom_autor"] = 'Desconhecido'
turno, tramitacao = get_turno(dic_expediente_materia, materia, sessao.data_inicio)
dic_votacao["des_turno"] = turno
dic_votacao["des_situacao"] = tramitacao
lst_votacao.append(dic_votacao)
return (lst_expediente_materia,

29
sapl/sessao/forms.py

@ -1,6 +1,5 @@
from datetime import datetime
import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout
from django import forms
@ -9,6 +8,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row
@ -98,14 +98,12 @@ class SessaoPlenariaForm(ModelForm):
else: # create
raise error
# Condições da verificação
abertura_entre_leg = leg.data_inicio <= abertura <= leg.data_fim
abertura_entre_sl = sl.data_inicio <= abertura <= sl.data_fim
if encerramento is not None:
encerramento_entre_leg = leg.data_inicio < encerramento < leg.data_fim
encerramento_entre_sl = sl.data_inicio < encerramento < sl.data_fim
encerramento_entre_leg = leg.data_inicio <= encerramento <= leg.data_fim
encerramento_entre_sl = sl.data_inicio <= encerramento <= sl.data_fim
# Verificação das datas de abertura e encerramento da Sessão
# Verificações com a data de encerramento preenchidas
if encerramento is not None:
@ -113,7 +111,8 @@ class SessaoPlenariaForm(ModelForm):
if encerramento < abertura:
raise ValidationError("A data de encerramento não pode ser "
"anterior a data de abertura.")
# Verifica se a data de abertura está entre a data de início e fim da legislatura
# Verifica se a data de abertura está entre a data de início e fim
# da legislatura
if abertura_entre_leg and encerramento_entre_leg:
if abertura_entre_sl and encerramento_entre_sl:
pass
@ -165,7 +164,6 @@ class SessaoPlenariaForm(ModelForm):
"datas de início e fim tanto Legislatura "
"quanto da Sessão Legislativa.")
# Verificações com a data de encerramento vazia
else:
if abertura_entre_leg:
@ -424,7 +422,7 @@ class VotacaoForm(forms.Form):
class VotacaoNominalForm(forms.Form):
resultado_votacao = forms.ModelChoiceField(label='Resultado da Votação',
required=True,
required=False,
queryset=TipoResultadoVotacao.objects.all())
@ -455,7 +453,6 @@ class SessaoPlenariaFilterSet(django_filters.FilterSet):
# pré-popula o campo do formulário com o ano corrente
self.form.fields['data_inicio__year'].initial = timezone.now().year
row1 = to_row(
[('data_inicio__year', 3),
('data_inicio__month', 3),
@ -570,13 +567,14 @@ class OradorExpedienteForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OradorExpedienteForm, self).__init__(*args, **kwargs)
legislatura_vigente = SessaoPlenaria.objects.get(pk=kwargs['initial']['id_sessao']).legislatura
legislatura_vigente = SessaoPlenaria.objects.get(
pk=kwargs['initial']['id_sessao']).legislatura
if legislatura_vigente:
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(ativo=True,
mandato__legislatura=legislatura_vigente
).order_by('nome_parlamentar')
).order_by('nome_parlamentar')
def clean(self):
super(OradorExpedienteForm, self).clean()
@ -586,11 +584,11 @@ class OradorExpedienteForm(ModelForm):
return self.cleaned_data
sessao_id = self.initial['id_sessao']
numero = self.initial.get('numero') # Retorna None se inexistente
numero = self.initial.get('numero') # Retorna None se inexistente
ordem = OradorExpediente.objects.filter(
sessao_plenaria_id=sessao_id,
numero_ordem=cleaned_data['numero_ordem']
).exists()
sessao_plenaria_id=sessao_id,
numero_ordem=cleaned_data['numero_ordem']
).exists()
if ordem and (cleaned_data['numero_ordem'] != numero):
raise ValidationError(_(
@ -598,7 +596,6 @@ class OradorExpedienteForm(ModelForm):
return self.cleaned_data
class Meta:
model = OradorExpediente
exclude = ['sessao_plenaria']

37
sapl/sessao/migrations/0023_auto_20180914_1315.py

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-09-14 16:15
from __future__ import unicode_literals
from django.db import migrations, models
def limpa_observacao_igual_ementa(apps, schema_editor):
ExpedienteMateria = apps.get_model('sessao', 'ExpedienteMateria')
OrdemDia = apps.get_model('sessao', 'OrdemDia')
q = models.Q(observacao__iexact=models.F('materia__ementa'))
ExpedienteMateria.objects.filter(q).update(observacao='')
OrdemDia.objects.filter(q).update(observacao='')
class Migration(migrations.Migration):
dependencies = [
('sessao', '0022_auto_20180618_1625'),
]
operations = [
migrations.AlterField(
model_name='expedientemateria',
name='observacao',
field=models.TextField(blank=True, verbose_name='Observação'),
),
migrations.AlterField(
model_name='ordemdia',
name='observacao',
field=models.TextField(blank=True, verbose_name='Observação'),
),
migrations.RunPython(limpa_observacao_igual_ementa),
]

8
sapl/sessao/models.py

@ -1,10 +1,10 @@
from operator import xor
import reversion
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
import reversion
from sapl.base.models import Autor
from sapl.materia.models import MateriaLegislativa
@ -237,7 +237,7 @@ class AbstractOrdemDia(models.Model):
verbose_name=_('Matéria'))
data_ordem = models.DateField(verbose_name=_('Data da Sessão'))
observacao = models.TextField(
blank=True, verbose_name=_('Ementa'))
blank=True, verbose_name=_('Observação'))
numero_ordem = models.PositiveIntegerField(verbose_name=_('Nº Ordem'))
resultado = models.TextField(blank=True, verbose_name=_('Resultado'))
tipo_votacao = models.PositiveIntegerField(
@ -254,6 +254,10 @@ class AbstractOrdemDia(models.Model):
class Meta:
abstract = True
@property
def ementa(self):
return self.materia.ementa
def __str__(self):
return 'Ordem do Dia/Expediente: %s - %s em %s' % (
self.numero_ordem, self.materia, self.sessao_plenaria)

16
sapl/sessao/serializers.py

@ -1,19 +1,3 @@
from rest_framework import serializers
from .models import SessaoPlenaria
class SessaoPlenariaSerializer(serializers.Serializer):
class Meta:
model = SessaoPlenaria
fields = ('tipo',
'sessao_legislativa',
'legislatura',
'data_inicio',
'hora_inicio',
'hora_fim',
'url_video',
'iniciada',
'finalizada'
)

4
sapl/sessao/urls.py

@ -10,7 +10,7 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
PesquisarPautaSessaoView,
PesquisarSessaoPlenariaView,
PresencaOrdemDiaView, PresencaView,
ResumoOrdenacaoView, ResumoView, SessaoCrud,
ResumoOrdenacaoView, ResumoView, ResumoAtaView, SessaoCrud,
TipoExpedienteCrud, TipoResultadoVotacaoCrud,
TipoSessaoCrud, VotacaoEditView,
VotacaoExpedienteEditView,
@ -117,6 +117,8 @@ urlpatterns = [
name='presencaordemdia'),
url(r'^sessao/(?P<pk>\d+)/resumo$',
ResumoView.as_view(), name='resumo'),
url(r'^sessao/(?P<pk>\d+)/resumo_ata$',
ResumoAtaView.as_view(), name='resumo_ata'),
url(r'^sessao/pesquisar-sessao$',
PesquisarSessaoPlenariaView.as_view(), name='pesquisar_sessao'),
url(r'^sessao/(?P<pk>\d+)/matordemdia/votnom/(?P<oid>\d+)/(?P<mid>\d+)$',

145
sapl/sessao/views.py

@ -1,5 +1,5 @@
from re import sub
from operator import itemgetter
from re import sub
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
@ -327,9 +327,9 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'mid': obj.materia_id})
resultado = ('<a href="%s">%s<br/>%s</a>' %
(url,
resultado_descricao,
resultado_observacao))
(url,
resultado_descricao,
resultado_observacao))
else:
if obj.tipo_votacao == 2:
@ -340,7 +340,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=expediente'
'?&materia=expediente'
else:
url = reverse(
'sapl.sessao:votacao_nominal_transparencia',
@ -348,12 +348,12 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=ordem'
'?&materia=ordem'
resultado = ('<a href="%s">%s<br/>%s</a>' %
(url,
resultado_descricao,
resultado_observacao))
(url,
resultado_descricao,
resultado_observacao))
elif obj.tipo_votacao == 1:
if is_expediente:
@ -363,7 +363,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=expediente'
'?&materia=expediente'
else:
url = reverse(
'sapl.sessao:votacao_simbolica_transparencia',
@ -371,7 +371,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=ordem'
'?&materia=ordem'
resultado = ('<a href="%s">%s<br/>%s</a>' %
(url,
@ -379,8 +379,8 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
resultado_observacao))
else:
resultado = ('%s<br/>%s' %
(resultado_descricao,
resultado_observacao))
(resultado_descricao,
resultado_observacao))
context['rows'][i][3] = (resultado, None)
return context
@ -391,7 +391,8 @@ def get_presencas_generic(model, sessao, legislatura):
presentes = [p.parlamentar for p in presencas]
presentes = sorted(presentes, key=lambda x: remover_acentos(x.nome_parlamentar))
presentes = sorted(
presentes, key=lambda x: remover_acentos(x.nome_parlamentar))
mandato = Mandato.objects.filter(
legislatura=legislatura).order_by('parlamentar__nome_parlamentar')
@ -415,7 +416,8 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia', 'materia__ementa',
list_field_names = ['numero_ordem', 'materia',
('materia__ementa', '', 'observacao'),
'resultado']
class CreateView(MasterDetailCrud.CreateView):
@ -446,17 +448,18 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
return initial
class DetailView(MasterDetailCrud.DetailView):
layout_key = 'OrdemDiaDetail'
class ListView(MasterDetailCrud.ListView):
paginate_by = None
ordering = ['numero_ordem', 'materia', 'resultado']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
has_permition = self.request.user.has_module_perms(AppConfig.label)
return customize_link_materia(context, self.kwargs['pk'], has_permition, False)
def recuperar_materia(request):
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia'])
numero = request.GET['numero_materia']
@ -470,7 +473,7 @@ def recuperar_materia(request):
'id': materia.id,
'indexacao': materia.indexacao})
except ObjectDoesNotExist:
response = JsonResponse({'ementa': '', 'id': 0, 'indexacao':''})
response = JsonResponse({'ementa': '', 'id': 0, 'indexacao': ''})
return response
@ -483,7 +486,8 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia',
'materia__ementa', 'resultado']
('materia__ementa', '', 'observacao'),
'resultado']
class ListView(MasterDetailCrud.ListView):
paginate_by = None
@ -551,7 +555,6 @@ class OradorExpedienteCrud(OradorCrud):
return reverse('sapl.sessao:oradorexpediente_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorExpedienteForm
@ -676,10 +679,10 @@ class SessaoCrud(Crud):
return {
'legislatura': legislatura,
'sessao_legislativa': legislatura.sessaolegislativa_set.filter(
legislatura_id=legislatura.id,
data_inicio__year=timezone.now().year
).first()
}
legislatura_id=legislatura.id,
data_inicio__year=timezone.now().year
).first()
}
else:
msg = _('Cadastre alguma legislatura antes de adicionar ' +
'uma sessão plenária!')
@ -785,7 +788,8 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
cronometro_discurso = AppsAppConfig.attr('cronometro_discurso')
cronometro_aparte = AppsAppConfig.attr('cronometro_aparte')
cronometro_ordem = AppsAppConfig.attr('cronometro_ordem')
cronometro_consideracoes = AppsAppConfig.attr('cronometro_consideracoes')
cronometro_consideracoes = AppsAppConfig.attr(
'cronometro_consideracoes')
if (not cronometro_discurso or not cronometro_aparte
or not cronometro_ordem or not cronometro_consideracoes):
@ -1006,15 +1010,18 @@ class MesaView(FormMixin, DetailView):
cargos_vagos = list(set(cargos) - set(cargos_ocupados))
# FIX-ME: tem formas melhores de fazer isso, poupando linhas.
parlamentares = Legislatura.objects.get(id=sessao.legislatura_id).mandato_set.all()
parlamentares = Legislatura.objects.get(
id=sessao.legislatura_id).mandato_set.all()
parlamentares_ocupados = [m.parlamentar for m in mesa]
parlamentares_vagos = list(
set(
[p.parlamentar for p in parlamentares]) - set(
parlamentares_ocupados))
org_parlamentares_vagos = parlamentares_vagos
org_parlamentares_vagos.sort(key=lambda x: remover_acentos(x.nome_parlamentar))
org_parlamentares_vagos = [p for p in org_parlamentares_vagos if p.ativo]
org_parlamentares_vagos.sort(
key=lambda x: remover_acentos(x.nome_parlamentar))
org_parlamentares_vagos = [
p for p in org_parlamentares_vagos if p.ativo]
# Se todos os cargos estiverem ocupados, a listagem de parlamentares
# deve ser renderizada vazia
if not cargos_vagos:
@ -1166,15 +1173,15 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
ordenacao = ResumoOrdenacao.objects.first()
if ordenacao:
initial.update({'primeiro': ordenacao.primeiro,
'segundo': ordenacao.segundo,
'terceiro': ordenacao.terceiro,
'quarto': ordenacao.quarto,
'quinto': ordenacao.quinto,
'sexto': ordenacao.sexto,
'setimo': ordenacao.setimo,
'oitavo': ordenacao.oitavo,
'nono': ordenacao.nono,
'decimo': ordenacao.decimo})
'segundo': ordenacao.segundo,
'terceiro': ordenacao.terceiro,
'quarto': ordenacao.quarto,
'quinto': ordenacao.quinto,
'sexto': ordenacao.sexto,
'setimo': ordenacao.setimo,
'oitavo': ordenacao.oitavo,
'nono': ordenacao.nono,
'decimo': ordenacao.decimo})
return initial
def form_valid(self, form):
@ -1279,7 +1286,6 @@ class ResumoView(DetailView):
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
context.update({'expedientes': expedientes})
# =====================================================================
# Matérias Expediente
materias = ExpedienteMateria.objects.filter(
@ -1335,7 +1341,7 @@ class ResumoView(DetailView):
ora = {'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
'parlamentar': parlamentar,
'observacao' : observacao
'observacao': observacao
}
oradores.append(ora)
@ -1455,7 +1461,8 @@ class ResumoView(DetailView):
'decimo_ordenacao': dict_ord_template['oradores_expli']})
return self.render_to_response(context)
class ResumoAtaView(ResumoView):
template_name = 'sessao/resumo_ata.html'
class ExpedienteView(FormMixin, DetailView):
template_name = 'sessao/expediente.html'
@ -1485,8 +1492,8 @@ class ExpedienteView(FormMixin, DetailView):
for tipo, conteudo in zip(list_tipo, list_conteudo):
ExpedienteSessao.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_id=tipo).delete()
sessao_plenaria_id=self.object.id,
tipo_id=tipo).delete()
expediente = ExpedienteSessao()
expediente.sessao_plenaria_id = self.object.id
@ -1832,13 +1839,11 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
elif self.expediente:
expediente_id = kwargs['oid']
try:
materia_votacao = ExpedienteMateria.objects.get(id=expediente_id)
materia_votacao = ExpedienteMateria.objects.get(
id=expediente_id)
except ObjectDoesNotExist:
raise Http404()
if 'cancelar-votacao' in request.POST:
fechar_votacao_materia(materia_votacao)
return self.form_valid(form)
if form.is_valid():
votos_sim = 0
@ -1846,6 +1851,21 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
abstencoes = 0
nao_votou = 0
if 'cancelar-votacao' in request.POST:
fechar_votacao_materia(materia_votacao)
if self.ordem:
return HttpResponseRedirect(reverse(
'sapl.sessao:ordemdia_list', kwargs={'pk': kwargs['pk']}))
else:
return HttpResponseRedirect(reverse(
'sapl.sessao:expedientemateria_list',
kwargs={'pk': kwargs['pk']}))
else:
if form.cleaned_data['resultado_votacao'] == None:
form.add_error(None, 'Não é possível finalizar a votação sem '
'nenhum resultado da votação')
return self.form_invalid(form)
for votos in request.POST.getlist('voto_parlamentar'):
v = votos.split(':')
voto = v[0]
@ -1930,7 +1950,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
return self.form_invalid(form)
def form_invalid(self, form):
errors_tuple = [(form[e].label, form.errors[e]) for e in form.errors if e in form.fields]
errors_tuple = [(form[e].label, form.errors[e])
for e in form.errors if e in form.fields]
error_message = '''<ul>'''
for e in errors_tuple:
error_message += '''<li><b>%s</b>: %s</li>''' % (e[0], e[1][0])
@ -2007,8 +2028,10 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
elif self.expediente:
expediente_id = kwargs['oid']
expediente = ExpedienteMateria.objects.filter(id=expediente_id).last()
votacao = RegistroVotacao.objects.filter(expediente_id=expediente_id).last()
expediente = ExpedienteMateria.objects.filter(
id=expediente_id).last()
votacao = RegistroVotacao.objects.filter(
expediente_id=expediente_id).last()
if not expediente or not votacao:
raise Http404()
@ -2127,9 +2150,11 @@ class VotacaoNominalTransparenciaDetailView(TemplateView):
materia_votacao = self.request.GET.get('materia', None)
if materia_votacao == 'ordem':
votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last()
votacao = RegistroVotacao.objects.filter(
ordem=self.kwargs['oid']).last()
elif materia_votacao == 'expediente':
votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last()
votacao = RegistroVotacao.objects.filter(
expediente=self.kwargs['oid']).last()
else:
raise Http404()
@ -2210,18 +2235,20 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
materia_votacao = self.request.GET.get('materia', None)
if materia_votacao == 'ordem':
votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last()
votacao = RegistroVotacao.objects.filter(
ordem=self.kwargs['oid']).last()
elif materia_votacao == 'expediente':
votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last()
votacao = RegistroVotacao.objects.filter(
expediente=self.kwargs['oid']).last()
else:
raise Http404()
context['votacao'] = votacao
registro_votacao = {'numero_votos_sim': votacao.numero_votos_sim,
'numero_votos_nao': votacao.numero_votos_nao,
'numero_abstencoes': votacao.numero_abstencoes}
context.update({'registro_votacao':registro_votacao})
'numero_votos_nao': votacao.numero_votos_nao,
'numero_abstencoes': votacao.numero_abstencoes}
context.update({'registro_votacao': registro_votacao})
votacao_existente = {'observacao': sub(
'&nbsp;', ' ', strip_tags(votacao.observacao)),
@ -2237,6 +2264,7 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
for tipo in TipoResultadoVotacao.objects.all():
yield tipo
class VotacaoExpedienteView(SessaoPermissionMixin):
"""
@ -2420,7 +2448,8 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin):
expediente_id = kwargs['oid']
if int(request.POST['anular_votacao']) == 1:
RegistroVotacao.objects.filter(expediente_id=expediente_id).delete()
RegistroVotacao.objects.filter(
expediente_id=expediente_id).delete()
expediente = ExpedienteMateria.objects.get(
sessao_plenaria_id=self.object.id,
@ -2459,10 +2488,10 @@ class PautaSessaoView(TemplateView):
sessao = SessaoPlenaria.objects.order_by("-data_inicio").first()
if not sessao:
return self.render_to_response({})
return self.render_to_response({})
return HttpResponseRedirect(
reverse('sapl.sessao:pauta_sessao_detail', kwargs={'pk': sessao.pk}))
reverse('sapl.sessao:pauta_sessao_detail', kwargs={'pk': sessao.pk}))
class PautaSessaoDetailView(DetailView):

22
sapl/settings.py

@ -116,11 +116,7 @@ HAYSTACK_CONNECTIONS = {
},
}
if DEBUG:
INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
MIDDLEWARE_CLASSES = (
MIDDLEWARE = [
'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
@ -131,8 +127,13 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
# 'speedinfo.middleware.ProfilerMiddleware', # Bug na versão 1.9
)
'speedinfo.middleware.ProfilerMiddleware',
]
if DEBUG:
INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware', ]
INTERNAL_IPS = ('127.0.0.1')
CACHES = {
'default': {
@ -221,7 +222,7 @@ EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='')
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='')
SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='')
MAX_DOC_UPLOAD_SIZE = 50 * 1024 * 1024 # 50MB
MAX_DOC_UPLOAD_SIZE = 60 * 1024 * 1024 # 60MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# Internationalization
@ -231,7 +232,10 @@ LANGUAGES = (
('pt-br', 'Português'),
)
TIME_ZONE = config('TZ', cast=str, default='America/Sao_Paulo')
TIME_ZONE = config('TZ', default='America/Sao_Paulo')
if not TIME_ZONE:
raise ValueError('TIMEZONE env variable undefined in .env settings file! Leaving...')
USE_I18N = True
USE_L10N = True
USE_TZ = True

1
sapl/templates/base/RelatorioAtas_filter.html

@ -12,6 +12,7 @@
<a href="{% url 'sapl.base:atas' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br />
<b>PERÍODO: {{ periodo }}<br /></b><br /><br/>
{% if object_list|length > 0 %}
<table class="table table-striped table-hover">
<thead>

38
sapl/templates/base/RelatorioAudiencia_filter.html

@ -0,0 +1,38 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block base_content %}
{% if not show_results %}
{% crispy filter.form %}
{% endif %}
{% if show_results %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:audiencia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
{% if object_list|length > 0 %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Tipo de Audiência</th>
<th>Nome</th>
</tr>
</thead>
<tbody>
{% for audiencia in object_list %}
<tr>
<td><a href="{% url 'sapl.audiencia:audienciapublica_detail' audiencia.id %}">
{{audiencia.tipo}}
</a></td>
<td>{{audiencia.nome}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<font size="5"><p align="center">Nenhuma Audiência Pública foi encontrada!</p></font>
{% endif %}
{% endif %}
{% endblock base_content %}

5
sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html

@ -12,6 +12,11 @@
<a href="{% url 'sapl.base:data_fim_prazo_tramitacoes' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Período: {{ data_tramitacao }} <br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacao__status }}<br />
&emsp;Local atual: {{ tramitacao__unidade_tramitacao_local }}<br /><br /><br />
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">

5
sapl/templates/base/RelatorioHistoricoTramitacao_filter.html

@ -12,6 +12,11 @@
<a href="{% url 'sapl.base:historico_tramitacoes' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Período: {{ data_tramitacao }} <br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacao__status }}<br />
&emsp;Local atual: {{ tramitacao__unidade_tramitacao_local }}<br /><br /><br />
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">

37
sapl/templates/base/RelatorioMateriasPorAnoAutorTipo_filter.html

@ -12,6 +12,25 @@
<a href="{% url 'sapl.base:materia_por_ano_autor_tipo' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Ano: {{ano}}<br /><br /><br/>
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active"><th colspan="2" class="text-center">QUADRO GERAL</th></tr>
<tr class="active">
<th>Tipo Matéria</th>
<th>Quantidade</th>
</tr>
</thead>
<tbody>
{% for key, value in qtdes.items %}
<tr>
<td>{{key.sigla}} - {{key}}</td>
<td>{{value}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h1>Autorias</h1>
<br/><br/>
{% for r in relatorio %}
@ -59,24 +78,6 @@
<br/>
<br/>
{% endfor %}
<br/><br/>
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active"><th colspan="2" class="text-center">QUADRO GERAL</th></tr>
<tr class="active">
<th>Tipo Matéria</th>
<th>Quantidade</th>
</tr>
</thead>
<tbody>
{% for key, value in qtdes.items %}
<tr>
<td>{{key.sigla}} - {{key}}</td>
<td>{{value}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endblock base_content %}

5
sapl/templates/base/RelatorioMateriasPorAutor_filter.html

@ -12,7 +12,10 @@
<a href="{% url 'sapl.base:materia_por_autor' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Autor: {{ autor }}<br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Data de apresentação: {{periodo}}<br /><br /><br/>
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active"><th colspan="3" class="text-center">QUADRO GERAL</th></tr>

6
sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html

@ -12,7 +12,11 @@
<a href="{% url 'sapl.base:materia_por_tramitacao' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Ano: {{ ano }} <br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacao__status }}<br />
&emsp;Local atual: {{ tramitacao__unidade_tramitacao_destino }}<br /><br /><br />
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active"><th colspan="2" class="text-center">QUADRO GERAL</th></tr>

38
sapl/templates/base/RelatorioReuniao_filter.html

@ -0,0 +1,38 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block base_content %}
{% if not show_results %}
{% crispy filter.form %}
{% endif %}
{% if show_results %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:reuniao' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
{% if object_list|length > 0 %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Comissao</th>
<th>Nome</th>
</tr>
</thead>
<tbody>
{% for reuniao in object_list %}
<tr>
<td><a href="{% url 'sapl.comissoes:reuniao_detail' reuniao.pk %}">
{{reuniao.comissao}}
</a></td>
<td>{{reuniao.nome}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<font size="5"><p align="center">Nenhum reunião foi encontrada!</p></font>
{% endif %}
{% endif %}
{% endblock base_content %}

10
sapl/templates/base/relatorios_list.html

@ -40,7 +40,15 @@
<td><a href="{% url 'sapl.base:data_fim_prazo_tramitacoes' %}">Tramitações por fim de prazo</a></td>
<td> Tramitações com fim de prazo no intervalo informado. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:reuniao' %}">Reunião de Comissão</a></td>
<td> Reunião de Comissão por data. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:audiencia' %}">Audiência Pública</a></td>
<td> Audiência Pública com o tipo. </td>
</tr>
</tbody>
</table>
</fieldset
</fieldset>
{% endblock base_content %}

3
sapl/templates/compilacao/text_edit_bloco.html

@ -36,9 +36,6 @@
{{ node.td.rotulo_sufixo_html|safe }}
{% endif %}
{{ node.td.texto_prefixo_html|safe }}
{% if node.da and node in node.da.alts and not node.dpt.visibilidade %}<small>({% trans 'Dispositivo visível apenas no Texto Articulado Original'%})</small>{% endif %}

34
sapl/templates/compilacao/text_list_blocoalteracao.html

@ -5,15 +5,31 @@
{% if ch.visibilidade %}
<div class="dpt" id="d{{ch.id}}" nivel="{{ch.nivel}}">
<div class="{{ ch.tipo_dispositivo.class_css }}" id="id{{ch.id}}" nivel="{{ch.nivel}}">
{% if ch.auto_inserido %}
{{ ch.dispositivo_pai.tipo_dispositivo.rotulo_prefixo_html|safe }}
<a name="{{ch.dispositivo_pai.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.dispositivo_pai.ta.pk %}#{{ch.dispositivo_pai.pk}}">{{ ch.dispositivo_pai.rotulo }}</a>
{{ ch.dispositivo_pai.tipo_dispositivo.rotulo_sufixo_html|safe }}
{% endif %}
{{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}
<a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">{{ ch.rotulo }}</a>
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }}
{% if ch.auto_inserido %}
{{ ch.dispositivo_pai.tipo_dispositivo.rotulo_prefixo_html|safe }}
{% if ch.dispositivo_pai.rotulo %}
<a name="{{ch.dispositivo_pai.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.dispositivo_pai.ta.pk %}#{{ch.dispositivo_pai.pk}}">{{ ch.dispositivo_pai.rotulo }}</a>
{{ ch.dispositivo_pai.tipo_dispositivo.rotulo_sufixo_html|safe }}
{% else %}
<a name="{{ch.dispositivo_pai.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.dispositivo_pai.ta.pk %}#{{ch.dispositivo_pai.pk}}">
{{ ch.dispositivo_pai.tipo_dispositivo.rotulo_sufixo_html|safe }}
</a>
{% endif %}
{% endif %}
{{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}
{% if ch.rotulo %}
<a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">{{ ch.rotulo }}</a>
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }}
{% elif not ch.rotulo and not ch.auto_inserido %}
<a name="{{ch.pk}}" href="{% url 'sapl.compilacao:ta_text' ch.ta.pk %}#{{ch.pk}}">
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }}
</a>
{% else %}
{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}
{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }}
{% endif %}
</div>
</div>
{%endif%}

10
sapl/templates/materia/materialegislativa_detail.html

@ -8,3 +8,13 @@
</div>
{% endif %}
{% endblock sub_actions %}
{% block detail_content %}
{{ block.super }}
{% if object.normajuridica_set.last %}
<p class="control-label">&emsp; Norma Jurídica Relacionada</p>
<div class="actions btn-group btn-group-sm" role="group">
&emsp;&emsp;<a href="{% url 'sapl.norma:normajuridica_detail' object.normajuridica_set.last.id %}">
{{ object.normajuridica_set.last }}</a>
</div>
{% endif %}
{% endblock detail_content %}

6
sapl/templates/norma/normajuridica_filter.html

@ -51,7 +51,11 @@
{% for n in page_obj %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' n.id %}">{{n.tipo}}</a></td>
<td>{{n.numero}}</td>
{% if n.texto_integral %}
<td><a href="{{n.texto_integral.url}}">{{n.numero}}</a></td>
{% else %}
<td>{{n.numero}}</td>
{% endif %}
<td>{{n.ano}}</td>
<td>{{n.data}}</td>
<td>{{n.ementa|safe}}</td>

4
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -34,10 +34,11 @@
{% endif %}
{% for d in page_obj %}
{% if request.user.is_anonymous and not d.restrito or not request.user.is_anonymous%}
<tr>
<td>
<strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
</br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }}
</br>
@ -65,6 +66,7 @@
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr><td><h3>Nenhum documento encontrado com essas especificações</h3></tr>

12
sapl/templates/sessao/blocos_ata/assinaturas.html

@ -0,0 +1,12 @@
{% load common_tags %}
</p>
</p>
<legend>Assinatura Parlamentares Presentes</legend>
<div class="row">
{% for p in presenca_ordem %}
<div class="col-md-12">{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }}</p>
</div>
{% endfor %}
</div>
</fieldset>

0
sapl/templates/sessao/blocos_ata/conteudo_multimidia.html

9
sapl/templates/sessao/blocos_ata/expedientes.html

@ -0,0 +1,9 @@
<fieldset>
<p align="justify">
<strong>Expedientes: </strong>
{% for e in expedientes %}
<b>{{e.tipo}}</b>:
{{e.conteudo|striptags|safe}}
{% endfor %}
</p>
</fieldset>

8
sapl/templates/sessao/blocos_ata/identificacao_basica.html

@ -0,0 +1,8 @@
<fieldset>
<p align="justify">
<strong>Identificação Básica: </strong>
{% for b in basica %}
{{b}} ;
{% endfor %}
</p>
</fieldset>

10
sapl/templates/sessao/blocos_ata/lista_presenca.html

@ -0,0 +1,10 @@
{% load common_tags %}
<fieldset>
<p align="justify">
<strong>Lista de Presença na Sessão: </strong>
{% for p in presenca_sessao %}
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{% endfor %}
</p>
</fieldset>

10
sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html

@ -0,0 +1,10 @@
{% load common_tags %}
<fieldset>
<p align="justify">
<strong>Lista de Presença na Ordem do Dia: </strong>
{% for p in presenca_ordem %}
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{% endfor %}
</p>
</fieldset>

25
sapl/templates/sessao/blocos_ata/materias_expediente.html

@ -0,0 +1,25 @@
<fieldset>
<p align="justify">
<strong>Matérias do Expediente: </strong>
{% for m in materia_expediente %}
<b>{{m.numero}} - {{m.titulo}}</b>
{% if m.turno %}
Turno: {{m.turno}}
{% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}
{% if m.numero_protocolo %}
Número de Protocolo: {{ m.numero_protocolo }}
{% endif %}
{% if m.numero_processo %}
Processo: {{ m.numero_processo }}
{% endif %}
{{m.ementa|safe}}
{{m.resultado}} {{m.resultado_observacao}}</td>
{% endfor %}
</p>
</fieldset>

23
sapl/templates/sessao/blocos_ata/materias_ordem_dia.html

@ -0,0 +1,23 @@
<fieldset>
<p align="justify">
<strong>Matérias da Ordem do Dia: </strong>
{% for m in materias_ordem %}
<b>{{m.numero}} - {{m.titulo}} </b>
{% if m.turno %}
Turno:{{m.turno}}
{% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}
{% if m.numero_protocolo %}
Número de Protocolo: {{ m.numero_protocolo }}
{% endif %}
{% if m.numero_processo %}
Processo: {{ m.numero_processo }}
{% endif %}
{{m.ementa|safe}}
{{m.resultado}} {{m.resultado_observacao}}
{% endfor %}
</p>
</fieldset>

10
sapl/templates/sessao/blocos_ata/mesa_diretora.html

@ -0,0 +1,10 @@
<fieldset>
<p align="justify">
<strong>Mesa Diretora: </strong>
{% for m in mesa %}
{{m.cargo}}:
{{m.parlamentar.nome_parlamentar}} / {{ m.parlamentar.filiacao_atual }} ;
{% endfor %}
</p>
</fieldset>

12
sapl/templates/sessao/blocos_ata/oradores_expediente.html

@ -0,0 +1,12 @@
<fieldset>
<p align="justify">
<strong>Oradores do Expediente: </strong>
{% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div>
<div>{{o.url_discurso}}</div>
<div>{{o.observacao}}</div>
</br>
{% endfor %}
</p>
</div>
</fieldset>

9
sapl/templates/sessao/blocos_ata/oradores_explicacoes.html

@ -0,0 +1,9 @@
<fieldset>
<p align="justify">
<strong>Oradores das Explicações Pessoais: </strong>
{% for o in oradores_explicacoes %}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }} ;
{{o.url_discurso}}
{% endfor %}
</p>
</fieldset>

25
sapl/templates/sessao/expedientemateria_form.html

@ -6,7 +6,7 @@
{% block extra_js %}
<script language="Javascript">
document.getElementById("id_observacao").readOnly = true;
//document.getElementById("id_observacao").readOnly = true;
function recuperar_materia() {
var tipo_materia = $("#id_tipo_materia").val()
@ -14,18 +14,29 @@
var ano_materia = $("#id_ano_materia").val()
if (tipo_materia && numero_materia && ano_materia) {
$.get("/sessao/recuperar-materia",{tipo_materia: tipo_materia,
numero_materia: numero_materia,
ano_materia: ano_materia},
function(data, status) {
$("#id_observacao").val(data.ementa);
});
$.get("/sessao/recuperar-materia", {
tipo_materia: tipo_materia,
numero_materia: numero_materia,
ano_materia: ano_materia
},
function(data, status) {
if ($(".ementa-materia").length === 0) {
$("#div_id_tipo_materia").closest('.row-fluid').after(
$('<div class="row-fluid"/>').append(
$('<div class="col-xs-12"/>').append(
$('<div class="alert alert-info ementa-materia"/>').html(data.ementa))))
}
else {
$('.ementa-materia').html(data.ementa)
}
});
}
}
var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"]
for (i = 0; i < fields.length; i++) {
$(fields[i]).change(recuperar_materia);
}
recuperar_materia()
</script>
{% endblock %}

2
sapl/templates/sessao/layouts.yaml

@ -56,12 +56,14 @@ OrdemDia:
ExpedienteMateriaDetail:
{% trans 'Matérias do Expediente' %}:
- materia
- ementa
- tipo_votacao
- observacao
OrdemDiaDetail:
{% trans 'Matérias da Ordem do Dia' %}:
- materia
- ementa
- tipo_votacao
- observacao

2
sapl/templates/sessao/pauta_sessao_detail.html

@ -3,7 +3,7 @@
{% load crispy_forms_tags %}
{% block base_content %}
<div align=right><a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' object.id %}"> Impressão PDF</a></li></div>
<div align=right><a href="{% url 'sapl.relatorios:relatorio_pauta_sessao' object.pk %}"> Impressão PDF</a></li></div>
<fieldset>
<legend>Identificação Básica</legend>
<table class="table">

2
sapl/templates/sessao/pauta_sessao_filter.html

@ -24,7 +24,7 @@
{% for s in page_obj %}
<tr>
<td><a href="{% url 'sapl.sessao:pauta_sessao_detail' s.id %}"><strong>{{s}}</strong></br></a></td><td>
<a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' s.id %}"><img height="30" width="30" src="{% static 'img/pdflogo.png' %}"></a>
<a href="{% url 'sapl.relatorios:relatorio_pauta_sessao' s.pk %}"><img height="30" width="30" src="{% static 'img/pdflogo.png' %}"></a>
</td>
</tr>
{% endfor %}

23
sapl/templates/sessao/resumo_ata.html

@ -0,0 +1,23 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}
<h1 class="page-header">
Extrato Eletrônico da {{sessaoplenaria}}
</h1>
{% endblock %}
{% block detail_content %}
{% include 'sessao/blocos_ata/'|add:primeiro_ordenacao %}
{% include 'sessao/blocos_ata/'|add:segundo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:terceiro_ordenacao %}
{% include 'sessao/blocos_ata/'|add:quarto_ordenacao %}
{% include 'sessao/blocos_ata/'|add:quinto_ordenacao %}
{% include 'sessao/blocos_ata/'|add:sexto_ordenacao %}
{% include 'sessao/blocos_ata/'|add:setimo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:oitavo_ordenacao %}
{% include 'sessao/blocos_ata/'|add:nono_ordenacao %}
{% include 'sessao/blocos_ata/'|add:decimo_ordenacao %}
{% include 'sessao/blocos_ata/assinaturas.html' %}
{% endblock detail_content %}

6
sapl/templates/sessao/subnav.yaml

@ -33,4 +33,8 @@
check_permission: painel.list_painel
- title: {% trans 'Resumo' %}
url: resumo
children:
- title: {% trans 'Resumo' %}
url: resumo
- title: {% trans 'Extrato' %}
url: resumo_ata

2
sapl/test_urls.py

@ -56,7 +56,7 @@ def create_perms_post_migrate(sapl_app_config):
ctype = ContentType.objects.get_for_model(klass)
ctypes.add(ctype)
for perm in _get_all_permissions(klass._meta, ctype):
for perm in _get_all_permissions(klass._meta):
searched_perms.append((ctype, perm))
all_perms = set(Permission.objects.filter(

6
sapl/urls.py

@ -70,6 +70,12 @@ urlpatterns = [
# http://stackoverflow.com/questions/35510373/
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
urlpatterns += static(settings.STATIC_URL,
document_root=settings.STATIC_ROOT)

2
setup.py

@ -49,7 +49,7 @@ install_requires = [
]
setup(
name='interlegis-sapl',
version='3.1.113',
version='3.1.119',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

Loading…
Cancel
Save