Browse Source

Merge branch '3.1.x' into votacao-bloco

pull/2416/head
Edward 7 years ago
committed by GitHub
parent
commit
e29aeeac61
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docker-compose.yml
  2. 2
      requirements/requirements.txt
  3. 26
      sapl/api/forms.py
  4. 136
      sapl/base/forms.py
  5. 20
      sapl/base/migrations/0027_appconfig_relatorios_atos.py
  6. 20
      sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py
  7. 19
      sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py
  8. 8
      sapl/base/models.py
  9. 16
      sapl/base/urls.py
  10. 159
      sapl/base/views.py
  11. 20
      sapl/comissoes/migrations/0019_auto_20181214_1023.py
  12. 1
      sapl/comissoes/models.py
  13. 3
      sapl/comissoes/tests/test_comissoes.py
  14. 3
      sapl/compilacao/templatetags/compilacao_filters.py
  15. 3
      sapl/compilacao/views.py
  16. 55
      sapl/materia/forms.py
  17. 7
      sapl/materia/urls.py
  18. 13
      sapl/norma/forms.py
  19. 25
      sapl/norma/migrations/0017_normaestatisticas.py
  20. 12
      sapl/norma/models.py
  21. 2
      sapl/norma/tests/test_norma.py
  22. 18
      sapl/norma/views.py
  23. 4
      sapl/parlamentares/views.py
  24. 103
      sapl/protocoloadm/forms.py
  25. 20
      sapl/protocoloadm/migrations/0010_auto_20181212_1900.py
  26. 2
      sapl/protocoloadm/models.py
  27. 98
      sapl/protocoloadm/views.py
  28. 2
      sapl/rules/map_rules.py
  29. 13
      sapl/sessao/forms.py
  30. 2
      sapl/sessao/views.py
  31. 13
      sapl/settings.py
  32. 2
      sapl/templates/base.html
  33. 64
      sapl/templates/base/EstatisticasAcessoNormas_filter.html
  34. 2
      sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
  35. 2
      sapl/templates/base/RelatorioMateriasPorAutor_filter.html
  36. 67
      sapl/templates/base/RelatorioNormaMes_filter.html
  37. 57
      sapl/templates/base/RelatorioNormasVigencia_filter.html
  38. 3
      sapl/templates/base/layouts.yaml
  39. 14
      sapl/templates/base/relatorios_list.html
  40. 107
      sapl/templates/materia/impressos/ficha_adm_pdf.html
  41. 6
      sapl/templates/materia/impressos/impressos.html
  42. 16
      sapl/templates/protocoloadm/comprovante.html
  43. 7
      sapl/templates/protocoloadm/protocolo_filter.html
  44. 2
      sapl/templates/sessao/blocos_ata/expedientes.html
  45. 8
      sapl/templates/sessao/blocos_ata/identificacao_basica.html
  46. 4
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  47. 15
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  48. 2
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  49. 37
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  50. 2
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  51. 4
      sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
  52. 2
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  53. 10
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  54. 4
      sapl/templates/sessao/pauta_sessao_detail.html
  55. 2
      setup.py

2
docker-compose.yml

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

2
requirements/requirements.txt

@ -9,7 +9,7 @@ django-compressor==2.0
django-crispy-forms==1.6.1 django-crispy-forms==1.6.1
django-extensions==1.9.8 django-extensions==1.9.8
django-extra-views==0.11.0 django-extra-views==0.11.0
django-filter==0.15.3 django-filter==1.0.0
django-floppyforms==1.6.2 django-floppyforms==1.6.2
django-model-utils==3.1.1 django-model-utils==3.1.1
django-sass-processor==0.5.8 django-sass-processor==0.5.8

26
sapl/api/forms.py

@ -5,9 +5,8 @@ from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import MultiWidget, TextInput from django.forms.widgets import MultiWidget, TextInput
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_filters.filters import DateFilter, MethodFilter, ModelChoiceFilter from django_filters.filters import CharFilter, ModelChoiceFilter, DateFilter
from rest_framework import serializers from rest_framework import serializers
from rest_framework.compat import django_filters
from rest_framework.filters import FilterSet from rest_framework.filters import FilterSet
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
@ -16,9 +15,9 @@ from sapl.utils import generic_relations_for_model
class SaplGenericRelationSearchFilterSet(FilterSet): class SaplGenericRelationSearchFilterSet(FilterSet):
q = MethodFilter() q = CharFilter(method='filter_q')
def filter_q(self, queryset, value): def filter_q(self, queryset, name, value):
query = value.split(' ') query = value.split(' ')
if query: if query:
@ -87,12 +86,12 @@ class SearchForFieldField(MultiValueField):
return None return None
class SearchForFieldFilter(django_filters.filters.MethodFilter): class SearchForFieldFilter(CharFilter):
field_class = SearchForFieldField field_class = SearchForFieldField
class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet): class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet):
q = MethodFilter() q = CharFilter(method='filter_q')
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all()) tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all())
class Meta: class Meta:
@ -101,18 +100,18 @@ class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet):
'tipo', 'tipo',
'nome', ] 'nome', ]
def filter_q(self, queryset, value): def filter_q(self, queryset, name,value):
return SaplGenericRelationSearchFilterSet.filter_q( return SaplGenericRelationSearchFilterSet.filter_q(
self, queryset, value).distinct('nome').order_by('nome') self, queryset, value).distinct('nome').order_by('nome')
class AutorSearchForFieldFilterSet(AutorChoiceFilterSet): class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
q = SearchForFieldFilter() q = SearchForFieldFilter(method='filter_q')
class Meta(AutorChoiceFilterSet.Meta): class Meta(AutorChoiceFilterSet.Meta):
pass pass
def filter_q(self, queryset, value): def filter_q(self, queryset, name, value):
value[0] = value[0].split(',') value[0] = value[0].split(',')
value[1] = value[1].split(',') value[1] = value[1].split(',')
@ -128,7 +127,7 @@ class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
class AutoresPossiveisFilterSet(FilterSet): class AutoresPossiveisFilterSet(FilterSet):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
data_relativa = DateFilter(method='filter_data_relativa') data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter() tipo = CharFilter(method='filter_tipo')
class Meta: class Meta:
model = Autor model = Autor
@ -137,10 +136,11 @@ class AutoresPossiveisFilterSet(FilterSet):
def filter_data_relativa(self, queryset, name, value): def filter_data_relativa(self, queryset, name, value):
return queryset return queryset
def filter_tipo(self, queryset, value): def filter_tipo(self, queryset, name, value):
try: try:
self.logger.debug("Tentando obter TipoAutor correspondente à pk {}.".format(value)) self.logger.debug(
"Tentando obter TipoAutor correspondente à pk {}.".format(value))
tipo = TipoAutor.objects.get(pk=value) tipo = TipoAutor.objects.get(pk=value)
except: except:
self.logger.error("TipoAutor(pk={}) inexistente.".format(value)) self.logger.error("TipoAutor(pk={}) inexistente.".format(value))

136
sapl/base/forms.py

@ -23,6 +23,7 @@ from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
from sapl.audiencia.models import AudienciaPublica,TipoAudienciaPublica from sapl.audiencia.models import AudienciaPublica,TipoAudienciaPublica
from sapl.comissoes.models import Reuniao, Comissao from sapl.comissoes.models import Reuniao, Comissao
from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao) from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.norma.models import (NormaJuridica)
from sapl.parlamentares.models import SessaoLegislativa from sapl.parlamentares.models import SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
@ -654,14 +655,13 @@ class AutorFormForAdmin(AutorForm):
class RelatorioAtasFilterSet(django_filters.FilterSet): class RelatorioAtasFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = SessaoPlenaria model = SessaoPlenaria
fields = ['data_inicio'] fields = ['data_inicio']
@ -688,16 +688,92 @@ class RelatorioAtasFilterSet(django_filters.FilterSet):
) )
class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet): class RelatorioNormasMesFilterSet(django_filters.FilterSet):
ano = django_filters.ChoiceFilter(required=True,
label='Ano da Norma',
choices=RANGE_ANOS)
filter_overrides = {models.DateField: { filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter, 'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: { 'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), 'label': '%s (%s)' % (f.verbose_name, _('Ano')),
'widget': RangeWidgetOverride} 'widget': RangeWidgetOverride}
}} }}
class Meta:
model = NormaJuridica
fields = ['ano']
def __init__(self, *args, **kwargs):
super(RelatorioNormasMesFilterSet, self).__init__(
*args, **kwargs)
self.filters['ano'].label = 'Ano'
self.form.fields['ano'].required = True
row1 = to_row([('ano', 12)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Normas por mês do ano.'),
row1, form_actions(label='Pesquisar'))
)
@property
def qs(self):
parent = super(RelatorioNormasMesFilterSet, self).qs
return parent.distinct().order_by('data')
class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet):
ano = django_filters.ChoiceFilter(required=True,
label='Ano da Norma',
choices=RANGE_ANOS)
vigencia = forms.ChoiceField(
label=_('Vigência'),
choices=[(True, "Vigente"), (False, "Não vigente")],
widget=forms.RadioSelect(),
required=True)
def __init__(self, *args, **kwargs):
super(RelatorioNormasVigenciaFilterSet, self).__init__(
*args, **kwargs)
self.filters['ano'].label = 'Ano'
self.form.fields['ano'].required = True
self.form.fields['vigencia'] = self.vigencia
row1 = to_row([('ano', 12)])
row2 = to_row([('vigencia', 12)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Normas por vigência.'),
row1, row2,
form_actions(label='Pesquisar'))
)
@property
def qs(self):
return qs_override_django_filter(self)
class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet):
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = SessaoPlenaria model = SessaoPlenaria
fields = ['data_inicio'] fields = ['data_inicio']
@ -724,19 +800,18 @@ class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet):
class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
@property @property
def qs(self): def qs(self):
parent = super(RelatorioHistoricoTramitacaoFilterSet, self).qs parent = super(RelatorioHistoricoTramitacaoFilterSet, self).qs
return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero')
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'tramitacao__unidade_tramitacao_local', fields = ['tipo', 'tramitacao__unidade_tramitacao_local',
'tramitacao__status', 'tramitacao__data_tramitacao'] 'tramitacao__status', 'tramitacao__data_tramitacao']
@ -764,19 +839,18 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
@property @property
def qs(self): def qs(self):
parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs
return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero')
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'tramitacao__unidade_tramitacao_local', fields = ['tipo', 'tramitacao__unidade_tramitacao_local',
'tramitacao__status', 'tramitacao__data_fim_prazo'] 'tramitacao__status', 'tramitacao__data_fim_prazo']
@ -936,13 +1010,6 @@ class RelatorioMateriasPorAnoAutorTipoFilterSet(django_filters.FilterSet):
class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet): class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput()) autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
@property @property
@ -952,6 +1019,12 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
.order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero') .order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero')
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao'] fields = ['tipo', 'data_apresentacao']
@ -1061,7 +1134,8 @@ class ConfiguracoesAppForm(ModelForm):
'cronometro_consideracoes', 'cronometro_consideracoes',
'mostrar_brasao_painel', 'mostrar_brasao_painel',
'receber_recibo_proposicao', 'receber_recibo_proposicao',
'assinatura_ata'] 'assinatura_ata',
'estatisticas_acesso_normas']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs) super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)

20
sapl/base/migrations/0027_appconfig_relatorios_atos.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-11 20:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0026_auto_20181126_1727'),
]
operations = [
migrations.AddField(
model_name='appconfig',
name='relatorios_atos',
field=models.CharField(choices=[('S', 'Sim'), ('N', 'Não')], default='N', max_length=1, verbose_name='Relatórios de atos acessados'),
),
]

20
sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-18 17:03
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0027_appconfig_relatorios_atos'),
]
operations = [
migrations.AddField(
model_name='appconfig',
name='estatisticas_acesso_normas',
field=models.CharField(choices=[('S', 'Sim'), ('N', 'Não')], default='N', max_length=1, verbose_name='Estatísticas de acesso a normas'),
),
]

19
sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-18 18:40
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('base', '0028_appconfig_estatisticas_acesso_normas'),
]
operations = [
migrations.RemoveField(
model_name='appconfig',
name='relatorios_atos',
),
]

8
sapl/base/models.py

@ -12,6 +12,9 @@ from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES,
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')), TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')),
('R', _('Restritiva'))) ('R', _('Restritiva')))
RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')),
('N', _('Não')))
SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')), SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')),
('L', _('Sequencial por legislatura')), ('L', _('Sequencial por legislatura')),
('U', _('Sequencial único'))) ('U', _('Sequencial único')))
@ -84,6 +87,11 @@ class AppConfig(models.Model):
verbose_name=_('Visibilidade dos Documentos Administrativos'), verbose_name=_('Visibilidade dos Documentos Administrativos'),
choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O') choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O')
estatisticas_acesso_normas = models.CharField(
max_length=1,
verbose_name=_('Estatísticas de acesso a normas'),
choices=RELATORIO_ATOS_ACESSADOS, default='N')
sequencia_numeracao = models.CharField( sequencia_numeracao = models.CharField(
max_length=1, max_length=1,
verbose_name=_('Sequência de numeração'), verbose_name=_('Sequência de numeração'),

16
sapl/base/urls.py

@ -23,7 +23,11 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
RelatorioMateriasPorAutorView, RelatorioMateriasPorAutorView,
RelatorioMateriasTramitacaoView, RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView, RelatorioPresencaSessaoView,
RelatorioReuniaoView, SaplSearchView) RelatorioReuniaoView, SaplSearchView,
RelatorioNormasPublicadasMesView,
RelatorioNormasVigenciaView,
EstatisticasAcessoNormas,
RelatoriosListView)
app_name = AppConfig.name app_name = AppConfig.name
@ -84,10 +88,16 @@ urlpatterns = [
url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())), url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())),
# TODO mover estas telas para a app 'relatorios' # TODO mover estas telas para a app 'relatorios'
url(r'^sistema/relatorios/$', TemplateView.as_view( url(r'^sistema/relatorios/$',
template_name='base/relatorios_list.html'), name='relatorios_list'), RelatoriosListView.as_view(), name='relatorios_list'),
url(r'^sistema/relatorios/materia-por-autor$', url(r'^sistema/relatorios/materia-por-autor$',
RelatorioMateriasPorAutorView.as_view(), name='materia_por_autor'), RelatorioMateriasPorAutorView.as_view(), name='materia_por_autor'),
url(r'^sistema/relatorios/relatorio-por-mes$',
RelatorioNormasPublicadasMesView.as_view(), name='normas_por_mes'),
url(r'^sistema/relatorios/relatorio-por-vigencia$',
RelatorioNormasVigenciaView.as_view(), name='normas_por_vigencia'),
url(r'^sistema/relatorios/estatisticas-acesso$',
EstatisticasAcessoNormas.as_view(), name='estatisticas_acesso'),
url(r'^sistema/relatorios/materia-por-ano-autor-tipo$', url(r'^sistema/relatorios/materia-por-ano-autor-tipo$',
RelatorioMateriasPorAnoAutorTipoView.as_view(), RelatorioMateriasPorAnoAutorTipoView.as_view(),
name='materia_por_ano_autor_tipo'), name='materia_por_ano_autor_tipo'),

159
sapl/base/views.py

@ -1,3 +1,5 @@
import collections
import datetime
import logging import logging
import os import os
@ -30,6 +32,7 @@ from sapl.comissoes.models import Reuniao, Comissao
from sapl.crud.base import CrudAux, make_pagination from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Autoria, MateriaLegislativa, from sapl.materia.models import (Autoria, MateriaLegislativa,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao) TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca) SessaoPlenariaPresenca)
from sapl.utils import (parlamentares_ativos, from sapl.utils import (parlamentares_ativos,
@ -45,7 +48,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm,
RelatorioMateriasTramitacaoilterSet, RelatorioMateriasTramitacaoilterSet,
RelatorioPresencaSessaoFilterSet, RelatorioPresencaSessaoFilterSet,
RelatorioReuniaoFilterSet, UsuarioCreateForm, RelatorioReuniaoFilterSet, UsuarioCreateForm,
UsuarioEditForm) UsuarioEditForm, RelatorioNormasMesFilterSet,
RelatorioNormasVigenciaFilterSet)
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
@ -276,6 +280,20 @@ class AutorCrud(CrudAux):
return url_reverse return url_reverse
class RelatoriosListView(TemplateView):
template_name='base/relatorios_list.html'
def get_context_data(self, **kwargs):
context = super(TemplateView, self).get_context_data(**kwargs)
estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
if estatisticas_acesso_normas == 'S':
context['estatisticas_acesso_normas'] = True
else:
context['estatisticas_acesso_normas'] = False
return context
class RelatorioAtasView(FilterView): class RelatorioAtasView(FilterView):
model = SessaoPlenaria model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet filterset_class = RelatorioAtasFilterSet
@ -744,6 +762,145 @@ class RelatorioMateriasPorAutorView(FilterView):
return context return context
class RelatorioNormasPublicadasMesView(FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasMesFilterSet
template_name = 'base/RelatorioNormaMes_filter.html'
def get_context_data(self, **kwargs):
context = super(RelatorioNormasPublicadasMesView,
self).get_context_data(**kwargs)
context['title'] = _('Normas')
# Verifica se os campos foram preenchidos
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['ano'] = self.request.GET['ano']
normas_mes = collections.OrderedDict()
meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho',
7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'}
for norma in context['object_list']:
if not meses[norma.data.month] in normas_mes:
normas_mes[meses[norma.data.month]] = []
normas_mes[meses[norma.data.month]].append(norma)
context['normas_mes'] = normas_mes
quant_normas_mes = {}
for key in normas_mes.keys():
quant_normas_mes[key] = len(normas_mes[key])
context['quant_normas_mes'] = quant_normas_mes
return context
class RelatorioNormasVigenciaView(FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasVigenciaFilterSet
template_name = 'base/RelatorioNormasVigencia_filter.html'
def get_filterset_kwargs(self, filterset_class):
super(RelatorioNormasVigenciaView,
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
qs = self.get_queryset().order_by('data').distinct()
if kwargs['data']:
ano = kwargs['data']['ano']
vigencia = kwargs['data']['vigencia']
qs = qs.filter(ano=ano)
if vigencia == 'True':
qs_dt_not_null = qs.filter(data_vigencia__isnull=True)
qs = (qs_dt_not_null | qs.filter(data_vigencia__gte=datetime.datetime.now().date())).distinct()
else:
qs = qs.filter(data_vigencia__lt=datetime.datetime.now().date())
kwargs.update({
'queryset': qs
})
return kwargs
def get_context_data(self, **kwargs):
context = super(RelatorioNormasVigenciaView,
self).get_context_data(**kwargs)
context['title'] = _('Normas por vigência')
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
return context
normas_totais = NormaJuridica.objects.filter(ano=self.request.GET['ano'])
context['quant_total'] = len(normas_totais)
if self.request.GET['vigencia'] == 'True':
context['vigencia'] = 'Vigente'
context['quant_vigente'] = len(context['object_list'])
context['quant_nao_vigente'] = context['quant_total'] - context['quant_vigente']
else:
context['vigencia'] = 'Não vigente'
context['quant_nao_vigente'] = len(context['object_list'])
context['quant_vigente'] = context['quant_total'] - context['quant_nao_vigente']
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['ano'] = self.request.GET['ano']
return context
class EstatisticasAcessoNormas(FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasMesFilterSet
template_name = 'base/EstatisticasAcessoNormas_filter.html'
def get_context_data(self, **kwargs):
context = super(EstatisticasAcessoNormas,
self).get_context_data(**kwargs)
context['title'] = _('Normas')
# Verifica se os campos foram preenchidos
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['ano'] = self.request.GET['ano']
normas_mes = collections.OrderedDict()
meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho',
7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'}
for norma in context['object_list']:
if not meses[norma.data.month] in normas_mes:
normas_mes[meses[norma.data.month]] = []
norma_est = [norma, len(NormaEstatisticas.objects.filter(norma=norma))]
normas_mes[meses[norma.data.month]].append(norma_est)
meses_sem_acesso = []
# Ordena por acesso e limita em 5
for n in normas_mes:
sorted_by_value = sorted(normas_mes[n], key=lambda kv: kv[1], reverse=True)
normas_mes[n] = sorted_by_value[0:5]
if all(v[1]==0 for v in normas_mes[n]):
meses_sem_acesso.append(n)
context['normas_mes'] = normas_mes
context['meses_sem_acesso'] = meses_sem_acesso
return context
class ListarUsuarioView(PermissionRequiredMixin, ListView): class ListarUsuarioView(PermissionRequiredMixin, ListView):
model = get_user_model() model = get_user_model()
template_name = 'auth/user_list.html' template_name = 'auth/user_list.html'

20
sapl/comissoes/migrations/0019_auto_20181214_1023.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-14 12:23
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comissoes', '0018_auto_20180924_1724'),
]
operations = [
migrations.AlterField(
model_name='reuniao',
name='hora_fim',
field=models.TimeField(blank=True, null=True, verbose_name='Horário de Término (hh:mm)'),
),
]

1
sapl/comissoes/models.py

@ -221,6 +221,7 @@ class Reuniao(models.Model):
null=True, null=True,
verbose_name=_('Horário de Início (hh:mm)')) verbose_name=_('Horário de Início (hh:mm)'))
hora_fim = models.TimeField( hora_fim = models.TimeField(
blank=True,
null=True, null=True,
verbose_name=_('Horário de Término (hh:mm)')) verbose_name=_('Horário de Término (hh:mm)'))
local_reuniao = models.CharField( local_reuniao = models.CharField(

3
sapl/comissoes/tests/test_comissoes.py

@ -139,7 +139,6 @@ def test_valida_campos_obrigatorios_reuniao_form():
assert errors['nome'] == [_('Este campo é obrigatório.')] assert errors['nome'] == [_('Este campo é obrigatório.')]
assert errors['data'] == [_('Este campo é obrigatório.')] assert errors['data'] == [_('Este campo é obrigatório.')]
assert errors['hora_inicio'] == [_('Este campo é obrigatório.')] assert errors['hora_inicio'] == [_('Este campo é obrigatório.')]
assert errors['hora_fim'] == [_('Este campo é obrigatório.')]
assert len(errors) == 7 assert len(errors) == 6

3
sapl/compilacao/templatetags/compilacao_filters.py

@ -83,6 +83,9 @@ def nota_automatica(dispositivo, ta_pub_list):
if dispositivo.ta_publicado: if dispositivo.ta_publicado:
d = dispositivo.dispositivo_atualizador.dispositivo_pai d = dispositivo.dispositivo_atualizador.dispositivo_pai
if d.auto_inserido:
d = d.dispositivo_pai
ta_publicado = ta_pub_list[dispositivo.ta_publicado_id] if\ ta_publicado = ta_pub_list[dispositivo.ta_publicado_id] if\
ta_pub_list else dispositivo.ta_publicado ta_pub_list else dispositivo.ta_publicado

3
sapl/compilacao/views.py

@ -1319,6 +1319,9 @@ class TextEditView(CompMixin, TemplateView):
if dispositivo.ta_publicado_id: if dispositivo.ta_publicado_id:
d = dispositivo.dispositivo_atualizador.dispositivo_pai d = dispositivo.dispositivo_atualizador.dispositivo_pai
if d.auto_inserido:
d = d.dispositivo_pai
ta_publicado = lista_ta_publicado[dispositivo.ta_publicado_id] if\ ta_publicado = lista_ta_publicado[dispositivo.ta_publicado_id] if\
lista_ta_publicado else dispositivo.ta_publicado lista_ta_publicado else dispositivo.ta_publicado

55
sapl/materia/forms.py

@ -127,6 +127,9 @@ class MateriaSimplificadaForm(ModelForm):
'numero_protocolo', 'regime_tramitacao', 'numero_protocolo', 'regime_tramitacao',
'em_tramitacao', 'ementa', 'tipo_apresentacao', 'em_tramitacao', 'ementa', 'tipo_apresentacao',
'texto_original'] 'texto_original']
widgets = {
'numero_protocolo': forms.TextInput(attrs={'readonly': True}),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -754,13 +757,6 @@ class AnexadaForm(ModelForm):
class MateriaLegislativaFilterSet(django_filters.FilterSet): class MateriaLegislativaFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial Final')),
'widget': RangeWidgetOverride}
}}
ano = django_filters.ChoiceFilter(required=False, ano = django_filters.ChoiceFilter(required=False,
label='Ano da Matéria', label='Ano da Matéria',
choices=ANO_CHOICES) choices=ANO_CHOICES)
@ -791,6 +787,12 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
o = MateriaPesquisaOrderingFilter() o = MateriaPesquisaOrderingFilter()
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['numero', fields = ['numero',
'numero_protocolo', 'numero_protocolo',
@ -1029,14 +1031,13 @@ class AutoriaMultiCreateForm(Form):
class AcessorioEmLoteFilterSet(django_filters.FilterSet): class AcessorioEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao'] fields = ['tipo', 'data_apresentacao']
@ -1060,14 +1061,13 @@ class AcessorioEmLoteFilterSet(django_filters.FilterSet):
class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet): class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao'] fields = ['tipo', 'data_apresentacao']
@ -1092,14 +1092,13 @@ class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet):
class TramitacaoEmLoteFilterSet(django_filters.FilterSet): class TramitacaoEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao', 'tramitacao__status', fields = ['tipo', 'data_apresentacao', 'tramitacao__status',
'tramitacao__unidade_tramitacao_destino'] 'tramitacao__unidade_tramitacao_destino']

7
sapl/materia/urls.py

@ -26,6 +26,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
proposicao_texto, recuperar_materia, proposicao_texto, recuperar_materia,
ExcluirTramitacaoEmLoteView, RetornarProposicao) ExcluirTramitacaoEmLoteView, RetornarProposicao)
from sapl.norma.views import NormaPesquisaSimplesView from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import (FichaPesquisaAdmView, FichaSelecionaAdmView)
from .apps import AppConfig from .apps import AppConfig
@ -47,6 +48,12 @@ urlpatterns_impressos = [
url(r'^materia/impressos/norma-pesquisa/$', url(r'^materia/impressos/norma-pesquisa/$',
NormaPesquisaSimplesView.as_view(), NormaPesquisaSimplesView.as_view(),
name='impressos_norma_pesquisa'), name='impressos_norma_pesquisa'),
url(r'^materia/impressos/ficha-pesquisa-adm/$',
FichaPesquisaAdmView.as_view(),
name= 'impressos_ficha_pesquisa_adm'),
url(r'^materia/impressos/ficha-seleciona-adm/$',
FichaSelecionaAdmView.as_view(),
name= 'impressos_ficha_seleciona_adm'),
] ]
urlpatterns_materia = [ urlpatterns_materia = [

13
sapl/norma/forms.py

@ -41,13 +41,6 @@ ORDENACAO_CHOICES = [('', '---------'),
class NormaFilterSet(django_filters.FilterSet): class NormaFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
ano = django_filters.ChoiceFilter(required=False, ano = django_filters.ChoiceFilter(required=False,
label='Ano', label='Ano',
choices=ANO_CHOICES) choices=ANO_CHOICES)
@ -63,6 +56,12 @@ class NormaFilterSet(django_filters.FilterSet):
o = NormaPesquisaOrderingFilter() o = NormaPesquisaOrderingFilter()
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = NormaJuridica model = NormaJuridica
fields = ['tipo', 'numero', 'ano', 'data', 'data_vigencia', fields = ['tipo', 'numero', 'ano', 'data', 'data_vigencia',
'data_publicacao', 'ementa', 'assuntos'] 'data_publicacao', 'ementa', 'assuntos']

25
sapl/norma/migrations/0017_normaestatisticas.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-17 18:44
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('norma', '0016_tipovinculonormajuridica_revoga_integramente'),
]
operations = [
migrations.CreateModel(
name='NormaEstatisticas',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('usuario', models.CharField(max_length=50)),
('horario_acesso', models.DateTimeField(auto_now=True, null=True)),
('norma', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='norma.NormaJuridica')),
],
),
]

12
sapl/norma/models.py

@ -191,6 +191,18 @@ class NormaJuridica(models.Model):
update_fields=update_fields) update_fields=update_fields)
class NormaEstatisticas(models.Model):
usuario = models.CharField(max_length=50)
horario_acesso = models.DateTimeField(
blank=True, null=True,
auto_now=True)
norma = models.ForeignKey(NormaJuridica,
on_delete=models.CASCADE)
def __str__(self):
return _('Usuário: %(usuario)s, Norma: %(norma)s') % {
'usuario': self.usuario, 'norma': self.norma}
@reversion.register() @reversion.register()
class AutoriaNorma(models.Model): class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor, autor = models.ForeignKey(Autor,

2
sapl/norma/tests/test_norma.py

@ -7,6 +7,7 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm, from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm,
NormaRelacionadaForm) NormaRelacionadaForm)
from sapl.norma.models import NormaJuridica, TipoNormaJuridica from sapl.norma.models import NormaJuridica, TipoNormaJuridica
from sapl.base.models import AppConfig
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@ -15,6 +16,7 @@ def test_incluir_norma_submit(admin_client):
tipo = mommy.make(TipoNormaJuridica, tipo = mommy.make(TipoNormaJuridica,
sigla='T', sigla='T',
descricao='Teste') descricao='Teste')
config = mommy.make(AppConfig)
# Testa POST # Testa POST
response = admin_client.post(reverse('sapl.norma:normajuridica_create'), response = admin_client.post(reverse('sapl.norma:normajuridica_create'),

18
sapl/norma/views.py

@ -1,6 +1,8 @@
import re
import logging import logging
import re
import sapl
import weasyprint
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -13,8 +15,6 @@ from django.views.generic import TemplateView, UpdateView
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
import weasyprint
import sapl
from sapl.base.models import AppConfig from sapl.base.models import AppConfig
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
@ -24,7 +24,7 @@ from sapl.utils import show_results_filter_set
from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm, from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm) NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm)
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma) TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma, NormaEstatisticas)
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '') # LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
@ -190,7 +190,13 @@ class NormaCrud(Crud):
return reverse('%s:%s' % (namespace, 'norma_pesquisa')) return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
class DetailView(Crud.DetailView): class DetailView(Crud.DetailView):
pass def get(self, request, *args, **kwargs):
estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
if estatisticas_acesso_normas == 'S':
NormaEstatisticas.objects.create(usuario=str(self.request.user),
norma_id=kwargs['pk'])
return super().get(request, *args, **kwargs)
class DeleteView(Crud.DeleteView): class DeleteView(Crud.DeleteView):
@ -225,7 +231,7 @@ class NormaCrud(Crud):
class ListView(Crud.ListView, RedirectView): class ListView(Crud.ListView, RedirectView):
def get_redirect_url(self, *args, **kwargs): def get_redirect_url(self, *args, **kwargs):
namespace = self.model._meta.app_config.name namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'norma_pesquisa')) return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

4
sapl/parlamentares/views.py

@ -288,7 +288,7 @@ def parlamentares_frente_selected(request):
return JsonResponse({'id_list': list(lista_parlamentar_id)}) return JsonResponse({'id_list': list(lista_parlamentar_id)})
class FrenteCrud(CrudAux): class FrenteCrud(Crud):
model = Frente model = Frente
help_topic = 'tipo_situa_militar' help_topic = 'tipo_situa_militar'
public = [RP_DETAIL, RP_LIST] public = [RP_DETAIL, RP_LIST]
@ -574,7 +574,7 @@ class ParlamentarCrud(Crud):
# Caso encontre UMA filiação nessas condições # Caso encontre UMA filiação nessas condições
else: else:
self.logger.info("user=" + username + ". Filiação encontrada com sucesso.") self.logger.debug("user=" + username + ". Filiação encontrada com sucesso.")
row[1] = (filiacao.partido.sigla, None, None) row[1] = (filiacao.partido.sigla, None, None)
return context return context

103
sapl/protocoloadm/forms.py

@ -66,13 +66,6 @@ class AcompanhamentoDocumentoForm(ModelForm):
class ProtocoloFilterSet(django_filters.FilterSet): class ProtocoloFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateTimeField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': 'Data (%s)' % (_('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
ano = django_filters.ChoiceFilter(required=False, ano = django_filters.ChoiceFilter(required=False,
label='Ano', label='Ano',
choices=ANO_CHOICES) choices=ANO_CHOICES)
@ -99,6 +92,12 @@ class ProtocoloFilterSet(django_filters.FilterSet):
o = AnoNumeroOrderingFilter() o = AnoNumeroOrderingFilter()
class Meta: class Meta:
filter_overrides = {models.DateTimeField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': 'Data (%s)' % (_('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = Protocolo model = Protocolo
fields = ['numero', fields = ['numero',
'tipo_documento', 'tipo_documento',
@ -154,13 +153,6 @@ class ProtocoloFilterSet(django_filters.FilterSet):
class DocumentoAdministrativoFilterSet(django_filters.FilterSet): class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': 'Data (%s)' % (_('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
ano = django_filters.ChoiceFilter(required=False, ano = django_filters.ChoiceFilter(required=False,
label='Ano', label='Ano',
choices=ANO_CHOICES) choices=ANO_CHOICES)
@ -176,6 +168,12 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
o = AnoNumeroOrderingFilter() o = AnoNumeroOrderingFilter()
class Meta: class Meta:
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': 'Data (%s)' % (_('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
model = DocumentoAdministrativo model = DocumentoAdministrativo
fields = ['tipo', fields = ['tipo',
'numero', 'numero',
@ -1000,3 +998,80 @@ def filtra_tramitacao_adm_destino_and_status(status, destino):
status=status, status=status,
unidade_tramitacao_destino=destino).distinct().values_list( unidade_tramitacao_destino=destino).distinct().values_list(
'documento_id', flat=True) 'documento_id', flat=True)
class FichaPesquisaAdmForm(forms.Form):
logger = logging.getLogger(__name__)
tipo_documento = forms.ModelChoiceField(
label=TipoDocumentoAdministrativo._meta.verbose_name,
queryset=TipoDocumentoAdministrativo.objects.all(),
empty_label='Selecione')
data_inicial = forms.DateField(
label='Data Inicial',
widget=forms.DateInput(format='%d/%m/%Y')
)
data_final = forms.DateField(
label='Data Final',
widget=forms.DateInput(format='%d/%m/%Y')
)
def __init__(self, *args, **kwargs):
super(FichaPesquisaAdmForm, self).__init__(*args, **kwargs)
row1 = to_row(
[('tipo_documento', 6),
('data_inicial', 3),
('data_final', 3)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
('Formulário de Ficha'),
row1,
form_actions(label='Pesquisar')
)
)
def clean(self):
super(FichaPesquisaAdmForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
if not self.is_valid():
return cleaned_data
if cleaned_data['data_final'] < cleaned_data['data_inicial']:
self.logger.error("A Data Final ({}) não pode ser menor que a Data Inicial ({})."
.format(cleaned_data['data_final'], cleaned_data['data_inicial']))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data
class FichaSelecionaAdmForm(forms.Form):
documento = forms.ModelChoiceField(
widget=forms.RadioSelect,
queryset=DocumentoAdministrativo.objects.all(),
label='')
def __init__(self, *args, **kwargs):
super(FichaSelecionaAdmForm, self).__init__(*args, **kwargs)
row1 = to_row(
[('documento', 12)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
('Selecione a ficha que deseja imprimir'),
row1,
form_actions(label='Gerar Impresso')
)
)

20
sapl/protocoloadm/migrations/0010_auto_20181212_1900.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-12-12 21:00
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0009_merge'),
]
operations = [
migrations.AlterField(
model_name='protocolo',
name='justificativa_anulacao',
field=models.CharField(blank=True, max_length=260, verbose_name='Motivo'),
),
]

2
sapl/protocoloadm/models.py

@ -93,7 +93,7 @@ class Protocolo(models.Model):
user_anulacao = models.CharField(max_length=20, blank=True) user_anulacao = models.CharField(max_length=20, blank=True)
ip_anulacao = models.CharField(max_length=15, blank=True) ip_anulacao = models.CharField(max_length=15, blank=True)
justificativa_anulacao = models.CharField( justificativa_anulacao = models.CharField(
max_length=60, blank=True, verbose_name=_('Motivo')) max_length=260, blank=True, verbose_name=_('Motivo'))
timestamp_anulacao = models.DateTimeField(blank=True, null=True) timestamp_anulacao = models.DateTimeField(blank=True, null=True)
class Meta: class Meta:

98
sapl/protocoloadm/views.py

@ -29,6 +29,7 @@ from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
from sapl.utils import (create_barcode, get_base_url, get_client_ip, from sapl.utils import (create_barcode, get_base_url, get_client_ip,
@ -38,7 +39,7 @@ from sapl.utils import (create_barcode, get_base_url, get_client_ip,
from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm,
DocumentoAcessorioAdministrativoForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet, DocumentoAdministrativoFilterSet,
DocumentoAdministrativoForm, ProtocoloDocumentForm, DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, ProtocoloDocumentForm,
ProtocoloFilterSet, ProtocoloMateriaForm, ProtocoloFilterSet, ProtocoloMateriaForm,
TramitacaoAdmEditForm, TramitacaoAdmForm, TramitacaoAdmEditForm, TramitacaoAdmForm,
DesvincularDocumentoForm, DesvincularMateriaForm, DesvincularDocumentoForm, DesvincularMateriaForm,
@ -1073,3 +1074,98 @@ class DesvincularMateriaView(PermissionRequiredMixin, FormView):
materia.numero_protocolo = None materia.numero_protocolo = None
materia.save() materia.save()
return redirect(self.get_success_url()) return redirect(self.get_success_url())
class ImpressosView(PermissionRequiredMixin, TemplateView):
template_name = 'materia/impressos/impressos.html'
permission_required = ('materia.can_access_impressos', )
class FichaPesquisaAdmView(PermissionRequiredMixin, FormView):
form_class = FichaPesquisaAdmForm
template_name = 'materia/impressos/ficha.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
tipo_documento = form.data['tipo_documento']
data_inicial = form.data['data_inicial']
data_final = form.data['data_final']
url = reverse('sapl.materia:impressos_ficha_seleciona_adm')
url = url + '?tipo=%s&data_inicial=%s&data_final=%s' % (
tipo_documento, data_inicial, data_final)
return HttpResponseRedirect(url)
class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
logger = logging.getLogger(__name__)
form_class = FichaSelecionaAdmForm
template_name = 'materia/impressos/ficha_seleciona.html'
permission_required = ('materia.can_access_impressos', )
def get_context_data(self, **kwargs):
if ('tipo' not in self.request.GET or
'data_inicial' not in self.request.GET or
'data_final' not in self.request.GET):
return HttpResponseRedirect(reverse(
'sapl.materia:impressos_ficha_pesquisa_adm'))
context = super(FichaSelecionaAdmView, self).get_context_data(
**kwargs)
tipo = self.request.GET['tipo']
data_inicial = datetime.strptime(
self.request.GET['data_inicial'], "%d/%m/%Y").date()
data_final = datetime.strptime(
self.request.GET['data_final'], "%d/%m/%Y").date()
documento_list = DocumentoAdministrativo.objects.filter(
tipo=tipo,
data__range=(data_inicial, data_final))
context['quantidade'] = len(documento_list)
documento_list = documento_list[:100]
context['form'].fields['documento'].choices = [
(d.id, str(d)) for d in documento_list]
username = self.request.user.username
if context['quantidade'] > 100:
self.logger.info('user=' + username + '. Sua pesquisa (tipo={}, data_inicial={}, data_final={}) retornou mais do que '
'100 impressos. Por questões de '
'performance, foram retornados '
'apenas os 100 primeiros. Caso '
'queira outros, tente fazer uma '
'pesquisa mais específica'.format(tipo, data_inicial, data_final))
messages.info(self.request, _('Sua pesquisa retornou mais do que '
'100 impressos. Por questões de '
'performance, foram retornados '
'apenas os 100 primeiros. Caso '
'queira outros, tente fazer uma '
'pesquisa mais específica'))
return context
def form_valid(self, form):
context = {}
username = self.request.user.username
try:
self.logger.debug(
"user=" + username + ". Tentando obter objeto DocumentoAdministrativo com id={}".format(form.data['documento']))
documento = DocumentoAdministrativo.objects.get(
id=form.data['documento'])
except ObjectDoesNotExist:
self.logger.error(
"user=" + username + ". Este DocumentoAdministrativo não existe (id={}).".format(form.data['documento']))
mensagem = _('Este Documento Administrativo não existe.')
self.messages.add_message(self.request, messages.INFO, mensagem)
return self.render_to_response(context)
if len(documento.assunto) > 301:
documento.assunto = documento.assunto[0:300] + '[...]'
context['documento'] = documento
return gerar_pdf_impressos(self.request, context,
'materia/impressos/ficha_adm_pdf.html')

2
sapl/rules/map_rules.py

@ -139,6 +139,7 @@ rules_group_norma = {
(norma.NormaRelacionada, __base__), (norma.NormaRelacionada, __base__),
(norma.AnexoNormaJuridica, __base__), (norma.AnexoNormaJuridica, __base__),
(norma.AutoriaNorma, __base__), (norma.AutoriaNorma, __base__),
(norma.NormaEstatisticas, __base__),
# Publicacao está com permissão apenas para norma e não para matéria # Publicacao está com permissão apenas para norma e não para matéria
# e proposições apenas por análise do contexto, não é uma limitação # e proposições apenas por análise do contexto, não é uma limitação
@ -242,6 +243,7 @@ rules_group_geral = {
(norma.AssuntoNorma, __base__), (norma.AssuntoNorma, __base__),
(norma.TipoNormaJuridica, __base__), (norma.TipoNormaJuridica, __base__),
(norma.TipoVinculoNormaJuridica, __base__), (norma.TipoVinculoNormaJuridica, __base__),
(norma.NormaEstatisticas, __base__),
(parlamentares.Legislatura, __base__), (parlamentares.Legislatura, __base__),
(parlamentares.SessaoLegislativa, __base__), (parlamentares.SessaoLegislativa, __base__),

13
sapl/sessao/forms.py

@ -23,9 +23,8 @@ from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato
from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
MateriaPesquisaOrderingFilter, autor_label, MateriaPesquisaOrderingFilter, autor_label,
autor_modal, timezone) autor_modal, timezone)
from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia,
Orador, OradorExpediente, OrdemDia, SessaoPlenaria, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, TipoJustificativa, TipoResultadoVotacao, SessaoPlenariaPresenca, TipoJustificativa, TipoResultadoVotacao,
OcorrenciaSessao, RegistroVotacao, RetiradaPauta, TipoRetiradaPauta) OcorrenciaSessao, RegistroVotacao, RetiradaPauta, TipoRetiradaPauta)
@ -872,7 +871,8 @@ class JustificativaAusenciaForm(ModelForm):
ordens = OrdemDia.objects.filter(q) ordens = OrdemDia.objects.filter(q)
expedientes = ExpedienteMateria.objects.filter(q) expedientes = ExpedienteMateria.objects.filter(q)
legislatura = kwargs['initial']['sessao_plenaria'].legislatura legislatura = kwargs['initial']['sessao_plenaria'].legislatura
mandato = Mandato.objects.filter(legislatura=legislatura) mandato = Mandato.objects.filter(
legislatura=legislatura).order_by('parlamentar__nome_parlamentar')
parlamentares = [m.parlamentar for m in mandato] parlamentares = [m.parlamentar for m in mandato]
@ -881,9 +881,14 @@ class JustificativaAusenciaForm(ModelForm):
presencas = SessaoPlenariaPresenca.objects.filter( presencas = SessaoPlenariaPresenca.objects.filter(
q).order_by('parlamentar__nome_parlamentar') q).order_by('parlamentar__nome_parlamentar')
presencas_ordem = PresencaOrdemDia.objects.filter(
q).order_by('parlamentar__nome_parlamentar')
presentes = [p.parlamentar for p in presencas] presentes = [p.parlamentar for p in presencas]
setFinal = set(parlamentares) - set(presentes) presentes_ordem = [p.parlamentar for p in presencas_ordem]
presentes_ambos = set(presentes).intersection(set(presentes_ordem))
setFinal = set(parlamentares) - presentes_ambos
self.fields['materias_do_expediente'].choices = [ self.fields['materias_do_expediente'].choices = [
(e.id, e.materia) for e in expedientes] (e.id, e.materia) for e in expedientes]

2
sapl/sessao/views.py

@ -2802,6 +2802,7 @@ class PautaSessaoDetailView(DetailView):
mat = {'id': m.materia_id, mat = {'id': m.materia_id,
'ementa': ementa, 'ementa': ementa,
'observacao': m.observacao,
'titulo': titulo, 'titulo': titulo,
'numero': numero, 'numero': numero,
'resultado': resultado, 'resultado': resultado,
@ -2865,6 +2866,7 @@ class PautaSessaoDetailView(DetailView):
mat = {'id': o.materia_id, mat = {'id': o.materia_id,
'ementa': ementa, 'ementa': ementa,
'observacao': o.observacao,
'titulo': titulo, 'titulo': titulo,
'numero': numero, 'numero': numero,
'resultado': resultado, 'resultado': resultado,

13
sapl/settings.py

@ -15,6 +15,7 @@ See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
""" """
import logging import logging
import socket import socket
import sys
from decouple import config from decouple import config
from dj_database_url import parse as db_url from dj_database_url import parse as db_url
@ -335,12 +336,16 @@ LOGGING = {
} }
def excepthook(*args): def uncaught_exceptions(type, value, error_traceback):
logging.getLogger(BASE_DIR.name).error( import traceback
'Uncaught exception:', exc_info=args) logger = logging.getLogger(__name__)
error_msg = ''.join(traceback.format_tb(error_traceback))
logger.error(error_msg)
print(error_msg)
# sys.excepthook = excepthook"""
# captura exceções que não foram tratadas
sys.excepthook = uncaught_exceptions
PASSWORD_HASHERS = [ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default 'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default

2
sapl/templates/base.html

@ -184,7 +184,7 @@
<small> <small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto. Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small> </small>
<span>Release: 3.1.137</span> <span>Release: 3.1.138</span>
</p> </p>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">

64
sapl/templates/base/EstatisticasAcessoNormas_filter.html

@ -0,0 +1,64 @@
{% 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:estatisticas_acesso' %}" 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/>
{% if normas_mes|length == 0 %}
<br>
<h3>{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}</h3>
{% elif normas_mes|length == meses_sem_acesso|length %}
<br>
<h3>{% trans 'Nenhuma norma teve acesso neste ano.'%}</h3>
{% else %}
{% for mes, normas in normas_mes.items %}
<div style="overflow:auto; ">
<table class="table table-bordered table-hover" style="margin-bottom: 0px;">
<thead class="thead-default">
<tr>
<th><h3 style="text-align:center;">Mês: {{ mes }}</h3></th>
</tr>
</thead>
</table>
{% if not mes in meses_sem_acesso %}
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
<th>Acessos</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
{% if n.1 > 0 %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' n.0.pk %}">
{{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}}
</a></td>
<td>{{n.0.ementa}}<br>{{n.0.observacao}}</td>
<td>{{n.1}}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% else %}
<h3 style="text-align:center;">{% trans 'Nenhuma norma deste mês teve acessos.'%}</h3>
<br><br>
{% endif %}
</div>
{% endfor %}
{% endif %}
{% endif %}
{% endblock base_content %}

2
sapl/templates/base/RelatorioHistoricoTramitacao_filter.html

@ -30,7 +30,7 @@
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}"> <td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} {{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td> </a></td>
<td>{{materia.ementa}}</td> <td>{{materia.ementa}}<br>{{materia.observacao}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

2
sapl/templates/base/RelatorioMateriasPorAutor_filter.html

@ -51,7 +51,7 @@
<td><a href="{% url 'sapl.materia:materialegislativa_detail' materia.pk %}"> <td><a href="{% url 'sapl.materia:materialegislativa_detail' materia.pk %}">
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td> </a></td>
<td>{% autoescape off %}{{materia.ementa}}{% endautoescape %}</td> <td>{% autoescape off %}{{materia.ementa}}<br>{{materia.observacao}}{% endautoescape %}</td>
<td> <td>
{% if materia.autoria_set.first != materia.autoria_set.last %} {% if materia.autoria_set.first != materia.autoria_set.last %}
{% for autor in materia.autoria_set.all %} {% for autor in materia.autoria_set.all %}

67
sapl/templates/base/RelatorioNormaMes_filter.html

@ -0,0 +1,67 @@
{% 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:normas_por_mes' %}" 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/>
{% if normas_mes|length == 0 %}
<br>
<h3>{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}</h3>
{% endif %}
{% for mes, normas in normas_mes.items %}
<div style="overflow:auto; ">
<table class="table table-bordered table-hover" style="margin-bottom: 0px;">
<thead class="thead-default">
<tr>
<th><h3 style="text-align:center;">Mês: {{ mes }}</h3></th>
</tr>
</thead>
</table>
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 0px;">
<thead class="thead-default" >
<tr class="active">
{% for k, v in quant_normas_mes.items %}
{% if k == mes %}
{% if v > 1 %}
<th>Quantidade encontrada no mês: {{ v }} normas.</th>
{% else %}
<th>Quantidade encontrada no mês: 1 norma.</th>
{% endif %}
{% endif %}
{% endfor %}
</tr>
</thead>
</table>
<table class="table table-bordered table-hover" style="width:100%; margin-bottom: 30px;">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for n in normas %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' n.pk %}">
{{n.tipo.descricao}} - {{n.tipo.sigla}} {{n.numero}}/{{n.ano}}
</a></td>
<td>{{n.ementa}}<br>{{n.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% endif %}
{% endblock base_content %}

57
sapl/templates/base/RelatorioNormasVigencia_filter.html

@ -0,0 +1,57 @@
{% 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:normas_por_vigencia' %}" 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;Vigência: {{ vigencia }} <br />
{% if object_list %}
<br/>
{% if object_list|length > 1 %}
<h3>Foram encontradas {{object_list|length}} normas.</h3>
{% else %}
<h3>Foi encontrada 1 norma.</h3>
{% endif %}
<br/>
<table class="table table-bordered table-hover" style="width:100%">
<thead class="thead-default" >
<tr class="active">
<th>Norma</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for norma in object_list %}
<tr>
<td><a href="{% url 'sapl.norma:normajuridica_detail' norma.pk %}">
{{norma.tipo.descricao}} - {{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}}
</a></td>
<td>{{norma.ementa}}<br>{{norma.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<table class="table table-bordered table-hover" style="margin-top:30px;">
<thead class="thead-default" >
<tr class="active">
<th> Não foi encontrada nenhuma norma com os parâmetros buscados.</th>
</tr>
</thead>
</table>
{% endif %}
<br>
<h3>Estatísticas das normas do ano:</h3><br>
<h3>{{quant_vigente}} vigente(s) / {{quant_nao_vigente}} não vigente(s)</h3>
{% endif %}
{% endblock base_content %}

3
sapl/templates/base/layouts.yaml

@ -23,6 +23,9 @@ AppConfig:
{% trans 'Textos Articulados' %}: {% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
{% trans 'Estatísticas de acesso' %}:
- estatisticas_acesso_normas
{% trans 'Assinaturas' %}: {% trans 'Assinaturas' %}:
- assinatura_ata - assinatura_ata

14
sapl/templates/base/relatorios_list.html

@ -48,6 +48,20 @@
<td><a href="{% url 'sapl.base:audiencia' %}">Audiência Pública</a></td> <td><a href="{% url 'sapl.base:audiencia' %}">Audiência Pública</a></td>
<td> Audiência Pública com o tipo. </td> <td> Audiência Pública com o tipo. </td>
</tr> </tr>
<tr>
<td><a href="{% url 'sapl.base:normas_por_mes' %}">Normas por mês</a></td>
<td> Normas publicadas por mês. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:normas_por_vigencia' %}">Normas por vigência</a></td>
<td> Normas vigentes ou não vigentes. </td>
</tr>
{% if estatisticas_acesso_normas %}
<tr>
<td><a href="{% url 'sapl.base:estatisticas_acesso' %}">Estatísticas de acesso de Normas.</a></td>
<td> Normas por acesso. </td>
</tr>
{% endif %}
</tbody> </tbody>
</table> </table>
</fieldset> </fieldset>

107
sapl/templates/materia/impressos/ficha_adm_pdf.html

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html><head>
<link rel="stylesheet" href="basicsstyles.css" type="text/css" media="screen">
<link rel="stylesheet" href="printstyles.css" type="text/css" media="print">
<style type="text/css" media="all">
body
{
font-size: small;
font-family: Arial;
line-height: 175%;
background-color: transparent;
margin: 5pt 5pt 0pt 0pt;
}
#voltar
{
position: absolute;
top: 50pt;
left: 500pt;
}
#ementa_texto
{
font-family: Arial;
line-height: 150%;
border-style: none;
text-align: justify;
padding: 0pt 5pt 0pt 0pt;
margin-right:100px;
font-size: small;
height:130px;
}
#titulo
{
font-size: medium;
margin-right:100px;
text-align: center;
}
#despacho_inicial
{
font-family: Arial;
line-height: 150%;
border-style: none;
text-align: justify;
font-size: small;
height:130px;
padding: 0pt 5pt 0pt 0pt;
margin-right:100px;
}
@media print {
#voltar { display: none; }
}
</style>
<body style="margin-left:-50px;margin-right:180px; margin-top: -50px">
<div style="page-break-inside: avoid;">
<justify>
<div id="titulo">
<!-- Informa o processo -->
<strong class="text_pdf">PROCESSO Nº: {{ documento.numero }} / {{documento.ano}}</strong><br>
</div>
<table border=0>
<td height="60pt" valign=top>
<!-- Informa o tipo da matéria -->
<strong class="text_pdf">{{documento.tipo}}:</strong> <span class="text_pdf"> {{documento.numero}} / {{documento.ano}} </span><br>
</td>
</table>
<table border=0>
<td height="60pt" valign=top>
<!-- Informa a Data de Entrada -->
<strong class="text_pdf">Data de entrada:</strong> <span class="text_pdf"> {{documento.data}}</span></br>
</td>
</table>
{% if documento.protocolo%}
<table border=0>
<td height="60pt" valign=top>
<div>
<strong class="text_pdf">Protocolo: </strong><span class="text_pdf">{{materia.protocolo}}</span><br>
</td>
</table>
{% endif %}
<!-- Ementa -->
<table border=0>
<td>
<div id="ementa_texto">
<strong class="text_pdf">Ementa:</strong> <span class="text_pdf">{{documento.assunto}}</span>
</div>
</td>
</table>
</div>
</justify>
</body>

6
sapl/templates/materia/impressos/impressos.html

@ -26,7 +26,11 @@
<ul> <ul>
<li><a href="{% url 'sapl.materia:impressos_norma_pesquisa' %}">Pesquisar</a></li> <li><a href="{% url 'sapl.materia:impressos_norma_pesquisa' %}">Pesquisar</a></li>
</ul> </ul>
</br>
<h2 class="legend">Capa Documento Administrativo</h2>
<ul>
<li><a href="{% url 'sapl.materia:impressos_ficha_pesquisa_adm' %}">Pesquisar</a></li>
</ul>
{#<h2 class="legend">Guia de Remessa</h2>#} {#<h2 class="legend">Guia de Remessa</h2>#}
{# <ul>#} {# <ul>#}

16
sapl/templates/protocoloadm/comprovante.html

@ -14,15 +14,21 @@
th, td { th, td {
padding: 5px; padding: 5px;
} }
@media print {
.hide-print {
display : none;
}
}
@page {
size: auto; /* auto is the initial value */
margin: 0mm; /* this affects the margin in the printer settings */
}
</style> </style>
<div align="center"> <div align="center">
<input type="submit" value="Imprimir" onclick="window.print();" class="btn btn-success"/> <input type="submit" value="Imprimir" onclick="window.print();" class="btn btn-success hide-print"/>
<input type="submit" value="Fechar" onclick="window.close();" class="btn btn-success"/> <input type="submit" value="Fechar" onclick="window.close();" class="btn btn-success hide-print"/>
</div> </div>
<br />
<table> <table>
<tr><td colspan="2" align="center"> <tr><td colspan="2" align="center">
<img height="90" width="90" <img height="90" width="90"

7
sapl/templates/protocoloadm/protocolo_filter.html

@ -62,6 +62,13 @@
<strong>Anulado por: </strong>{{ p.user_anulacao }} - IP {{ p.ip_anulacao }}</br> <strong>Anulado por: </strong>{{ p.user_anulacao }} - IP {{ p.ip_anulacao }}</br>
<strong>Motivo Anulação: </strong>{{ p.justificativa_anulacao }}</br> <strong>Motivo Anulação: </strong>{{ p.justificativa_anulacao }}</br>
{% endif %} {% endif %}
{% if p.tipo_documento and p.documentoadministrativo_set.first %}
<strong>Documentos vinculados: </strong>
<a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' p.documentoadministrativo_set.first.pk %}">
{{ p.documentoadministrativo_set.first.tipo }} - {{ p.documentoadministrativo_set.first.numero }} /
{{ p.documentoadministrativo_set.first.ano }}
</a>
{% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

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

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

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

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

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

@ -2,15 +2,19 @@
<fieldset> <fieldset>
<p align="justify"> <p align="justify">
{% if presenca_sessao %}
<strong>Lista de Presença na Sessão: </strong> <strong>Lista de Presença na Sessão: </strong>
{% for p in presenca_sessao %} {% for p in presenca_sessao %}
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{% endfor %} {% endfor %}
{% endif %}
</p> </p>
<p align="justify"> <p align="justify">
{% if justificativa_ausencia %}
<strong>Justificativas de Ausências na Sessão: </strong> <strong>Justificativas de Ausências na Sessão: </strong>
{% for j in justificativa_ausencia %} {% for j in justificativa_ausencia %}
{{j.parlamentar}} / {{ j.tipo_ausencia }} ; {{j.parlamentar}} / {{ j.tipo_ausencia }} ;
{% endfor %} {% endfor %}
{% endif %}
</p> </p>
</fieldset> </fieldset>

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

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

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

@ -1,5 +1,6 @@
<fieldset> <fieldset>
<p align="justify"> <p align="justify">
{% if materia_expediente %}
<strong>Matérias do Expediente: </strong> <strong>Matérias do Expediente: </strong>
{% for m in materia_expediente %} {% for m in materia_expediente %}
<b>{{m.numero}} - {{m.titulo}}</b> <b>{{m.numero}} - {{m.titulo}}</b>
@ -21,5 +22,6 @@
{{m.ementa|safe}} {{m.ementa|safe}}
{{m.resultado}} {{m.resultado_observacao}}</td> {{m.resultado}} {{m.resultado_observacao}}</td>
{% endfor %} {% endfor %}
{% endif %}
</p> </p>
</fieldset> </fieldset>

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

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

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

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

4
sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html

@ -1,6 +1,8 @@
<fieldset> <fieldset>
<p align="justify"> <p align="justify">
{% if object.ocorrenciasessao.conteudo %}
<strong>Ocorrências da Sessão: </strong> <strong>Ocorrências da Sessão: </strong>
{{object.ocorrenciasessao.conteudo|striptags|safe}} {{object.ocorrenciasessao.conteudo|striptags|safe}}
</p> {% endif %}
</p>
</fieldset> </fieldset>

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

@ -1,5 +1,6 @@
<fieldset> <fieldset>
<p align="justify"> <p align="justify">
{% if oradores %}
<strong>Oradores do Expediente: </strong> <strong>Oradores do Expediente: </strong>
{% for o in oradores %} {% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div> <div><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div>
@ -7,6 +8,7 @@
<div>{{o.observacao}}</div> <div>{{o.observacao}}</div>
</br> </br>
{% endfor %} {% endfor %}
{% endif %}
</p> </p>
</div> </div>
</fieldset> </fieldset>

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

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

4
sapl/templates/sessao/pauta_sessao_detail.html

@ -34,7 +34,7 @@
<br /> <br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>
<td style="width:70%;">{{m.ementa|safe}}</td> <td style="width:70%;">{{m.ementa|safe}}<br>{{m.observacao|safe}}</td>
<td style="width:10%;">{{m.situacao}}</td> <td style="width:10%;">{{m.situacao}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -62,7 +62,7 @@
<br /> <br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>
<td style="width:70%;">{{m.ementa|safe}}</td> <td style="width:70%;">{{m.ementa|safe}}<br>{{m.observacao|safe}}</td>
<td style="width:10%;">{{m.situacao}}</td> <td style="width:10%;">{{m.situacao}}</td>
</tr> </tr>
{% endfor %} {% endfor %}

2
setup.py

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

Loading…
Cancel
Save